From gerrit-no-reply at lists.osmocom.org Mon Aug 1 09:50:21 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Mon, 1 Aug 2016 09:50:21 +0000 Subject: [PATCH] openbsc[master]: Added slhc code from kernel.org Message-ID: Review at https://gerrit.osmocom.org/634 Added slhc code from kernel.org Change-Id: Ied69c143678dc4a64cecc671f5c4dfebe19d8519 --- A openbsc/include/openbsc/slhc_vj.h A openbsc/src/gprs/slhc.c 2 files changed, 991 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/34/634/1 diff --git a/openbsc/include/openbsc/slhc_vj.h b/openbsc/include/openbsc/slhc_vj.h new file mode 100644 index 0000000..0a85dc0 --- /dev/null +++ b/openbsc/include/openbsc/slhc_vj.h @@ -0,0 +1,191 @@ +#ifndef _SLHC_H +#define _SLHC_H +/* + * Definitions for tcp compression routines. + * + * $Header: slcompress.h,v 1.10 89/12/31 08:53:02 van Exp $ + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van at helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + * + * + * modified for KA9Q Internet Software Package by + * Katie Stevens (dkstevens at ucdavis.edu) + * University of California, Davis + * Computing Services + * - 01-31-90 initial adaptation + * + * - Feb 1991 Bill_Simpson at um.cc.umich.edu + * variable number of conversation slots + * allow zero or one slots + * separate routines + * status display + */ + +/* + * Compressed packet format: + * + * The first octet contains the packet type (top 3 bits), TCP + * 'push' bit, and flags that indicate which of the 4 TCP sequence + * numbers have changed (bottom 5 bits). The next octet is a + * conversation number that associates a saved IP/TCP header with + * the compressed packet. The next two octets are the TCP checksum + * from the original datagram. The next 0 to 15 octets are + * sequence number changes, one change per bit set in the header + * (there may be no changes and there are two special cases where + * the receiver implicitly knows what changed -- see below). + * + * There are 5 numbers which can change (they are always inserted + * in the following order): TCP urgent pointer, window, + * acknowledgment, sequence number and IP ID. (The urgent pointer + * is different from the others in that its value is sent, not the + * change in value.) Since typical use of SLIP links is biased + * toward small packets (see comments on MTU/MSS below), changes + * use a variable length coding with one octet for numbers in the + * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the + * range 256 - 65535 or 0. (If the change in sequence number or + * ack is more than 65535, an uncompressed packet is sent.) + */ + +/* + * Packet types (must not conflict with IP protocol version) + * + * The top nibble of the first octet is the packet type. There are + * three possible types: IP (not proto TCP or tcp with one of the + * control flags set); uncompressed TCP (a normal IP/TCP packet but + * with the 8-bit protocol field replaced by an 8-bit connection id -- + * this type of packet syncs the sender & receiver); and compressed + * TCP (described above). + * + * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and + * is logically part of the 4-bit "changes" field that follows. Top + * three bits are actual packet type. For backward compatibility + * and in the interest of conserving bits, numbers are chosen so the + * IP protocol version number (4) which normally appears in this nibble + * means "IP packet". + */ + + +#include +#include + +/* SLIP compression masks for len/vers byte */ +#define SL_TYPE_IP 0x40 +#define SL_TYPE_UNCOMPRESSED_TCP 0x70 +#define SL_TYPE_COMPRESSED_TCP 0x80 +#define SL_TYPE_ERROR 0x00 + +/* Bits in first octet of compressed packet */ +#define NEW_C 0x40 /* flag bits for what changed in a packet */ +#define NEW_I 0x20 +#define NEW_S 0x08 +#define NEW_A 0x04 +#define NEW_W 0x02 +#define NEW_U 0x01 + +/* reserved, special-case values of above */ +#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */ +#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */ +#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U) + +#define TCP_PUSH_BIT 0x10 + +/* + * data type and sizes conversion assumptions: + * + * VJ code KA9Q style generic + * u_char byte_t unsigned char 8 bits + * u_short int16 unsigned short 16 bits + * u_int int16 unsigned short 16 bits + * u_long unsigned long unsigned long 32 bits + * int int32 long 32 bits + */ + +typedef __u8 byte_t; +typedef __u32 int32; + +/* + * "state" data for each active tcp conversation on the wire. This is + * basically a copy of the entire IP/TCP header from the last packet + * we saw from the conversation together with a small identifier + * the transmit & receive ends of the line use to locate saved header. + */ +struct cstate { + byte_t cs_this; /* connection id number (xmit) */ + struct cstate *next; /* next in ring (xmit) */ + struct iphdr cs_ip; /* ip/tcp hdr from most recent packet */ + struct tcphdr cs_tcp; + unsigned char cs_ipopt[64]; + unsigned char cs_tcpopt[64]; + int cs_hsize; +}; +#define NULLSLSTATE (struct cstate *)0 + +/* + * all the state data for one serial line (we need one of these per line). + */ +struct slcompress { + struct cstate *tstate; /* transmit connection states (array)*/ + struct cstate *rstate; /* receive connection states (array)*/ + + byte_t tslot_limit; /* highest transmit slot id (0-l)*/ + byte_t rslot_limit; /* highest receive slot id (0-l)*/ + + byte_t xmit_oldest; /* oldest xmit in ring */ + byte_t xmit_current; /* most recent xmit id */ + byte_t recv_current; /* most recent rcvd id */ + + byte_t flags; +#define SLF_TOSS 0x01 /* tossing rcvd frames until id received */ + + int32 sls_o_nontcp; /* outbound non-TCP packets */ + int32 sls_o_tcp; /* outbound TCP packets */ + int32 sls_o_uncompressed; /* outbound uncompressed packets */ + int32 sls_o_compressed; /* outbound compressed packets */ + int32 sls_o_searches; /* searches for connection state */ + int32 sls_o_misses; /* times couldn't find conn. state */ + + int32 sls_i_uncompressed; /* inbound uncompressed packets */ + int32 sls_i_compressed; /* inbound compressed packets */ + int32 sls_i_error; /* inbound error packets */ + int32 sls_i_tossed; /* inbound packets tossed because of error */ + + int32 sls_i_runt; + int32 sls_i_badcheck; +}; +#define NULLSLCOMPR (struct slcompress *)0 + +#define __ARGS(x) x + +/* In slhc.c: */ +struct slcompress *slhc_init __ARGS((int rslots, int tslots)); +void slhc_free __ARGS((struct slcompress *comp)); + +int slhc_compress __ARGS((struct slcompress *comp, unsigned char *icp, + int isize, unsigned char *ocp, unsigned char **cpp, + int compress_cid)); +int slhc_uncompress __ARGS((struct slcompress *comp, unsigned char *icp, + int isize)); +int slhc_remember __ARGS((struct slcompress *comp, unsigned char *icp, + int isize)); +int slhc_toss __ARGS((struct slcompress *comp)); + +void slhc_i_status __ARGS((struct slcompress *comp)); +void slhc_o_status __ARGS((struct slcompress *comp)); + +#endif /* _SLHC_H */ diff --git a/openbsc/src/gprs/slhc.c b/openbsc/src/gprs/slhc.c new file mode 100644 index 0000000..b1a855c --- /dev/null +++ b/openbsc/src/gprs/slhc.c @@ -0,0 +1,800 @@ +/* + * Routines to compress and uncompress tcp packets (for transmission + * over low speed serial lines). + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van at helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + * + * + * modified for KA9Q Internet Software Package by + * Katie Stevens (dkstevens at ucdavis.edu) + * University of California, Davis + * Computing Services + * - 01-31-90 initial adaptation (from 1.19) + * PPP.05 02-15-90 [ks] + * PPP.08 05-02-90 [ks] use PPP protocol field to signal compression + * PPP.15 09-90 [ks] improve mbuf handling + * PPP.16 11-02 [karn] substantially rewritten to use NOS facilities + * + * - Feb 1991 Bill_Simpson at um.cc.umich.edu + * variable number of conversation slots + * allow zero or one slots + * separate routines + * status display + * - Jul 1994 Dmitry Gorodchanin + * Fixes for memory leaks. + * - Oct 1994 Dmitry Gorodchanin + * Modularization. + * - Jan 1995 Bjorn Ekwall + * Use ip_fast_csum from ip.h + * - July 1995 Christos A. Polyzols + * Spotted bug in tcp option checking + * + * + * This module is a difficult issue. It's clearly inet code but it's also clearly + * driver code belonging close to PPP and SLIP + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_INET +/* Entire module is for IP only */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned char *encode(unsigned char *cp, unsigned short n); +static long decode(unsigned char **cpp); +static unsigned char * put16(unsigned char *cp, unsigned short x); +static unsigned short pull16(unsigned char **cpp); + +/* Initialize compression data structure + * slots must be in range 0 to 255 (zero meaning no compression) + */ +struct slcompress * +slhc_init(int rslots, int tslots) +{ + register short i; + register struct cstate *ts; + struct slcompress *comp; + + MOD_INC_USE_COUNT; + comp = (struct slcompress *)kmalloc(sizeof(struct slcompress), + GFP_KERNEL); + if (! comp) + goto out_fail; + memset(comp, 0, sizeof(struct slcompress)); + + if ( rslots > 0 && rslots < 256 ) { + size_t rsize = rslots * sizeof(struct cstate); + comp->rstate = (struct cstate *) kmalloc(rsize, GFP_KERNEL); + if (! comp->rstate) + goto out_free; + memset(comp->rstate, 0, rsize); + comp->rslot_limit = rslots - 1; + } + + if ( tslots > 0 && tslots < 256 ) { + size_t tsize = tslots * sizeof(struct cstate); + comp->tstate = (struct cstate *) kmalloc(tsize, GFP_KERNEL); + if (! comp->tstate) + goto out_free2; + memset(comp->tstate, 0, tsize); + comp->tslot_limit = tslots - 1; + } + + comp->xmit_oldest = 0; + comp->xmit_current = 255; + comp->recv_current = 255; + /* + * don't accept any packets with implicit index until we get + * one with an explicit index. Otherwise the uncompress code + * will try to use connection 255, which is almost certainly + * out of range + */ + comp->flags |= SLF_TOSS; + + if ( tslots > 0 ) { + ts = comp->tstate; + for(i = comp->tslot_limit; i > 0; --i){ + ts[i].cs_this = i; + ts[i].next = &(ts[i - 1]); + } + ts[0].next = &(ts[comp->tslot_limit]); + ts[0].cs_this = 0; + } + return comp; + +out_free2: + kfree((unsigned char *)comp->rstate); +out_free: + kfree((unsigned char *)comp); +out_fail: + MOD_DEC_USE_COUNT; + return NULL; +} + + +/* Free a compression data structure */ +void +slhc_free(struct slcompress *comp) +{ + if ( comp == NULLSLCOMPR ) + return; + + if ( comp->tstate != NULLSLSTATE ) + kfree( comp->tstate ); + + if ( comp->rstate != NULLSLSTATE ) + kfree( comp->rstate ); + + kfree( comp ); + MOD_DEC_USE_COUNT; +} + + +/* Put a short in host order into a char array in network order */ +static inline unsigned char * +put16(unsigned char *cp, unsigned short x) +{ + *cp++ = x >> 8; + *cp++ = x; + + return cp; +} + + +/* Encode a number */ +unsigned char * +encode(unsigned char *cp, unsigned short n) +{ + if(n >= 256 || n == 0){ + *cp++ = 0; + cp = put16(cp,n); + } else { + *cp++ = n; + } + return cp; +} + +/* Pull a 16-bit integer in host order from buffer in network byte order */ +static unsigned short +pull16(unsigned char **cpp) +{ + short rval; + + rval = *(*cpp)++; + rval <<= 8; + rval |= *(*cpp)++; + return rval; +} + +/* Decode a number */ +long +decode(unsigned char **cpp) +{ + register int x; + + x = *(*cpp)++; + if(x == 0){ + return pull16(cpp) & 0xffff; /* pull16 returns -1 on error */ + } else { + return x & 0xff; /* -1 if PULLCHAR returned error */ + } +} + +/* + * icp and isize are the original packet. + * ocp is a place to put a copy if necessary. + * cpp is initially a pointer to icp. If the copy is used, + * change it to ocp. + */ + +int +slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, + unsigned char *ocp, unsigned char **cpp, int compress_cid) +{ + register struct cstate *ocs = &(comp->tstate[comp->xmit_oldest]); + register struct cstate *lcs = ocs; + register struct cstate *cs = lcs->next; + register unsigned long deltaS, deltaA; + register short changes = 0; + int hlen; + unsigned char new_seq[16]; + register unsigned char *cp = new_seq; + struct iphdr *ip; + struct tcphdr *th, *oth; + + + /* + * Don't play with runt packets. + */ + + if(isizeprotocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x3fff)) { + /* Send as regular IP */ + if(ip->protocol != IPPROTO_TCP) + comp->sls_o_nontcp++; + else + comp->sls_o_tcp++; + return isize; + } + /* Extract TCP header */ + + th = (struct tcphdr *)(((unsigned char *)ip) + ip->ihl*4); + hlen = ip->ihl*4 + th->doff*4; + + /* Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or + * some other control bit is set). Also uncompressible if + * its a runt. + */ + if(hlen > isize || th->syn || th->fin || th->rst || + ! (th->ack)){ + /* TCP connection stuff; send as regular IP */ + comp->sls_o_tcp++; + return isize; + } + /* + * Packet is compressible -- we're going to send either a + * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way, + * we need to locate (or create) the connection state. + * + * States are kept in a circularly linked list with + * xmit_oldest pointing to the end of the list. The + * list is kept in lru order by moving a state to the + * head of the list whenever it is referenced. Since + * the list is short and, empirically, the connection + * we want is almost always near the front, we locate + * states via linear search. If we don't find a state + * for the datagram, the oldest state is (re-)used. + */ + for ( ; ; ) { + if( ip->saddr == cs->cs_ip.saddr + && ip->daddr == cs->cs_ip.daddr + && th->source == cs->cs_tcp.source + && th->dest == cs->cs_tcp.dest) + goto found; + + /* if current equal oldest, at end of list */ + if ( cs == ocs ) + break; + lcs = cs; + cs = cs->next; + comp->sls_o_searches++; + }; + /* + * Didn't find it -- re-use oldest cstate. Send an + * uncompressed packet that tells the other side what + * connection number we're using for this conversation. + * + * Note that since the state list is circular, the oldest + * state points to the newest and we only need to set + * xmit_oldest to update the lru linkage. + */ + comp->sls_o_misses++; + comp->xmit_oldest = lcs->cs_this; + goto uncompressed; + +found: + /* + * Found it -- move to the front on the connection list. + */ + if(lcs == ocs) { + /* found at most recently used */ + } else if (cs == ocs) { + /* found at least recently used */ + comp->xmit_oldest = lcs->cs_this; + } else { + /* more than 2 elements */ + lcs->next = cs->next; + cs->next = ocs->next; + ocs->next = cs; + } + + /* + * Make sure that only what we expect to change changed. + * Check the following: + * IP protocol version, header length & type of service. + * The "Don't fragment" bit. + * The time-to-live field. + * The TCP header length. + * IP options, if any. + * TCP options, if any. + * If any of these things are different between the previous & + * current datagram, we send the current datagram `uncompressed'. + */ + oth = &cs->cs_tcp; + + if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl + || ip->tos != cs->cs_ip.tos + || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000)) + || ip->ttl != cs->cs_ip.ttl + || th->doff != cs->cs_tcp.doff + || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) + || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){ + goto uncompressed; + } + + /* + * Figure out which of the changing fields changed. The + * receiver expects changes in the order: urgent, window, + * ack, seq (the order minimizes the number of temporaries + * needed in this section of code). + */ + if(th->urg){ + deltaS = ntohs(th->urg_ptr); + cp = encode(cp,deltaS); + changes |= NEW_U; + } else if(th->urg_ptr != oth->urg_ptr){ + /* argh! URG not set but urp changed -- a sensible + * implementation should never do this but RFC793 + * doesn't prohibit the change so we have to deal + * with it. */ + goto uncompressed; + } + if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){ + cp = encode(cp,deltaS); + changes |= NEW_W; + } + if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){ + if(deltaA > 0x0000ffff) + goto uncompressed; + cp = encode(cp,deltaA); + changes |= NEW_A; + } + if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){ + if(deltaS > 0x0000ffff) + goto uncompressed; + cp = encode(cp,deltaS); + changes |= NEW_S; + } + + switch(changes){ + case 0: /* Nothing changed. If this packet contains data and the + * last one didn't, this is probably a data packet following + * an ack (normal on an interactive connection) and we send + * it compressed. Otherwise it's probably a retransmit, + * retransmitted ack or window probe. Send it uncompressed + * in case the other side missed the compressed version. + */ + if(ip->tot_len != cs->cs_ip.tot_len && + ntohs(cs->cs_ip.tot_len) == hlen) + break; + goto uncompressed; + break; + case SPECIAL_I: + case SPECIAL_D: + /* actual changes match one of our special case encodings -- + * send packet uncompressed. + */ + goto uncompressed; + case NEW_S|NEW_A: + if(deltaS == deltaA && + deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ + /* special case for echoed terminal traffic */ + changes = SPECIAL_I; + cp = new_seq; + } + break; + case NEW_S: + if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ + /* special case for data xfer */ + changes = SPECIAL_D; + cp = new_seq; + } + break; + } + deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id); + if(deltaS != 1){ + cp = encode(cp,deltaS); + changes |= NEW_I; + } + if(th->psh) + changes |= TCP_PUSH_BIT; + /* Grab the cksum before we overwrite it below. Then update our + * state with this packet's header. + */ + deltaA = ntohs(th->check); + memcpy(&cs->cs_ip,ip,20); + memcpy(&cs->cs_tcp,th,20); + /* We want to use the original packet as our compressed packet. + * (cp - new_seq) is the number of bytes we need for compressed + * sequence numbers. In addition we need one byte for the change + * mask, one for the connection id and two for the tcp checksum. + * So, (cp - new_seq) + 4 bytes of header are needed. + */ + deltaS = cp - new_seq; + if(compress_cid == 0 || comp->xmit_current != cs->cs_this){ + cp = ocp; + *cpp = ocp; + *cp++ = changes | NEW_C; + *cp++ = cs->cs_this; + comp->xmit_current = cs->cs_this; + } else { + cp = ocp; + *cpp = ocp; + *cp++ = changes; + } + cp = put16(cp,(short)deltaA); /* Write TCP checksum */ +/* deltaS is now the size of the change section of the compressed header */ + memcpy(cp,new_seq,deltaS); /* Write list of deltas */ + memcpy(cp+deltaS,icp+hlen,isize-hlen); + comp->sls_o_compressed++; + ocp[0] |= SL_TYPE_COMPRESSED_TCP; + return isize - hlen + deltaS + (cp - ocp); + + /* Update connection state cs & send uncompressed packet (i.e., + * a regular ip/tcp packet but with the 'conversation id' we hope + * to use on future compressed packets in the protocol field). + */ +uncompressed: + memcpy(&cs->cs_ip,ip,20); + memcpy(&cs->cs_tcp,th,20); + if (ip->ihl > 5) + memcpy(cs->cs_ipopt, ip+1, ((ip->ihl) - 5) * 4); + if (th->doff > 5) + memcpy(cs->cs_tcpopt, th+1, ((th->doff) - 5) * 4); + comp->xmit_current = cs->cs_this; + comp->sls_o_uncompressed++; + memcpy(ocp, icp, isize); + *cpp = ocp; + ocp[9] = cs->cs_this; + ocp[0] |= SL_TYPE_UNCOMPRESSED_TCP; + return isize; +} + + +int +slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) +{ + register int changes; + long x; + register struct tcphdr *thp; + register struct iphdr *ip; + register struct cstate *cs; + int len, hdrlen; + unsigned char *cp = icp; + + /* We've got a compressed packet; read the change byte */ + comp->sls_i_compressed++; + if(isize < 3){ + comp->sls_i_error++; + return 0; + } + changes = *cp++; + if(changes & NEW_C){ + /* Make sure the state index is in range, then grab the state. + * If we have a good state index, clear the 'discard' flag. + */ + x = *cp++; /* Read conn index */ + if(x < 0 || x > comp->rslot_limit) + goto bad; + + comp->flags &=~ SLF_TOSS; + comp->recv_current = x; + } else { + /* this packet has an implicit state index. If we've + * had a line error since the last time we got an + * explicit state index, we have to toss the packet. */ + if(comp->flags & SLF_TOSS){ + comp->sls_i_tossed++; + return 0; + } + } + cs = &comp->rstate[comp->recv_current]; + thp = &cs->cs_tcp; + ip = &cs->cs_ip; + + if((x = pull16(&cp)) == -1) { /* Read the TCP checksum */ + goto bad; + } + thp->check = htons(x); + + thp->psh = (changes & TCP_PUSH_BIT) ? 1 : 0; +/* + * we can use the same number for the length of the saved header and + * the current one, because the packet wouldn't have been sent + * as compressed unless the options were the same as the previous one + */ + + hdrlen = ip->ihl * 4 + thp->doff * 4; + + switch(changes & SPECIALS_MASK){ + case SPECIAL_I: /* Echoed terminal traffic */ + { + register short i; + i = ntohs(ip->tot_len) - hdrlen; + thp->ack_seq = htonl( ntohl(thp->ack_seq) + i); + thp->seq = htonl( ntohl(thp->seq) + i); + } + break; + + case SPECIAL_D: /* Unidirectional data */ + thp->seq = htonl( ntohl(thp->seq) + + ntohs(ip->tot_len) - hdrlen); + break; + + default: + if(changes & NEW_U){ + thp->urg = 1; + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->urg_ptr = htons(x); + } else + thp->urg = 0; + if(changes & NEW_W){ + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->window = htons( ntohs(thp->window) + x); + } + if(changes & NEW_A){ + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->ack_seq = htonl( ntohl(thp->ack_seq) + x); + } + if(changes & NEW_S){ + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->seq = htonl( ntohl(thp->seq) + x); + } + break; + } + if(changes & NEW_I){ + if((x = decode(&cp)) == -1) { + goto bad; + } + ip->id = htons (ntohs (ip->id) + x); + } else + ip->id = htons (ntohs (ip->id) + 1); + + /* + * At this point, cp points to the first byte of data in the + * packet. Put the reconstructed TCP and IP headers back on the + * packet. Recalculate IP checksum (but not TCP checksum). + */ + + len = isize - (cp - icp); + if (len < 0) + goto bad; + len += hdrlen; + ip->tot_len = htons(len); + ip->check = 0; + + memmove(icp + hdrlen, cp, len - hdrlen); + + cp = icp; + memcpy(cp, ip, 20); + cp += 20; + + if (ip->ihl > 5) { + memcpy(cp, cs->cs_ipopt, (ip->ihl - 5) * 4); + cp += (ip->ihl - 5) * 4; + } + + put_unaligned(ip_fast_csum(icp, ip->ihl), + &((struct iphdr *)icp)->check); + + memcpy(cp, thp, 20); + cp += 20; + + if (thp->doff > 5) { + memcpy(cp, cs->cs_tcpopt, ((thp->doff) - 5) * 4); + cp += ((thp->doff) - 5) * 4; + } + + return len; +bad: + comp->sls_i_error++; + return slhc_toss( comp ); +} + + +int +slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +{ + register struct cstate *cs; + unsigned ihl; + + unsigned char index; + + if(isize < 20) { + /* The packet is shorter than a legal IP header */ + comp->sls_i_runt++; + return slhc_toss( comp ); + } + /* Peek at the IP header's IHL field to find its length */ + ihl = icp[0] & 0xf; + if(ihl < 20 / 4){ + /* The IP header length field is too small */ + comp->sls_i_runt++; + return slhc_toss( comp ); + } + index = icp[9]; + icp[9] = IPPROTO_TCP; + + if (ip_fast_csum(icp, ihl)) { + /* Bad IP header checksum; discard */ + comp->sls_i_badcheck++; + return slhc_toss( comp ); + } + if(index > comp->rslot_limit) { + comp->sls_i_error++; + return slhc_toss(comp); + } + + /* Update local state */ + cs = &comp->rstate[comp->recv_current = index]; + comp->flags &=~ SLF_TOSS; + memcpy(&cs->cs_ip,icp,20); + memcpy(&cs->cs_tcp,icp + ihl*4,20); + if (ihl > 5) + memcpy(cs->cs_ipopt, icp + sizeof(struct iphdr), (ihl - 5) * 4); + if (cs->cs_tcp.doff > 5) + memcpy(cs->cs_tcpopt, icp + ihl*4 + sizeof(struct tcphdr), (cs->cs_tcp.doff - 5) * 4); + cs->cs_hsize = ihl*2 + cs->cs_tcp.doff*2; + /* Put headers back on packet + * Neither header checksum is recalculated + */ + comp->sls_i_uncompressed++; + return isize; +} + + +int +slhc_toss(struct slcompress *comp) +{ + if ( comp == NULLSLCOMPR ) + return 0; + + comp->flags |= SLF_TOSS; + return 0; +} + + +void slhc_i_status(struct slcompress *comp) +{ + if (comp != NULLSLCOMPR) { + printk("\t%d Cmp, %d Uncmp, %d Bad, %d Tossed\n", + comp->sls_i_compressed, + comp->sls_i_uncompressed, + comp->sls_i_error, + comp->sls_i_tossed); + } +} + + +void slhc_o_status(struct slcompress *comp) +{ + if (comp != NULLSLCOMPR) { + printk("\t%d Cmp, %d Uncmp, %d AsIs, %d NotTCP\n", + comp->sls_o_compressed, + comp->sls_o_uncompressed, + comp->sls_o_tcp, + comp->sls_o_nontcp); + printk("\t%10d Searches, %10d Misses\n", + comp->sls_o_searches, + comp->sls_o_misses); + } +} + +/* Should this be surrounded with "#ifdef CONFIG_MODULES" ? */ +/* VJ header compression */ +EXPORT_SYMBOL(slhc_init); +EXPORT_SYMBOL(slhc_free); +EXPORT_SYMBOL(slhc_remember); +EXPORT_SYMBOL(slhc_compress); +EXPORT_SYMBOL(slhc_uncompress); +EXPORT_SYMBOL(slhc_toss); + +#ifdef MODULE + +int init_module(void) +{ + printk(KERN_INFO "CSLIP: code copyright 1989 Regents of the University of California\n"); + return 0; +} + +void cleanup_module(void) +{ + return; +} + +#endif /* MODULE */ +#else /* CONFIG_INET */ + + +int +slhc_toss(struct slcompress *comp) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss"); + return -EINVAL; +} +int +slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress"); + return -EINVAL; +} +int +slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, + unsigned char *ocp, unsigned char **cpp, int compress_cid) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress"); + return -EINVAL; +} + +int +slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember"); + return -EINVAL; +} + +void +slhc_free(struct slcompress *comp) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free"); + return; +} +struct slcompress * +slhc_init(int rslots, int tslots) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init"); + return NULL; +} +EXPORT_SYMBOL(slhc_init); +EXPORT_SYMBOL(slhc_free); +EXPORT_SYMBOL(slhc_remember); +EXPORT_SYMBOL(slhc_compress); +EXPORT_SYMBOL(slhc_uncompress); +EXPORT_SYMBOL(slhc_toss); + +#endif /* CONFIG_INET */ +MODULE_LICENSE("Dual BSD/GPL"); -- To view, visit https://gerrit.osmocom.org/634 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ied69c143678dc4a64cecc671f5c4dfebe19d8519 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter From gerrit-no-reply at lists.osmocom.org Mon Aug 1 10:17:56 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Mon, 1 Aug 2016 10:17:56 +0000 Subject: [PATCH] openbsc[master]: Modifed version of slhc Message-ID: Review at https://gerrit.osmocom.org/635 Modifed version of slhc Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 --- M openbsc/include/openbsc/debug.h R openbsc/include/openbsc/slhc.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/slhc.c 4 files changed, 127 insertions(+), 176 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/35/635/1 diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 43ebb19..90ddca5 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -29,6 +29,7 @@ DBSSGP, DLLC, DSNDCP, + DSLHC, DNAT, DCTRL, DSMPP, diff --git a/openbsc/include/openbsc/slhc_vj.h b/openbsc/include/openbsc/slhc.h similarity index 89% rename from openbsc/include/openbsc/slhc_vj.h rename to openbsc/include/openbsc/slhc.h index 0a85dc0..2e926dd 100644 --- a/openbsc/include/openbsc/slhc_vj.h +++ b/openbsc/include/openbsc/slhc.h @@ -80,7 +80,6 @@ * means "IP packet". */ - #include #include @@ -109,7 +108,7 @@ * data type and sizes conversion assumptions: * * VJ code KA9Q style generic - * u_char byte_t unsigned char 8 bits + * u_char byte_t uint8_t 8 bits * u_short int16 unsigned short 16 bits * u_int int16 unsigned short 16 bits * u_long unsigned long unsigned long 32 bits @@ -130,8 +129,8 @@ struct cstate *next; /* next in ring (xmit) */ struct iphdr cs_ip; /* ip/tcp hdr from most recent packet */ struct tcphdr cs_tcp; - unsigned char cs_ipopt[64]; - unsigned char cs_tcpopt[64]; + uint8_t cs_ipopt[64]; + uint8_t cs_tcpopt[64]; int cs_hsize; }; #define NULLSLSTATE (struct cstate *)0 @@ -173,19 +172,16 @@ #define __ARGS(x) x /* In slhc.c: */ -struct slcompress *slhc_init __ARGS((int rslots, int tslots)); -void slhc_free __ARGS((struct slcompress *comp)); +struct slcompress *slhc_init(int rslots, int tslots); -int slhc_compress __ARGS((struct slcompress *comp, unsigned char *icp, - int isize, unsigned char *ocp, unsigned char **cpp, - int compress_cid)); -int slhc_uncompress __ARGS((struct slcompress *comp, unsigned char *icp, - int isize)); -int slhc_remember __ARGS((struct slcompress *comp, unsigned char *icp, - int isize)); -int slhc_toss __ARGS((struct slcompress *comp)); +void slhc_free(struct slcompress *comp); -void slhc_i_status __ARGS((struct slcompress *comp)); -void slhc_o_status __ARGS((struct slcompress *comp)); +int slhc_compress(struct slcompress *comp, uint8_t *icp, int isize, uint8_t *ocp, uint8_t **cpp, int compress_cid); +int slhc_uncompress(struct slcompress *comp, uint8_t *icp, int isize); +int slhc_remember(struct slcompress *comp, uint8_t *icp, int isize); +int slhc_toss(struct slcompress *comp); + +void slhc_i_status(struct slcompress *comp); +void slhc_o_status(struct slcompress *comp); #endif /* _SLHC_H */ diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 6dc7e16..548b38c 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -23,6 +23,7 @@ $(OSMO_LIBS) $(LIBCRYPTO_LIBS) -lrt osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \ + slhc.c \ sgsn_main.c sgsn_vty.c sgsn_libgtp.c \ gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c crc24.c \ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ diff --git a/openbsc/src/gprs/slhc.c b/openbsc/src/gprs/slhc.c index b1a855c..b201ddb 100644 --- a/openbsc/src/gprs/slhc.c +++ b/openbsc/src/gprs/slhc.c @@ -50,62 +50,71 @@ * driver code belonging close to PPP and SLIP */ -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#ifdef CONFIG_INET -/* Entire module is for IP only */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +static uint8_t *encode(uint8_t *cp, uint16_t n); +static long decode(uint8_t **cpp); +static uint8_t * put16(uint8_t *cp, uint16_t x); +static uint16_t pull16(uint8_t **cpp); -static unsigned char *encode(unsigned char *cp, unsigned short n); -static long decode(unsigned char **cpp); -static unsigned char * put16(unsigned char *cp, unsigned short x); -static unsigned short pull16(unsigned char **cpp); + +/* Replacement for kernel space function ip_fast_csum() */ +static uint16_t ip_fast_csum(uint8_t *iph, int ihl) +{ + int i; + uint16_t temp; + uint32_t accumulator = 0xFFFF; + + for(i=0;i0xFFFF) + { + accumulator++; + accumulator&=0xFFFF; + } + } + + return (uint16_t)(htons(~accumulator)&0xFFFF); +} + +/* Replacement for kernel space function put_unaligned() */ +static void put_unaligned(uint16_t val, void *ptr) +{ + memcpy(ptr,&val,sizeof(val)); +} + /* Initialize compression data structure * slots must be in range 0 to 255 (zero meaning no compression) */ -struct slcompress * -slhc_init(int rslots, int tslots) +struct slcompress *slhc_init(int rslots, int tslots) { register short i; register struct cstate *ts; struct slcompress *comp; - MOD_INC_USE_COUNT; - comp = (struct slcompress *)kmalloc(sizeof(struct slcompress), - GFP_KERNEL); + comp = (struct slcompress *)talloc_zero_size(NULL,sizeof(struct slcompress)); if (! comp) goto out_fail; memset(comp, 0, sizeof(struct slcompress)); if ( rslots > 0 && rslots < 256 ) { size_t rsize = rslots * sizeof(struct cstate); - comp->rstate = (struct cstate *) kmalloc(rsize, GFP_KERNEL); + comp->rstate = (struct cstate *) talloc_zero_size(NULL, rsize); if (! comp->rstate) goto out_free; memset(comp->rstate, 0, rsize); @@ -114,7 +123,7 @@ if ( tslots > 0 && tslots < 256 ) { size_t tsize = tslots * sizeof(struct cstate); - comp->tstate = (struct cstate *) kmalloc(tsize, GFP_KERNEL); + comp->tstate = (struct cstate *) talloc_zero_size(NULL, tsize); if (! comp->tstate) goto out_free2; memset(comp->tstate, 0, tsize); @@ -144,36 +153,34 @@ return comp; out_free2: - kfree((unsigned char *)comp->rstate); + talloc_free((uint8_t *)comp->rstate); out_free: - kfree((unsigned char *)comp); + talloc_free((uint8_t *)comp); out_fail: - MOD_DEC_USE_COUNT; + + return NULL; } - /* Free a compression data structure */ -void -slhc_free(struct slcompress *comp) +void slhc_free(struct slcompress *comp) { + LOGP(DSLHC, LOGL_DEBUG, "slhc_free(): Freeing compression states...\n"); + if ( comp == NULLSLCOMPR ) return; if ( comp->tstate != NULLSLSTATE ) - kfree( comp->tstate ); + talloc_free(comp->tstate ); if ( comp->rstate != NULLSLSTATE ) - kfree( comp->rstate ); + talloc_free( comp->rstate ); - kfree( comp ); - MOD_DEC_USE_COUNT; + talloc_free( comp ); } - /* Put a short in host order into a char array in network order */ -static inline unsigned char * -put16(unsigned char *cp, unsigned short x) +static inline uint8_t *put16(uint8_t *cp, uint16_t x) { *cp++ = x >> 8; *cp++ = x; @@ -183,8 +190,7 @@ /* Encode a number */ -unsigned char * -encode(unsigned char *cp, unsigned short n) +uint8_t *encode(uint8_t *cp, uint16_t n) { if(n >= 256 || n == 0){ *cp++ = 0; @@ -196,8 +202,7 @@ } /* Pull a 16-bit integer in host order from buffer in network byte order */ -static unsigned short -pull16(unsigned char **cpp) +static uint16_t pull16(uint8_t **cpp) { short rval; @@ -208,8 +213,7 @@ } /* Decode a number */ -long -decode(unsigned char **cpp) +long decode(uint8_t **cpp) { register int x; @@ -228,9 +232,7 @@ * change it to ocp. */ -int -slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, - unsigned char *ocp, unsigned char **cpp, int compress_cid) +int slhc_compress(struct slcompress *comp, uint8_t *icp, int isize, uint8_t *ocp, uint8_t **cpp, int compress_cid) { register struct cstate *ocs = &(comp->tstate[comp->xmit_oldest]); register struct cstate *lcs = ocs; @@ -238,11 +240,10 @@ register unsigned long deltaS, deltaA; register short changes = 0; int hlen; - unsigned char new_seq[16]; - register unsigned char *cp = new_seq; + uint8_t new_seq[16]; + register uint8_t *cp = new_seq; struct iphdr *ip; struct tcphdr *th, *oth; - /* * Don't play with runt packets. @@ -260,11 +261,12 @@ comp->sls_o_nontcp++; else comp->sls_o_tcp++; + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Not a TCP packat, will not touch...\n"); return isize; } - /* Extract TCP header */ - th = (struct tcphdr *)(((unsigned char *)ip) + ip->ihl*4); + /* Extract TCP header */ + th = (struct tcphdr *)(((uint8_t *)ip) + ip->ihl*4); hlen = ip->ihl*4 + th->doff*4; /* Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or @@ -275,8 +277,10 @@ ! (th->ack)){ /* TCP connection stuff; send as regular IP */ comp->sls_o_tcp++; + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Packet is part of a TCP connection, will not touch...\n"); return isize; } + /* * Packet is compressible -- we're going to send either a * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way, @@ -291,6 +295,9 @@ * states via linear search. If we don't find a state * for the datagram, the oldest state is (re-)used. */ + + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Compressible packet detected!\n"); + for ( ; ; ) { if( ip->saddr == cs->cs_ip.saddr && ip->daddr == cs->cs_ip.daddr @@ -314,11 +321,14 @@ * state points to the newest and we only need to set * xmit_oldest to update the lru linkage. */ + + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Header not yet seen, will memorize header for the next turn...\n"); comp->sls_o_misses++; comp->xmit_oldest = lcs->cs_this; goto uncompressed; found: + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Header already seen, trying to compress...\n"); /* * Found it -- move to the front on the connection list. */ @@ -348,6 +358,7 @@ */ oth = &cs->cs_tcp; + if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl || ip->tos != cs->cs_ip.tos || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000)) @@ -355,6 +366,7 @@ || th->doff != cs->cs_tcp.doff || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){ + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): The header contains unexpected changes, can't compress...\n"); goto uncompressed; } @@ -373,6 +385,7 @@ * implementation should never do this but RFC793 * doesn't prohibit the change so we have to deal * with it. */ + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): URG not set but urp changed, can't compress...\n"); goto uncompressed; } if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){ @@ -381,13 +394,19 @@ } if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){ if(deltaA > 0x0000ffff) + { + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): (deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L, can't compress...\n"); goto uncompressed; + } cp = encode(cp,deltaA); changes |= NEW_A; } if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){ if(deltaS > 0x0000ffff) + { + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): (deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L, can't compress...\n"); goto uncompressed; + } cp = encode(cp,deltaS); changes |= NEW_S; } @@ -403,6 +422,7 @@ if(ip->tot_len != cs->cs_ip.tot_len && ntohs(cs->cs_ip.tot_len) == hlen) break; + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Retransmitted packet detected, can't compress...\n"); goto uncompressed; break; case SPECIAL_I: @@ -410,6 +430,7 @@ /* actual changes match one of our special case encodings -- * send packet uncompressed. */ + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Special case detected, can't compress...\n"); goto uncompressed; case NEW_S|NEW_A: if(deltaS == deltaA && @@ -438,7 +459,6 @@ * state with this packet's header. */ deltaA = ntohs(th->check); - memcpy(&cs->cs_ip,ip,20); memcpy(&cs->cs_tcp,th,20); /* We want to use the original packet as our compressed packet. * (cp - new_seq) is the number of bytes we need for compressed @@ -471,6 +491,7 @@ * to use on future compressed packets in the protocol field). */ uncompressed: + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Packet will be sent uncompressed...\n"); memcpy(&cs->cs_ip,ip,20); memcpy(&cs->cs_tcp,th,20); if (ip->ihl > 5) @@ -487,8 +508,7 @@ } -int -slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) +int slhc_uncompress(struct slcompress *comp, uint8_t *icp, int isize) { register int changes; long x; @@ -496,7 +516,7 @@ register struct iphdr *ip; register struct cstate *cs; int len, hdrlen; - unsigned char *cp = icp; + uint8_t *cp = icp; /* We've got a compressed packet; read the change byte */ comp->sls_i_compressed++; @@ -544,6 +564,8 @@ switch(changes & SPECIALS_MASK){ case SPECIAL_I: /* Echoed terminal traffic */ + LOGP(DSLHC, LOGL_DEBUG, "slhc_uncompress(): Echoed terminal traffic detected\n"); + { register short i; i = ntohs(ip->tot_len) - hdrlen; @@ -553,11 +575,13 @@ break; case SPECIAL_D: /* Unidirectional data */ + LOGP(DSLHC, LOGL_DEBUG, "slhc_uncompress(): Unidirectional data detected\n"); thp->seq = htonl( ntohl(thp->seq) + ntohs(ip->tot_len) - hdrlen); break; default: + LOGP(DSLHC, LOGL_DEBUG, "slhc_uncompress(): default packet type detected\n"); if(changes & NEW_U){ thp->urg = 1; if((x = decode(&cp)) == -1) { @@ -607,6 +631,7 @@ ip->tot_len = htons(len); ip->check = 0; + LOGP(DSLHC, LOGL_DEBUG, "slhc_uncompress(): making space for the reconstructed header...\n"); memmove(icp + hdrlen, cp, len - hdrlen); cp = icp; @@ -618,8 +643,7 @@ cp += (ip->ihl - 5) * 4; } - put_unaligned(ip_fast_csum(icp, ip->ihl), - &((struct iphdr *)icp)->check); + put_unaligned(ip_fast_csum(icp, ip->ihl), &((struct iphdr *)icp)->check); memcpy(cp, thp, 20); cp += 20; @@ -631,22 +655,24 @@ return len; bad: + LOGP(DSLHC, LOGL_DEBUG, "slhc_uncompress(): bad packet detected!\n"); comp->sls_i_error++; return slhc_toss( comp ); } -int -slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +int slhc_remember(struct slcompress *comp, uint8_t *icp, int isize) { register struct cstate *cs; unsigned ihl; - unsigned char index; + uint8_t index; + uint16_t checksum; if(isize < 20) { /* The packet is shorter than a legal IP header */ comp->sls_i_runt++; + LOGP(DSLHC, LOGL_DEBUG, "slhc_remember(): The packet is shorter than a legal IP header ==> slhc_toss()\n"); return slhc_toss( comp ); } /* Peek at the IP header's IHL field to find its length */ @@ -654,18 +680,23 @@ if(ihl < 20 / 4){ /* The IP header length field is too small */ comp->sls_i_runt++; + LOGP(DSLHC, LOGL_DEBUG, "slhc_remember(): The IP header length field is too small ==> slhc_toss()\n"); return slhc_toss( comp ); } + index = icp[9]; icp[9] = IPPROTO_TCP; + checksum = ip_fast_csum(icp, ihl); - if (ip_fast_csum(icp, ihl)) { + if (checksum) { /* Bad IP header checksum; discard */ comp->sls_i_badcheck++; + LOGP(DSLHC, LOGL_DEBUG, "slhc_remember(): Bad IP header checksum; discard ==> slhc_toss()\n"); return slhc_toss( comp ); } if(index > comp->rslot_limit) { comp->sls_i_error++; + LOGP(DSLHC, LOGL_DEBUG, "slhc_remember(): index > comp->rslot_limit ==> slhc_toss()\n"); return slhc_toss(comp); } @@ -686,10 +717,9 @@ return isize; } - -int -slhc_toss(struct slcompress *comp) +int slhc_toss(struct slcompress *comp) { + LOGP(DSLHC, LOGL_DEBUG, "slhc_toss(): Reset compression state...\n"); if ( comp == NULLSLCOMPR ) return 0; @@ -697,11 +727,10 @@ return 0; } - void slhc_i_status(struct slcompress *comp) { if (comp != NULLSLCOMPR) { - printk("\t%d Cmp, %d Uncmp, %d Bad, %d Tossed\n", + LOGP(DSLHC, LOGL_DEBUG, "slhc_i_status(): %d Cmp, %d Uncmp, %d Bad, %d Tossed\n", comp->sls_i_compressed, comp->sls_i_uncompressed, comp->sls_i_error, @@ -709,92 +738,16 @@ } } - void slhc_o_status(struct slcompress *comp) { if (comp != NULLSLCOMPR) { - printk("\t%d Cmp, %d Uncmp, %d AsIs, %d NotTCP\n", + LOGP(DSLHC, LOGL_DEBUG, "slhc_o_status(): %d Cmp, %d Uncmp, %d AsIs, %d NotTCP %d Searches, %d Misses\n", comp->sls_o_compressed, comp->sls_o_uncompressed, comp->sls_o_tcp, - comp->sls_o_nontcp); - printk("\t%10d Searches, %10d Misses\n", + comp->sls_o_nontcp, comp->sls_o_searches, comp->sls_o_misses); } } -/* Should this be surrounded with "#ifdef CONFIG_MODULES" ? */ -/* VJ header compression */ -EXPORT_SYMBOL(slhc_init); -EXPORT_SYMBOL(slhc_free); -EXPORT_SYMBOL(slhc_remember); -EXPORT_SYMBOL(slhc_compress); -EXPORT_SYMBOL(slhc_uncompress); -EXPORT_SYMBOL(slhc_toss); - -#ifdef MODULE - -int init_module(void) -{ - printk(KERN_INFO "CSLIP: code copyright 1989 Regents of the University of California\n"); - return 0; -} - -void cleanup_module(void) -{ - return; -} - -#endif /* MODULE */ -#else /* CONFIG_INET */ - - -int -slhc_toss(struct slcompress *comp) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss"); - return -EINVAL; -} -int -slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress"); - return -EINVAL; -} -int -slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, - unsigned char *ocp, unsigned char **cpp, int compress_cid) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress"); - return -EINVAL; -} - -int -slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember"); - return -EINVAL; -} - -void -slhc_free(struct slcompress *comp) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free"); - return; -} -struct slcompress * -slhc_init(int rslots, int tslots) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init"); - return NULL; -} -EXPORT_SYMBOL(slhc_init); -EXPORT_SYMBOL(slhc_free); -EXPORT_SYMBOL(slhc_remember); -EXPORT_SYMBOL(slhc_compress); -EXPORT_SYMBOL(slhc_uncompress); -EXPORT_SYMBOL(slhc_toss); - -#endif /* CONFIG_INET */ -MODULE_LICENSE("Dual BSD/GPL"); -- To view, visit https://gerrit.osmocom.org/635 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter From gerrit-no-reply at lists.osmocom.org Mon Aug 1 10:17:56 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Mon, 1 Aug 2016 10:17:56 +0000 Subject: [PATCH] openbsc[master]: moved gprs_sndcp.h to include dir Message-ID: Review at https://gerrit.osmocom.org/636 moved gprs_sndcp.h to include dir Change-Id: If4e4f1252c81d7907c1b4d738c982bb172b128c9 --- M openbsc/include/openbsc/Makefile.am R openbsc/include/openbsc/gprs_sndcp.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/gprs_sndcp.c M openbsc/src/gprs/gprs_sndcp_vty.c 5 files changed, 3 insertions(+), 7 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/36/636/1 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index c272b14..983f573 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,7 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h + gtphub.h gprs_sndcp.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/src/gprs/gprs_sndcp.h b/openbsc/include/openbsc/gprs_sndcp.h similarity index 100% rename from openbsc/src/gprs/gprs_sndcp.h rename to openbsc/include/openbsc/gprs_sndcp.h diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 548b38c..a118a19 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -6,8 +6,6 @@ OSMO_LIBS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) \ $(LIBOSMOCTRL_LIBS) $(LIBOSMOGB_LIBS) -noinst_HEADERS = gprs_sndcp.h - bin_PROGRAMS = osmo-gbproxy if HAVE_LIBGTP diff --git a/openbsc/src/gprs/gprs_sndcp.c b/openbsc/src/gprs/gprs_sndcp.c index 75f95c9..4f71121 100644 --- a/openbsc/src/gprs/gprs_sndcp.c +++ b/openbsc/src/gprs/gprs_sndcp.c @@ -34,8 +34,7 @@ #include #include #include - -#include "gprs_sndcp.h" +#include /* Chapter 7.2: SN-PDU Formats */ struct sndcp_common_hdr { diff --git a/openbsc/src/gprs/gprs_sndcp_vty.c b/openbsc/src/gprs/gprs_sndcp_vty.c index deeef07..430881f 100644 --- a/openbsc/src/gprs/gprs_sndcp_vty.c +++ b/openbsc/src/gprs/gprs_sndcp_vty.c @@ -35,8 +35,7 @@ #include #include #include - -#include "gprs_sndcp.h" +#include #include #include -- To view, visit https://gerrit.osmocom.org/636 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: If4e4f1252c81d7907c1b4d738c982bb172b128c9 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter From gerrit-no-reply at lists.osmocom.org Mon Aug 1 11:30:07 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Mon, 1 Aug 2016 11:30:07 +0000 Subject: [PATCH] openbsc[master]: Added slhc.h to Makefile.am Message-ID: Review at https://gerrit.osmocom.org/637 Added slhc.h to Makefile.am Change-Id: Ib28596ba5633ae1e9301fd81ed1dbf7236a8805d --- M openbsc/include/openbsc/Makefile.am 1 file changed, 1 insertion(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/37/637/1 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 983f573..9ef8a15 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,7 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_sndcp.h + gtphub.h gprs_sndcp.h slhc.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc -- To view, visit https://gerrit.osmocom.org/637 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ib28596ba5633ae1e9301fd81ed1dbf7236a8805d Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter From gerrit-no-reply at lists.osmocom.org Mon Aug 1 11:56:08 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Mon, 1 Aug 2016 11:56:08 +0000 Subject: [PATCH] openbsc[master]: Added llc-xid encoder / decoder Message-ID: Review at https://gerrit.osmocom.org/638 Added llc-xid encoder / decoder Change-Id: Ia06e4cb08bf9b48c2a4682606d1b1a91d19a9d37 --- M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_llc_xid.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_llc_xid.c 4 files changed, 316 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/38/638/1 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 9ef8a15..9e8c554 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,7 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_sndcp.h slhc.h + gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_llc_xid.h b/openbsc/include/openbsc/gprs_llc_xid.h new file mode 100644 index 0000000..c840edb --- /dev/null +++ b/openbsc/include/openbsc/gprs_llc_xid.h @@ -0,0 +1,58 @@ +/* GPRS LLC XID field encoding/decoding as per 3GPP TS 04.64 */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_LLC_XID_H +#define _GPRS_LLC_XID_H + +#include +#include + +/* TS 101 351 6.4.1.6 Exchange Identification (XID) + command/response parameter field */ +struct gprs_llc_xid_field { + struct llist_head list; + uint8_t type; /* See also Table 6: LLC layer parameter + negotiation */ + uint8_t *data; /* Payload data (octets) */ + unsigned int data_len; /* Payload length */ +}; + +/* Transform a list with XID fields into a XID message (bytes) */ +int gprs_llc_compile_xid(struct llist_head *xid_fields, uint8_t * bytes, + int bytes_maxlen); + +/* Transform a XID message (bytes) into a list of XID fields */ +int gprs_llc_parse_xid(struct llist_head *xid_fields, uint8_t * bytes, + int bytes_len); + +/* Free llist with xid fields */ +void gprs_llc_free_xid(struct llist_head *xid_fields); + +/* Create a duplicate of an XID-Field */ +struct gprs_llc_xid_field *gprs_llc_duplicate_xid_field(struct + gprs_llc_xid_field + *xid_field); + +/* Dump a list with XID fields (Debug) */ +void gprs_llc_dump_xid_fields(struct llist_head *xid_fields); + +#endif diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index a118a19..b3a5137 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -23,7 +23,8 @@ osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \ slhc.c \ sgsn_main.c sgsn_vty.c sgsn_libgtp.c \ - gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c crc24.c \ + gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c \ + gprs_llc_xid.c crc24.c \ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ diff --git a/openbsc/src/gprs/gprs_llc_xid.c b/openbsc/src/gprs/gprs_llc_xid.c new file mode 100644 index 0000000..d8c5339 --- /dev/null +++ b/openbsc/src/gprs/gprs_llc_xid.c @@ -0,0 +1,255 @@ +/* GPRS LLC XID field encoding/decoding as per 3GPP TS 04.64 */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +/* Parse XID parameter field */ +static int +decode_xid_field(uint8_t *bytes, uint8_t bytes_len, + struct gprs_llc_xid_field *xid_field) +{ + uint8_t xl; + uint8_t type; + uint8_t len; + int bytes_counter = 0; + + /* Exit immediately if it is clear that no + parseable data is present */ + if ((bytes_len < 1) || (!(bytes))) + return -EINVAL; + + /* Exit immediately if no result can be stored */ + if (!xid_field) + return -EINVAL; + + /* Extract header info */ + xl = (*bytes >> 7) & 1; + type = (*bytes >> 2) & 0x1F; + + /* Extract length field */ + len = (*bytes) & 0x3; + bytes++; + bytes_counter++; + if (xl) { + if (bytes_len < 2) + return -EINVAL; + len = (len << 6) & 0xC0; + len |= ((*bytes) >> 2) & 0x3F; + bytes++; + bytes_counter++; + } + + /* Fill out struct */ + xid_field->type = type; + xid_field->data_len = len; + if (len > 0) { + if (bytes_len < bytes_counter + len) + return -EINVAL; + + xid_field->data = + talloc_zero_size(NULL, xid_field->data_len); + memcpy(xid_field->data, bytes, xid_field->data_len); + } else + xid_field->data = NULL; + + /* Return consumed length */ + return bytes_counter + len; +} + + +/* Encode XID parameter field */ +static int +encode_xid_field(uint8_t *bytes, int bytes_maxlen, + struct gprs_llc_xid_field *xid_field) +{ + int xl = 0; + + /* Exit immediately if no source struct is available */ + if (!xid_field) + return -EINVAL; + + /* When the length does not fit into 2 bits, + we need extended length fields */ + if (xid_field->data_len > 3) + xl = 1; + + /* Exit immediately if it is clear that no + encoding result can be stored */ + if (bytes_maxlen < xid_field->data_len + 1 + xl) + return -EINVAL; + + /* There are only 5 bits reserved for the type, exit on exceed */ + if (xid_field->type > 31) + return -EINVAL; + + /* Encode header */ + memset(bytes, 0, bytes_maxlen); + if (xl) + bytes[0] |= 0x80; + bytes[0] |= (((xid_field->type) & 0x1F) << 2); + + if (xl) { + bytes[0] |= (((xid_field->data_len) >> 6) & 0x03); + bytes[1] = ((xid_field->data_len) << 2) & 0xFC; + } else + bytes[0] |= ((xid_field->data_len) & 0x03); + + /* Append payload data */ + if ((xid_field->data) && (xid_field->data_len)) + memcpy(bytes + 1 + xl, xid_field->data, + xid_field->data_len); + + /* Return generated length */ + return xid_field->data_len + 1 + xl; +} + + +/* Transform a list with XID fields into a XID message (bytes) */ +int +gprs_llc_compile_xid(struct llist_head *xid_fields, uint8_t * bytes, + int bytes_maxlen) +{ + struct gprs_llc_xid_field *xid_field; + int rc; + int byte_counter = 0; + + memset(bytes, 0, bytes_maxlen); + + llist_for_each_entry(xid_field, xid_fields, list) { + /* Encode XID-Field */ + rc = encode_xid_field(bytes, bytes_maxlen, xid_field); + + /* Immediately stop on error */ + if (rc < 0) + return rc; + + /* Advance pointer and lower maxlen for the + next encoding round */ + bytes += rc; + byte_counter += rc; + bytes_maxlen -= rc; + } + + /* Return generated length */ + return byte_counter; +} + + +/* Transform a XID message (bytes) into a list of XID fields */ +int +gprs_llc_parse_xid(struct llist_head *xid_fields, uint8_t * bytes, + int bytes_len) +{ + struct gprs_llc_xid_field *xid_field; + int rc; + + while (1) { + /* Decode XID field */ + xid_field = talloc_zero(NULL, struct gprs_llc_xid_field); + rc = decode_xid_field(bytes, bytes_len, xid_field); + + /* Immediately stop on error */ + if (rc < 0) + return rc; + + /* Add parsed XID field to list */ + llist_add(&xid_field->list, xid_fields); + + /* Advance pointer and lower bytes_len for the next + decoding round */ + bytes += rc; + bytes_len -= rc; + + /* We are (scuccessfully) done when no further byes are left */ + if (bytes_len == 0) + return 0; + } +} + + +/* Free llist with xid fields */ +void gprs_llc_free_xid(struct llist_head *xid_fields) +{ + struct gprs_llc_xid_field *xid_field; + + llist_for_each_entry(xid_field, xid_fields, list) { + if ((xid_field->data) && (xid_field->data_len)) + talloc_free(xid_field->data); + talloc_free(xid_field); + } + +} + + +/* Create a duplicate of an XID-Field */ +struct gprs_llc_xid_field *gprs_llc_duplicate_xid_field(struct + gprs_llc_xid_field + *xid_field) +{ + struct gprs_llc_xid_field *duplicate_of_xid_field; + + /* Create a copy of the XID field in memory */ + duplicate_of_xid_field = + talloc_zero(NULL, struct gprs_llc_xid_field); + memcpy(duplicate_of_xid_field, xid_field, + sizeof(struct gprs_llc_xid_field)); + duplicate_of_xid_field->data = + talloc_zero_size(NULL, xid_field->data_len); + memcpy(duplicate_of_xid_field->data, xid_field->data, + xid_field->data_len); + + /* Wipeout all llist information in the duplicate (just to be sure) */ + memset(&duplicate_of_xid_field->list, 0, + sizeof(struct llist_head)); + + return duplicate_of_xid_field; +} + + +/* Dump a list with XID fields (Debug) */ +void gprs_llc_dump_xid_fields(struct llist_head *xid_fields) +{ + struct gprs_llc_xid_field *xid_field; + + llist_for_each_entry(xid_field, xid_fields, list) { + LOGP(DSNDCP, LOGL_DEBUG, + "XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + osmo_hexdump_nospc(xid_field->data, + xid_field->data_len)); + } +} -- To view, visit https://gerrit.osmocom.org/638 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ia06e4cb08bf9b48c2a4682606d1b1a91d19a9d37 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter From gerrit-no-reply at lists.osmocom.org Mon Aug 1 12:07:01 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 1 Aug 2016 12:07:01 +0000 Subject: [PATCH] openbsc[master]: add example config for sysmobts Message-ID: Review at https://gerrit.osmocom.org/639 add example config for sysmobts Many years ago, there was no difference between the libbsc support for nanobts and sysmobts. However, this is not the case for a long time anymore, and there are some specifics in OsmoNITB when it comes to sysmobts. Let's have an example config file Change-Id: I94ae57c9a3cb497ca39d56270fa15ed65d7f147e --- A openbsc/doc/examples/osmo-nitb/sysmobts/openbsc.cfg 1 file changed, 77 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/39/639/1 diff --git a/openbsc/doc/examples/osmo-nitb/sysmobts/openbsc.cfg b/openbsc/doc/examples/osmo-nitb/sysmobts/openbsc.cfg new file mode 100644 index 0000000..7c078f6 --- /dev/null +++ b/openbsc/doc/examples/osmo-nitb/sysmobts/openbsc.cfg @@ -0,0 +1,77 @@ +! +! OpenBSC configuration saved from vty +! ! +password foo +! +line vty + no login +! +e1_input + e1_line 0 driver ipa +network + network country code 1 + mobile network code 1 + short name OpenBSC + long name OpenBSC + auth policy closed + location updating reject cause 13 + encryption a5 0 + neci 1 + rrlp mode none + mm info 1 + handover 0 + handover window rxlev averaging 10 + handover window rxqual averaging 1 + handover window rxlev neighbor averaging 10 + handover power budget interval 6 + handover power budget hysteresis 3 + handover maximum distance 9999 + timer t3101 10 + timer t3103 0 + timer t3105 0 + timer t3107 0 + timer t3109 4 + timer t3111 0 + timer t3113 60 + timer t3115 0 + timer t3117 0 + timer t3119 0 + timer t3141 0 + bts 0 + type sysmobts + band DCS1800 + cell_identity 0 + location_area_code 1 + training_sequence_code 7 + base_station_id_code 63 + ms max power 15 + cell reselection hysteresis 4 + rxlev access min 0 + channel allocator ascending + rach tx integer 9 + rach max transmission 7 + ip.access unit_id 1801 0 + oml ip.access stream_id 255 line 0 + gprs mode none + trx 0 + rf_locked 0 + arfcn 514 + nominal power 23 + max_power_red 20 + rsl e1 tei 0 + timeslot 0 + phys_chan_config CCCH+SDCCH4 + timeslot 1 + phys_chan_config SDCCH8 + timeslot 2 + phys_chan_config TCH/F + timeslot 3 + phys_chan_config TCH/F + timeslot 4 + phys_chan_config TCH/F + timeslot 5 + phys_chan_config TCH/F + timeslot 6 + phys_chan_config TCH/F + timeslot 7 + phys_chan_config TCH/F -- To view, visit https://gerrit.osmocom.org/639 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I94ae57c9a3cb497ca39d56270fa15ed65d7f147e Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Harald Welte From gerrit-no-reply at lists.osmocom.org Mon Aug 1 12:32:02 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 1 Aug 2016 12:32:02 +0000 Subject: openbsc[master]: add example config for sysmobts In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/639 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I94ae57c9a3cb497ca39d56270fa15ed65d7f147e Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Harald Welte Gerrit-Reviewer: Harald Welte Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 1 12:49:35 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Mon, 1 Aug 2016 12:49:35 +0000 Subject: [PATCH] openbsc[master]: Use random operation id Message-ID: Review at https://gerrit.osmocom.org/640 Use random operation id According to documentation for Control Interface Protocol is "A numeric identifier, uniquely identifying this particular operation", hence it's best to be illustrated with random integer instead of previously used python-specific objects' id which only creates unnecessary confusion between 2 completely unrelated things. Change-Id: I87d9ee0e9a87f58702c60bb141c973d41fa06997 Related: OS#1646 --- M openbsc/contrib/bsc_control.py 1 file changed, 8 insertions(+), 7 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/40/640/1 diff --git a/openbsc/contrib/bsc_control.py b/openbsc/contrib/bsc_control.py index 26a421d..dd5d7e9 100755 --- a/openbsc/contrib/bsc_control.py +++ b/openbsc/contrib/bsc_control.py @@ -1,6 +1,6 @@ #!/usr/bin/python -import sys,os +import sys,os, random from optparse import OptionParser import socket import struct @@ -36,12 +36,12 @@ data = prefix_ipa_ctrl_header(data) sck.send(data) -def do_set(var, value, id, sck): - setmsg = "SET %s %s %s" %(options.id, var, value) +def do_set(var, value, op_id, sck): + setmsg = "SET %s %s %s" %(op_id, var, value) send(sck, setmsg) -def do_get(var, id, sck): - getmsg = "GET %s %s" %(options.id, var) +def do_get(var, op_id, sck): + getmsg = "GET %s %s" %(op_id, var) send(sck, getmsg) if __name__ == '__main__': @@ -64,6 +64,7 @@ (options, args) = parser.parse_args() verbose = options.verbose + random.seed() if options.cmd_set and options.cmd_get: parser.error("Get and set options are mutually exclusive!") @@ -79,12 +80,12 @@ if options.cmd_set: if len(args) < 2: parser.error("Set requires var and value arguments") - do_set(args[0], ' '.join(args[1:]), options.id, sock) + do_set(args[0], ' '.join(args[1:]), random.randint(1, sys.maxint), sock) if options.cmd_get: if len(args) != 1: parser.error("Get requires the var argument") - do_get(args[0], options.id, sock) + do_get(args[0], random.randint(1, sys.maxint), sock) data = sock.recv(1024) while (len(data)>0): -- To view, visit https://gerrit.osmocom.org/640 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I87d9ee0e9a87f58702c60bb141c973d41fa06997 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max From gerrit-no-reply at lists.osmocom.org Mon Aug 1 14:06:41 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Mon, 1 Aug 2016 14:06:41 +0000 Subject: [PATCH] openbsc[master]: Added slhc code from kernel.org. In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/634 to look at the new patch set (#2). Added slhc code from kernel.org. Slhc is an Implementation of RFC1144 TCP/IP header compression. We will need RFC1144 compression to compress GPRS TCP/IP traffic. The implementation pushed with this commit was taken from git://git.kernel.org/pub/scm/linux/kernel/git/wtarreau/linux-2.4.git commit e294a2074f0059de7c69b30fe3048fe61f971b83 Change-Id: Ied69c143678dc4a64cecc671f5c4dfebe19d8519 --- A openbsc/include/openbsc/slhc_vj.h A openbsc/src/gprs/slhc.c 2 files changed, 991 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/34/634/2 diff --git a/openbsc/include/openbsc/slhc_vj.h b/openbsc/include/openbsc/slhc_vj.h new file mode 100644 index 0000000..0a85dc0 --- /dev/null +++ b/openbsc/include/openbsc/slhc_vj.h @@ -0,0 +1,191 @@ +#ifndef _SLHC_H +#define _SLHC_H +/* + * Definitions for tcp compression routines. + * + * $Header: slcompress.h,v 1.10 89/12/31 08:53:02 van Exp $ + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van at helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + * + * + * modified for KA9Q Internet Software Package by + * Katie Stevens (dkstevens at ucdavis.edu) + * University of California, Davis + * Computing Services + * - 01-31-90 initial adaptation + * + * - Feb 1991 Bill_Simpson at um.cc.umich.edu + * variable number of conversation slots + * allow zero or one slots + * separate routines + * status display + */ + +/* + * Compressed packet format: + * + * The first octet contains the packet type (top 3 bits), TCP + * 'push' bit, and flags that indicate which of the 4 TCP sequence + * numbers have changed (bottom 5 bits). The next octet is a + * conversation number that associates a saved IP/TCP header with + * the compressed packet. The next two octets are the TCP checksum + * from the original datagram. The next 0 to 15 octets are + * sequence number changes, one change per bit set in the header + * (there may be no changes and there are two special cases where + * the receiver implicitly knows what changed -- see below). + * + * There are 5 numbers which can change (they are always inserted + * in the following order): TCP urgent pointer, window, + * acknowledgment, sequence number and IP ID. (The urgent pointer + * is different from the others in that its value is sent, not the + * change in value.) Since typical use of SLIP links is biased + * toward small packets (see comments on MTU/MSS below), changes + * use a variable length coding with one octet for numbers in the + * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the + * range 256 - 65535 or 0. (If the change in sequence number or + * ack is more than 65535, an uncompressed packet is sent.) + */ + +/* + * Packet types (must not conflict with IP protocol version) + * + * The top nibble of the first octet is the packet type. There are + * three possible types: IP (not proto TCP or tcp with one of the + * control flags set); uncompressed TCP (a normal IP/TCP packet but + * with the 8-bit protocol field replaced by an 8-bit connection id -- + * this type of packet syncs the sender & receiver); and compressed + * TCP (described above). + * + * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and + * is logically part of the 4-bit "changes" field that follows. Top + * three bits are actual packet type. For backward compatibility + * and in the interest of conserving bits, numbers are chosen so the + * IP protocol version number (4) which normally appears in this nibble + * means "IP packet". + */ + + +#include +#include + +/* SLIP compression masks for len/vers byte */ +#define SL_TYPE_IP 0x40 +#define SL_TYPE_UNCOMPRESSED_TCP 0x70 +#define SL_TYPE_COMPRESSED_TCP 0x80 +#define SL_TYPE_ERROR 0x00 + +/* Bits in first octet of compressed packet */ +#define NEW_C 0x40 /* flag bits for what changed in a packet */ +#define NEW_I 0x20 +#define NEW_S 0x08 +#define NEW_A 0x04 +#define NEW_W 0x02 +#define NEW_U 0x01 + +/* reserved, special-case values of above */ +#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */ +#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */ +#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U) + +#define TCP_PUSH_BIT 0x10 + +/* + * data type and sizes conversion assumptions: + * + * VJ code KA9Q style generic + * u_char byte_t unsigned char 8 bits + * u_short int16 unsigned short 16 bits + * u_int int16 unsigned short 16 bits + * u_long unsigned long unsigned long 32 bits + * int int32 long 32 bits + */ + +typedef __u8 byte_t; +typedef __u32 int32; + +/* + * "state" data for each active tcp conversation on the wire. This is + * basically a copy of the entire IP/TCP header from the last packet + * we saw from the conversation together with a small identifier + * the transmit & receive ends of the line use to locate saved header. + */ +struct cstate { + byte_t cs_this; /* connection id number (xmit) */ + struct cstate *next; /* next in ring (xmit) */ + struct iphdr cs_ip; /* ip/tcp hdr from most recent packet */ + struct tcphdr cs_tcp; + unsigned char cs_ipopt[64]; + unsigned char cs_tcpopt[64]; + int cs_hsize; +}; +#define NULLSLSTATE (struct cstate *)0 + +/* + * all the state data for one serial line (we need one of these per line). + */ +struct slcompress { + struct cstate *tstate; /* transmit connection states (array)*/ + struct cstate *rstate; /* receive connection states (array)*/ + + byte_t tslot_limit; /* highest transmit slot id (0-l)*/ + byte_t rslot_limit; /* highest receive slot id (0-l)*/ + + byte_t xmit_oldest; /* oldest xmit in ring */ + byte_t xmit_current; /* most recent xmit id */ + byte_t recv_current; /* most recent rcvd id */ + + byte_t flags; +#define SLF_TOSS 0x01 /* tossing rcvd frames until id received */ + + int32 sls_o_nontcp; /* outbound non-TCP packets */ + int32 sls_o_tcp; /* outbound TCP packets */ + int32 sls_o_uncompressed; /* outbound uncompressed packets */ + int32 sls_o_compressed; /* outbound compressed packets */ + int32 sls_o_searches; /* searches for connection state */ + int32 sls_o_misses; /* times couldn't find conn. state */ + + int32 sls_i_uncompressed; /* inbound uncompressed packets */ + int32 sls_i_compressed; /* inbound compressed packets */ + int32 sls_i_error; /* inbound error packets */ + int32 sls_i_tossed; /* inbound packets tossed because of error */ + + int32 sls_i_runt; + int32 sls_i_badcheck; +}; +#define NULLSLCOMPR (struct slcompress *)0 + +#define __ARGS(x) x + +/* In slhc.c: */ +struct slcompress *slhc_init __ARGS((int rslots, int tslots)); +void slhc_free __ARGS((struct slcompress *comp)); + +int slhc_compress __ARGS((struct slcompress *comp, unsigned char *icp, + int isize, unsigned char *ocp, unsigned char **cpp, + int compress_cid)); +int slhc_uncompress __ARGS((struct slcompress *comp, unsigned char *icp, + int isize)); +int slhc_remember __ARGS((struct slcompress *comp, unsigned char *icp, + int isize)); +int slhc_toss __ARGS((struct slcompress *comp)); + +void slhc_i_status __ARGS((struct slcompress *comp)); +void slhc_o_status __ARGS((struct slcompress *comp)); + +#endif /* _SLHC_H */ diff --git a/openbsc/src/gprs/slhc.c b/openbsc/src/gprs/slhc.c new file mode 100644 index 0000000..b1a855c --- /dev/null +++ b/openbsc/src/gprs/slhc.c @@ -0,0 +1,800 @@ +/* + * Routines to compress and uncompress tcp packets (for transmission + * over low speed serial lines). + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van at helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + * + * + * modified for KA9Q Internet Software Package by + * Katie Stevens (dkstevens at ucdavis.edu) + * University of California, Davis + * Computing Services + * - 01-31-90 initial adaptation (from 1.19) + * PPP.05 02-15-90 [ks] + * PPP.08 05-02-90 [ks] use PPP protocol field to signal compression + * PPP.15 09-90 [ks] improve mbuf handling + * PPP.16 11-02 [karn] substantially rewritten to use NOS facilities + * + * - Feb 1991 Bill_Simpson at um.cc.umich.edu + * variable number of conversation slots + * allow zero or one slots + * separate routines + * status display + * - Jul 1994 Dmitry Gorodchanin + * Fixes for memory leaks. + * - Oct 1994 Dmitry Gorodchanin + * Modularization. + * - Jan 1995 Bjorn Ekwall + * Use ip_fast_csum from ip.h + * - July 1995 Christos A. Polyzols + * Spotted bug in tcp option checking + * + * + * This module is a difficult issue. It's clearly inet code but it's also clearly + * driver code belonging close to PPP and SLIP + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_INET +/* Entire module is for IP only */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned char *encode(unsigned char *cp, unsigned short n); +static long decode(unsigned char **cpp); +static unsigned char * put16(unsigned char *cp, unsigned short x); +static unsigned short pull16(unsigned char **cpp); + +/* Initialize compression data structure + * slots must be in range 0 to 255 (zero meaning no compression) + */ +struct slcompress * +slhc_init(int rslots, int tslots) +{ + register short i; + register struct cstate *ts; + struct slcompress *comp; + + MOD_INC_USE_COUNT; + comp = (struct slcompress *)kmalloc(sizeof(struct slcompress), + GFP_KERNEL); + if (! comp) + goto out_fail; + memset(comp, 0, sizeof(struct slcompress)); + + if ( rslots > 0 && rslots < 256 ) { + size_t rsize = rslots * sizeof(struct cstate); + comp->rstate = (struct cstate *) kmalloc(rsize, GFP_KERNEL); + if (! comp->rstate) + goto out_free; + memset(comp->rstate, 0, rsize); + comp->rslot_limit = rslots - 1; + } + + if ( tslots > 0 && tslots < 256 ) { + size_t tsize = tslots * sizeof(struct cstate); + comp->tstate = (struct cstate *) kmalloc(tsize, GFP_KERNEL); + if (! comp->tstate) + goto out_free2; + memset(comp->tstate, 0, tsize); + comp->tslot_limit = tslots - 1; + } + + comp->xmit_oldest = 0; + comp->xmit_current = 255; + comp->recv_current = 255; + /* + * don't accept any packets with implicit index until we get + * one with an explicit index. Otherwise the uncompress code + * will try to use connection 255, which is almost certainly + * out of range + */ + comp->flags |= SLF_TOSS; + + if ( tslots > 0 ) { + ts = comp->tstate; + for(i = comp->tslot_limit; i > 0; --i){ + ts[i].cs_this = i; + ts[i].next = &(ts[i - 1]); + } + ts[0].next = &(ts[comp->tslot_limit]); + ts[0].cs_this = 0; + } + return comp; + +out_free2: + kfree((unsigned char *)comp->rstate); +out_free: + kfree((unsigned char *)comp); +out_fail: + MOD_DEC_USE_COUNT; + return NULL; +} + + +/* Free a compression data structure */ +void +slhc_free(struct slcompress *comp) +{ + if ( comp == NULLSLCOMPR ) + return; + + if ( comp->tstate != NULLSLSTATE ) + kfree( comp->tstate ); + + if ( comp->rstate != NULLSLSTATE ) + kfree( comp->rstate ); + + kfree( comp ); + MOD_DEC_USE_COUNT; +} + + +/* Put a short in host order into a char array in network order */ +static inline unsigned char * +put16(unsigned char *cp, unsigned short x) +{ + *cp++ = x >> 8; + *cp++ = x; + + return cp; +} + + +/* Encode a number */ +unsigned char * +encode(unsigned char *cp, unsigned short n) +{ + if(n >= 256 || n == 0){ + *cp++ = 0; + cp = put16(cp,n); + } else { + *cp++ = n; + } + return cp; +} + +/* Pull a 16-bit integer in host order from buffer in network byte order */ +static unsigned short +pull16(unsigned char **cpp) +{ + short rval; + + rval = *(*cpp)++; + rval <<= 8; + rval |= *(*cpp)++; + return rval; +} + +/* Decode a number */ +long +decode(unsigned char **cpp) +{ + register int x; + + x = *(*cpp)++; + if(x == 0){ + return pull16(cpp) & 0xffff; /* pull16 returns -1 on error */ + } else { + return x & 0xff; /* -1 if PULLCHAR returned error */ + } +} + +/* + * icp and isize are the original packet. + * ocp is a place to put a copy if necessary. + * cpp is initially a pointer to icp. If the copy is used, + * change it to ocp. + */ + +int +slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, + unsigned char *ocp, unsigned char **cpp, int compress_cid) +{ + register struct cstate *ocs = &(comp->tstate[comp->xmit_oldest]); + register struct cstate *lcs = ocs; + register struct cstate *cs = lcs->next; + register unsigned long deltaS, deltaA; + register short changes = 0; + int hlen; + unsigned char new_seq[16]; + register unsigned char *cp = new_seq; + struct iphdr *ip; + struct tcphdr *th, *oth; + + + /* + * Don't play with runt packets. + */ + + if(isizeprotocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x3fff)) { + /* Send as regular IP */ + if(ip->protocol != IPPROTO_TCP) + comp->sls_o_nontcp++; + else + comp->sls_o_tcp++; + return isize; + } + /* Extract TCP header */ + + th = (struct tcphdr *)(((unsigned char *)ip) + ip->ihl*4); + hlen = ip->ihl*4 + th->doff*4; + + /* Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or + * some other control bit is set). Also uncompressible if + * its a runt. + */ + if(hlen > isize || th->syn || th->fin || th->rst || + ! (th->ack)){ + /* TCP connection stuff; send as regular IP */ + comp->sls_o_tcp++; + return isize; + } + /* + * Packet is compressible -- we're going to send either a + * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way, + * we need to locate (or create) the connection state. + * + * States are kept in a circularly linked list with + * xmit_oldest pointing to the end of the list. The + * list is kept in lru order by moving a state to the + * head of the list whenever it is referenced. Since + * the list is short and, empirically, the connection + * we want is almost always near the front, we locate + * states via linear search. If we don't find a state + * for the datagram, the oldest state is (re-)used. + */ + for ( ; ; ) { + if( ip->saddr == cs->cs_ip.saddr + && ip->daddr == cs->cs_ip.daddr + && th->source == cs->cs_tcp.source + && th->dest == cs->cs_tcp.dest) + goto found; + + /* if current equal oldest, at end of list */ + if ( cs == ocs ) + break; + lcs = cs; + cs = cs->next; + comp->sls_o_searches++; + }; + /* + * Didn't find it -- re-use oldest cstate. Send an + * uncompressed packet that tells the other side what + * connection number we're using for this conversation. + * + * Note that since the state list is circular, the oldest + * state points to the newest and we only need to set + * xmit_oldest to update the lru linkage. + */ + comp->sls_o_misses++; + comp->xmit_oldest = lcs->cs_this; + goto uncompressed; + +found: + /* + * Found it -- move to the front on the connection list. + */ + if(lcs == ocs) { + /* found at most recently used */ + } else if (cs == ocs) { + /* found at least recently used */ + comp->xmit_oldest = lcs->cs_this; + } else { + /* more than 2 elements */ + lcs->next = cs->next; + cs->next = ocs->next; + ocs->next = cs; + } + + /* + * Make sure that only what we expect to change changed. + * Check the following: + * IP protocol version, header length & type of service. + * The "Don't fragment" bit. + * The time-to-live field. + * The TCP header length. + * IP options, if any. + * TCP options, if any. + * If any of these things are different between the previous & + * current datagram, we send the current datagram `uncompressed'. + */ + oth = &cs->cs_tcp; + + if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl + || ip->tos != cs->cs_ip.tos + || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000)) + || ip->ttl != cs->cs_ip.ttl + || th->doff != cs->cs_tcp.doff + || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) + || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){ + goto uncompressed; + } + + /* + * Figure out which of the changing fields changed. The + * receiver expects changes in the order: urgent, window, + * ack, seq (the order minimizes the number of temporaries + * needed in this section of code). + */ + if(th->urg){ + deltaS = ntohs(th->urg_ptr); + cp = encode(cp,deltaS); + changes |= NEW_U; + } else if(th->urg_ptr != oth->urg_ptr){ + /* argh! URG not set but urp changed -- a sensible + * implementation should never do this but RFC793 + * doesn't prohibit the change so we have to deal + * with it. */ + goto uncompressed; + } + if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){ + cp = encode(cp,deltaS); + changes |= NEW_W; + } + if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){ + if(deltaA > 0x0000ffff) + goto uncompressed; + cp = encode(cp,deltaA); + changes |= NEW_A; + } + if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){ + if(deltaS > 0x0000ffff) + goto uncompressed; + cp = encode(cp,deltaS); + changes |= NEW_S; + } + + switch(changes){ + case 0: /* Nothing changed. If this packet contains data and the + * last one didn't, this is probably a data packet following + * an ack (normal on an interactive connection) and we send + * it compressed. Otherwise it's probably a retransmit, + * retransmitted ack or window probe. Send it uncompressed + * in case the other side missed the compressed version. + */ + if(ip->tot_len != cs->cs_ip.tot_len && + ntohs(cs->cs_ip.tot_len) == hlen) + break; + goto uncompressed; + break; + case SPECIAL_I: + case SPECIAL_D: + /* actual changes match one of our special case encodings -- + * send packet uncompressed. + */ + goto uncompressed; + case NEW_S|NEW_A: + if(deltaS == deltaA && + deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ + /* special case for echoed terminal traffic */ + changes = SPECIAL_I; + cp = new_seq; + } + break; + case NEW_S: + if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ + /* special case for data xfer */ + changes = SPECIAL_D; + cp = new_seq; + } + break; + } + deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id); + if(deltaS != 1){ + cp = encode(cp,deltaS); + changes |= NEW_I; + } + if(th->psh) + changes |= TCP_PUSH_BIT; + /* Grab the cksum before we overwrite it below. Then update our + * state with this packet's header. + */ + deltaA = ntohs(th->check); + memcpy(&cs->cs_ip,ip,20); + memcpy(&cs->cs_tcp,th,20); + /* We want to use the original packet as our compressed packet. + * (cp - new_seq) is the number of bytes we need for compressed + * sequence numbers. In addition we need one byte for the change + * mask, one for the connection id and two for the tcp checksum. + * So, (cp - new_seq) + 4 bytes of header are needed. + */ + deltaS = cp - new_seq; + if(compress_cid == 0 || comp->xmit_current != cs->cs_this){ + cp = ocp; + *cpp = ocp; + *cp++ = changes | NEW_C; + *cp++ = cs->cs_this; + comp->xmit_current = cs->cs_this; + } else { + cp = ocp; + *cpp = ocp; + *cp++ = changes; + } + cp = put16(cp,(short)deltaA); /* Write TCP checksum */ +/* deltaS is now the size of the change section of the compressed header */ + memcpy(cp,new_seq,deltaS); /* Write list of deltas */ + memcpy(cp+deltaS,icp+hlen,isize-hlen); + comp->sls_o_compressed++; + ocp[0] |= SL_TYPE_COMPRESSED_TCP; + return isize - hlen + deltaS + (cp - ocp); + + /* Update connection state cs & send uncompressed packet (i.e., + * a regular ip/tcp packet but with the 'conversation id' we hope + * to use on future compressed packets in the protocol field). + */ +uncompressed: + memcpy(&cs->cs_ip,ip,20); + memcpy(&cs->cs_tcp,th,20); + if (ip->ihl > 5) + memcpy(cs->cs_ipopt, ip+1, ((ip->ihl) - 5) * 4); + if (th->doff > 5) + memcpy(cs->cs_tcpopt, th+1, ((th->doff) - 5) * 4); + comp->xmit_current = cs->cs_this; + comp->sls_o_uncompressed++; + memcpy(ocp, icp, isize); + *cpp = ocp; + ocp[9] = cs->cs_this; + ocp[0] |= SL_TYPE_UNCOMPRESSED_TCP; + return isize; +} + + +int +slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) +{ + register int changes; + long x; + register struct tcphdr *thp; + register struct iphdr *ip; + register struct cstate *cs; + int len, hdrlen; + unsigned char *cp = icp; + + /* We've got a compressed packet; read the change byte */ + comp->sls_i_compressed++; + if(isize < 3){ + comp->sls_i_error++; + return 0; + } + changes = *cp++; + if(changes & NEW_C){ + /* Make sure the state index is in range, then grab the state. + * If we have a good state index, clear the 'discard' flag. + */ + x = *cp++; /* Read conn index */ + if(x < 0 || x > comp->rslot_limit) + goto bad; + + comp->flags &=~ SLF_TOSS; + comp->recv_current = x; + } else { + /* this packet has an implicit state index. If we've + * had a line error since the last time we got an + * explicit state index, we have to toss the packet. */ + if(comp->flags & SLF_TOSS){ + comp->sls_i_tossed++; + return 0; + } + } + cs = &comp->rstate[comp->recv_current]; + thp = &cs->cs_tcp; + ip = &cs->cs_ip; + + if((x = pull16(&cp)) == -1) { /* Read the TCP checksum */ + goto bad; + } + thp->check = htons(x); + + thp->psh = (changes & TCP_PUSH_BIT) ? 1 : 0; +/* + * we can use the same number for the length of the saved header and + * the current one, because the packet wouldn't have been sent + * as compressed unless the options were the same as the previous one + */ + + hdrlen = ip->ihl * 4 + thp->doff * 4; + + switch(changes & SPECIALS_MASK){ + case SPECIAL_I: /* Echoed terminal traffic */ + { + register short i; + i = ntohs(ip->tot_len) - hdrlen; + thp->ack_seq = htonl( ntohl(thp->ack_seq) + i); + thp->seq = htonl( ntohl(thp->seq) + i); + } + break; + + case SPECIAL_D: /* Unidirectional data */ + thp->seq = htonl( ntohl(thp->seq) + + ntohs(ip->tot_len) - hdrlen); + break; + + default: + if(changes & NEW_U){ + thp->urg = 1; + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->urg_ptr = htons(x); + } else + thp->urg = 0; + if(changes & NEW_W){ + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->window = htons( ntohs(thp->window) + x); + } + if(changes & NEW_A){ + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->ack_seq = htonl( ntohl(thp->ack_seq) + x); + } + if(changes & NEW_S){ + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->seq = htonl( ntohl(thp->seq) + x); + } + break; + } + if(changes & NEW_I){ + if((x = decode(&cp)) == -1) { + goto bad; + } + ip->id = htons (ntohs (ip->id) + x); + } else + ip->id = htons (ntohs (ip->id) + 1); + + /* + * At this point, cp points to the first byte of data in the + * packet. Put the reconstructed TCP and IP headers back on the + * packet. Recalculate IP checksum (but not TCP checksum). + */ + + len = isize - (cp - icp); + if (len < 0) + goto bad; + len += hdrlen; + ip->tot_len = htons(len); + ip->check = 0; + + memmove(icp + hdrlen, cp, len - hdrlen); + + cp = icp; + memcpy(cp, ip, 20); + cp += 20; + + if (ip->ihl > 5) { + memcpy(cp, cs->cs_ipopt, (ip->ihl - 5) * 4); + cp += (ip->ihl - 5) * 4; + } + + put_unaligned(ip_fast_csum(icp, ip->ihl), + &((struct iphdr *)icp)->check); + + memcpy(cp, thp, 20); + cp += 20; + + if (thp->doff > 5) { + memcpy(cp, cs->cs_tcpopt, ((thp->doff) - 5) * 4); + cp += ((thp->doff) - 5) * 4; + } + + return len; +bad: + comp->sls_i_error++; + return slhc_toss( comp ); +} + + +int +slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +{ + register struct cstate *cs; + unsigned ihl; + + unsigned char index; + + if(isize < 20) { + /* The packet is shorter than a legal IP header */ + comp->sls_i_runt++; + return slhc_toss( comp ); + } + /* Peek at the IP header's IHL field to find its length */ + ihl = icp[0] & 0xf; + if(ihl < 20 / 4){ + /* The IP header length field is too small */ + comp->sls_i_runt++; + return slhc_toss( comp ); + } + index = icp[9]; + icp[9] = IPPROTO_TCP; + + if (ip_fast_csum(icp, ihl)) { + /* Bad IP header checksum; discard */ + comp->sls_i_badcheck++; + return slhc_toss( comp ); + } + if(index > comp->rslot_limit) { + comp->sls_i_error++; + return slhc_toss(comp); + } + + /* Update local state */ + cs = &comp->rstate[comp->recv_current = index]; + comp->flags &=~ SLF_TOSS; + memcpy(&cs->cs_ip,icp,20); + memcpy(&cs->cs_tcp,icp + ihl*4,20); + if (ihl > 5) + memcpy(cs->cs_ipopt, icp + sizeof(struct iphdr), (ihl - 5) * 4); + if (cs->cs_tcp.doff > 5) + memcpy(cs->cs_tcpopt, icp + ihl*4 + sizeof(struct tcphdr), (cs->cs_tcp.doff - 5) * 4); + cs->cs_hsize = ihl*2 + cs->cs_tcp.doff*2; + /* Put headers back on packet + * Neither header checksum is recalculated + */ + comp->sls_i_uncompressed++; + return isize; +} + + +int +slhc_toss(struct slcompress *comp) +{ + if ( comp == NULLSLCOMPR ) + return 0; + + comp->flags |= SLF_TOSS; + return 0; +} + + +void slhc_i_status(struct slcompress *comp) +{ + if (comp != NULLSLCOMPR) { + printk("\t%d Cmp, %d Uncmp, %d Bad, %d Tossed\n", + comp->sls_i_compressed, + comp->sls_i_uncompressed, + comp->sls_i_error, + comp->sls_i_tossed); + } +} + + +void slhc_o_status(struct slcompress *comp) +{ + if (comp != NULLSLCOMPR) { + printk("\t%d Cmp, %d Uncmp, %d AsIs, %d NotTCP\n", + comp->sls_o_compressed, + comp->sls_o_uncompressed, + comp->sls_o_tcp, + comp->sls_o_nontcp); + printk("\t%10d Searches, %10d Misses\n", + comp->sls_o_searches, + comp->sls_o_misses); + } +} + +/* Should this be surrounded with "#ifdef CONFIG_MODULES" ? */ +/* VJ header compression */ +EXPORT_SYMBOL(slhc_init); +EXPORT_SYMBOL(slhc_free); +EXPORT_SYMBOL(slhc_remember); +EXPORT_SYMBOL(slhc_compress); +EXPORT_SYMBOL(slhc_uncompress); +EXPORT_SYMBOL(slhc_toss); + +#ifdef MODULE + +int init_module(void) +{ + printk(KERN_INFO "CSLIP: code copyright 1989 Regents of the University of California\n"); + return 0; +} + +void cleanup_module(void) +{ + return; +} + +#endif /* MODULE */ +#else /* CONFIG_INET */ + + +int +slhc_toss(struct slcompress *comp) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss"); + return -EINVAL; +} +int +slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress"); + return -EINVAL; +} +int +slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, + unsigned char *ocp, unsigned char **cpp, int compress_cid) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress"); + return -EINVAL; +} + +int +slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember"); + return -EINVAL; +} + +void +slhc_free(struct slcompress *comp) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free"); + return; +} +struct slcompress * +slhc_init(int rslots, int tslots) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init"); + return NULL; +} +EXPORT_SYMBOL(slhc_init); +EXPORT_SYMBOL(slhc_free); +EXPORT_SYMBOL(slhc_remember); +EXPORT_SYMBOL(slhc_compress); +EXPORT_SYMBOL(slhc_uncompress); +EXPORT_SYMBOL(slhc_toss); + +#endif /* CONFIG_INET */ +MODULE_LICENSE("Dual BSD/GPL"); -- To view, visit https://gerrit.osmocom.org/634 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ied69c143678dc4a64cecc671f5c4dfebe19d8519 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 1 14:06:41 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Mon, 1 Aug 2016 14:06:41 +0000 Subject: [PATCH] openbsc[master]: Modifed version of slhc (RFC1144 implementation) In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/635 to look at the new patch set (#2). Modifed version of slhc (RFC1144 implementation) The previously pushed slhc implementation has been modified to compile and function outside of the kernel. Also debug log messages were added and datatypes ware matched. The implementation is now ready to be used Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 --- M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/debug.h R openbsc/include/openbsc/slhc.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/slhc.c 5 files changed, 128 insertions(+), 177 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/35/635/2 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index c272b14..9ef8a15 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,7 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h + gtphub.h gprs_sndcp.h slhc.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 43ebb19..90ddca5 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -29,6 +29,7 @@ DBSSGP, DLLC, DSNDCP, + DSLHC, DNAT, DCTRL, DSMPP, diff --git a/openbsc/include/openbsc/slhc_vj.h b/openbsc/include/openbsc/slhc.h similarity index 89% rename from openbsc/include/openbsc/slhc_vj.h rename to openbsc/include/openbsc/slhc.h index 0a85dc0..2e926dd 100644 --- a/openbsc/include/openbsc/slhc_vj.h +++ b/openbsc/include/openbsc/slhc.h @@ -80,7 +80,6 @@ * means "IP packet". */ - #include #include @@ -109,7 +108,7 @@ * data type and sizes conversion assumptions: * * VJ code KA9Q style generic - * u_char byte_t unsigned char 8 bits + * u_char byte_t uint8_t 8 bits * u_short int16 unsigned short 16 bits * u_int int16 unsigned short 16 bits * u_long unsigned long unsigned long 32 bits @@ -130,8 +129,8 @@ struct cstate *next; /* next in ring (xmit) */ struct iphdr cs_ip; /* ip/tcp hdr from most recent packet */ struct tcphdr cs_tcp; - unsigned char cs_ipopt[64]; - unsigned char cs_tcpopt[64]; + uint8_t cs_ipopt[64]; + uint8_t cs_tcpopt[64]; int cs_hsize; }; #define NULLSLSTATE (struct cstate *)0 @@ -173,19 +172,16 @@ #define __ARGS(x) x /* In slhc.c: */ -struct slcompress *slhc_init __ARGS((int rslots, int tslots)); -void slhc_free __ARGS((struct slcompress *comp)); +struct slcompress *slhc_init(int rslots, int tslots); -int slhc_compress __ARGS((struct slcompress *comp, unsigned char *icp, - int isize, unsigned char *ocp, unsigned char **cpp, - int compress_cid)); -int slhc_uncompress __ARGS((struct slcompress *comp, unsigned char *icp, - int isize)); -int slhc_remember __ARGS((struct slcompress *comp, unsigned char *icp, - int isize)); -int slhc_toss __ARGS((struct slcompress *comp)); +void slhc_free(struct slcompress *comp); -void slhc_i_status __ARGS((struct slcompress *comp)); -void slhc_o_status __ARGS((struct slcompress *comp)); +int slhc_compress(struct slcompress *comp, uint8_t *icp, int isize, uint8_t *ocp, uint8_t **cpp, int compress_cid); +int slhc_uncompress(struct slcompress *comp, uint8_t *icp, int isize); +int slhc_remember(struct slcompress *comp, uint8_t *icp, int isize); +int slhc_toss(struct slcompress *comp); + +void slhc_i_status(struct slcompress *comp); +void slhc_o_status(struct slcompress *comp); #endif /* _SLHC_H */ diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 6dc7e16..548b38c 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -23,6 +23,7 @@ $(OSMO_LIBS) $(LIBCRYPTO_LIBS) -lrt osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \ + slhc.c \ sgsn_main.c sgsn_vty.c sgsn_libgtp.c \ gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c crc24.c \ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ diff --git a/openbsc/src/gprs/slhc.c b/openbsc/src/gprs/slhc.c index b1a855c..b201ddb 100644 --- a/openbsc/src/gprs/slhc.c +++ b/openbsc/src/gprs/slhc.c @@ -50,62 +50,71 @@ * driver code belonging close to PPP and SLIP */ -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#ifdef CONFIG_INET -/* Entire module is for IP only */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +static uint8_t *encode(uint8_t *cp, uint16_t n); +static long decode(uint8_t **cpp); +static uint8_t * put16(uint8_t *cp, uint16_t x); +static uint16_t pull16(uint8_t **cpp); -static unsigned char *encode(unsigned char *cp, unsigned short n); -static long decode(unsigned char **cpp); -static unsigned char * put16(unsigned char *cp, unsigned short x); -static unsigned short pull16(unsigned char **cpp); + +/* Replacement for kernel space function ip_fast_csum() */ +static uint16_t ip_fast_csum(uint8_t *iph, int ihl) +{ + int i; + uint16_t temp; + uint32_t accumulator = 0xFFFF; + + for(i=0;i0xFFFF) + { + accumulator++; + accumulator&=0xFFFF; + } + } + + return (uint16_t)(htons(~accumulator)&0xFFFF); +} + +/* Replacement for kernel space function put_unaligned() */ +static void put_unaligned(uint16_t val, void *ptr) +{ + memcpy(ptr,&val,sizeof(val)); +} + /* Initialize compression data structure * slots must be in range 0 to 255 (zero meaning no compression) */ -struct slcompress * -slhc_init(int rslots, int tslots) +struct slcompress *slhc_init(int rslots, int tslots) { register short i; register struct cstate *ts; struct slcompress *comp; - MOD_INC_USE_COUNT; - comp = (struct slcompress *)kmalloc(sizeof(struct slcompress), - GFP_KERNEL); + comp = (struct slcompress *)talloc_zero_size(NULL,sizeof(struct slcompress)); if (! comp) goto out_fail; memset(comp, 0, sizeof(struct slcompress)); if ( rslots > 0 && rslots < 256 ) { size_t rsize = rslots * sizeof(struct cstate); - comp->rstate = (struct cstate *) kmalloc(rsize, GFP_KERNEL); + comp->rstate = (struct cstate *) talloc_zero_size(NULL, rsize); if (! comp->rstate) goto out_free; memset(comp->rstate, 0, rsize); @@ -114,7 +123,7 @@ if ( tslots > 0 && tslots < 256 ) { size_t tsize = tslots * sizeof(struct cstate); - comp->tstate = (struct cstate *) kmalloc(tsize, GFP_KERNEL); + comp->tstate = (struct cstate *) talloc_zero_size(NULL, tsize); if (! comp->tstate) goto out_free2; memset(comp->tstate, 0, tsize); @@ -144,36 +153,34 @@ return comp; out_free2: - kfree((unsigned char *)comp->rstate); + talloc_free((uint8_t *)comp->rstate); out_free: - kfree((unsigned char *)comp); + talloc_free((uint8_t *)comp); out_fail: - MOD_DEC_USE_COUNT; + + return NULL; } - /* Free a compression data structure */ -void -slhc_free(struct slcompress *comp) +void slhc_free(struct slcompress *comp) { + LOGP(DSLHC, LOGL_DEBUG, "slhc_free(): Freeing compression states...\n"); + if ( comp == NULLSLCOMPR ) return; if ( comp->tstate != NULLSLSTATE ) - kfree( comp->tstate ); + talloc_free(comp->tstate ); if ( comp->rstate != NULLSLSTATE ) - kfree( comp->rstate ); + talloc_free( comp->rstate ); - kfree( comp ); - MOD_DEC_USE_COUNT; + talloc_free( comp ); } - /* Put a short in host order into a char array in network order */ -static inline unsigned char * -put16(unsigned char *cp, unsigned short x) +static inline uint8_t *put16(uint8_t *cp, uint16_t x) { *cp++ = x >> 8; *cp++ = x; @@ -183,8 +190,7 @@ /* Encode a number */ -unsigned char * -encode(unsigned char *cp, unsigned short n) +uint8_t *encode(uint8_t *cp, uint16_t n) { if(n >= 256 || n == 0){ *cp++ = 0; @@ -196,8 +202,7 @@ } /* Pull a 16-bit integer in host order from buffer in network byte order */ -static unsigned short -pull16(unsigned char **cpp) +static uint16_t pull16(uint8_t **cpp) { short rval; @@ -208,8 +213,7 @@ } /* Decode a number */ -long -decode(unsigned char **cpp) +long decode(uint8_t **cpp) { register int x; @@ -228,9 +232,7 @@ * change it to ocp. */ -int -slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, - unsigned char *ocp, unsigned char **cpp, int compress_cid) +int slhc_compress(struct slcompress *comp, uint8_t *icp, int isize, uint8_t *ocp, uint8_t **cpp, int compress_cid) { register struct cstate *ocs = &(comp->tstate[comp->xmit_oldest]); register struct cstate *lcs = ocs; @@ -238,11 +240,10 @@ register unsigned long deltaS, deltaA; register short changes = 0; int hlen; - unsigned char new_seq[16]; - register unsigned char *cp = new_seq; + uint8_t new_seq[16]; + register uint8_t *cp = new_seq; struct iphdr *ip; struct tcphdr *th, *oth; - /* * Don't play with runt packets. @@ -260,11 +261,12 @@ comp->sls_o_nontcp++; else comp->sls_o_tcp++; + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Not a TCP packat, will not touch...\n"); return isize; } - /* Extract TCP header */ - th = (struct tcphdr *)(((unsigned char *)ip) + ip->ihl*4); + /* Extract TCP header */ + th = (struct tcphdr *)(((uint8_t *)ip) + ip->ihl*4); hlen = ip->ihl*4 + th->doff*4; /* Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or @@ -275,8 +277,10 @@ ! (th->ack)){ /* TCP connection stuff; send as regular IP */ comp->sls_o_tcp++; + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Packet is part of a TCP connection, will not touch...\n"); return isize; } + /* * Packet is compressible -- we're going to send either a * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way, @@ -291,6 +295,9 @@ * states via linear search. If we don't find a state * for the datagram, the oldest state is (re-)used. */ + + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Compressible packet detected!\n"); + for ( ; ; ) { if( ip->saddr == cs->cs_ip.saddr && ip->daddr == cs->cs_ip.daddr @@ -314,11 +321,14 @@ * state points to the newest and we only need to set * xmit_oldest to update the lru linkage. */ + + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Header not yet seen, will memorize header for the next turn...\n"); comp->sls_o_misses++; comp->xmit_oldest = lcs->cs_this; goto uncompressed; found: + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Header already seen, trying to compress...\n"); /* * Found it -- move to the front on the connection list. */ @@ -348,6 +358,7 @@ */ oth = &cs->cs_tcp; + if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl || ip->tos != cs->cs_ip.tos || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000)) @@ -355,6 +366,7 @@ || th->doff != cs->cs_tcp.doff || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){ + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): The header contains unexpected changes, can't compress...\n"); goto uncompressed; } @@ -373,6 +385,7 @@ * implementation should never do this but RFC793 * doesn't prohibit the change so we have to deal * with it. */ + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): URG not set but urp changed, can't compress...\n"); goto uncompressed; } if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){ @@ -381,13 +394,19 @@ } if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){ if(deltaA > 0x0000ffff) + { + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): (deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L, can't compress...\n"); goto uncompressed; + } cp = encode(cp,deltaA); changes |= NEW_A; } if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){ if(deltaS > 0x0000ffff) + { + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): (deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L, can't compress...\n"); goto uncompressed; + } cp = encode(cp,deltaS); changes |= NEW_S; } @@ -403,6 +422,7 @@ if(ip->tot_len != cs->cs_ip.tot_len && ntohs(cs->cs_ip.tot_len) == hlen) break; + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Retransmitted packet detected, can't compress...\n"); goto uncompressed; break; case SPECIAL_I: @@ -410,6 +430,7 @@ /* actual changes match one of our special case encodings -- * send packet uncompressed. */ + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Special case detected, can't compress...\n"); goto uncompressed; case NEW_S|NEW_A: if(deltaS == deltaA && @@ -438,7 +459,6 @@ * state with this packet's header. */ deltaA = ntohs(th->check); - memcpy(&cs->cs_ip,ip,20); memcpy(&cs->cs_tcp,th,20); /* We want to use the original packet as our compressed packet. * (cp - new_seq) is the number of bytes we need for compressed @@ -471,6 +491,7 @@ * to use on future compressed packets in the protocol field). */ uncompressed: + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Packet will be sent uncompressed...\n"); memcpy(&cs->cs_ip,ip,20); memcpy(&cs->cs_tcp,th,20); if (ip->ihl > 5) @@ -487,8 +508,7 @@ } -int -slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) +int slhc_uncompress(struct slcompress *comp, uint8_t *icp, int isize) { register int changes; long x; @@ -496,7 +516,7 @@ register struct iphdr *ip; register struct cstate *cs; int len, hdrlen; - unsigned char *cp = icp; + uint8_t *cp = icp; /* We've got a compressed packet; read the change byte */ comp->sls_i_compressed++; @@ -544,6 +564,8 @@ switch(changes & SPECIALS_MASK){ case SPECIAL_I: /* Echoed terminal traffic */ + LOGP(DSLHC, LOGL_DEBUG, "slhc_uncompress(): Echoed terminal traffic detected\n"); + { register short i; i = ntohs(ip->tot_len) - hdrlen; @@ -553,11 +575,13 @@ break; case SPECIAL_D: /* Unidirectional data */ + LOGP(DSLHC, LOGL_DEBUG, "slhc_uncompress(): Unidirectional data detected\n"); thp->seq = htonl( ntohl(thp->seq) + ntohs(ip->tot_len) - hdrlen); break; default: + LOGP(DSLHC, LOGL_DEBUG, "slhc_uncompress(): default packet type detected\n"); if(changes & NEW_U){ thp->urg = 1; if((x = decode(&cp)) == -1) { @@ -607,6 +631,7 @@ ip->tot_len = htons(len); ip->check = 0; + LOGP(DSLHC, LOGL_DEBUG, "slhc_uncompress(): making space for the reconstructed header...\n"); memmove(icp + hdrlen, cp, len - hdrlen); cp = icp; @@ -618,8 +643,7 @@ cp += (ip->ihl - 5) * 4; } - put_unaligned(ip_fast_csum(icp, ip->ihl), - &((struct iphdr *)icp)->check); + put_unaligned(ip_fast_csum(icp, ip->ihl), &((struct iphdr *)icp)->check); memcpy(cp, thp, 20); cp += 20; @@ -631,22 +655,24 @@ return len; bad: + LOGP(DSLHC, LOGL_DEBUG, "slhc_uncompress(): bad packet detected!\n"); comp->sls_i_error++; return slhc_toss( comp ); } -int -slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +int slhc_remember(struct slcompress *comp, uint8_t *icp, int isize) { register struct cstate *cs; unsigned ihl; - unsigned char index; + uint8_t index; + uint16_t checksum; if(isize < 20) { /* The packet is shorter than a legal IP header */ comp->sls_i_runt++; + LOGP(DSLHC, LOGL_DEBUG, "slhc_remember(): The packet is shorter than a legal IP header ==> slhc_toss()\n"); return slhc_toss( comp ); } /* Peek at the IP header's IHL field to find its length */ @@ -654,18 +680,23 @@ if(ihl < 20 / 4){ /* The IP header length field is too small */ comp->sls_i_runt++; + LOGP(DSLHC, LOGL_DEBUG, "slhc_remember(): The IP header length field is too small ==> slhc_toss()\n"); return slhc_toss( comp ); } + index = icp[9]; icp[9] = IPPROTO_TCP; + checksum = ip_fast_csum(icp, ihl); - if (ip_fast_csum(icp, ihl)) { + if (checksum) { /* Bad IP header checksum; discard */ comp->sls_i_badcheck++; + LOGP(DSLHC, LOGL_DEBUG, "slhc_remember(): Bad IP header checksum; discard ==> slhc_toss()\n"); return slhc_toss( comp ); } if(index > comp->rslot_limit) { comp->sls_i_error++; + LOGP(DSLHC, LOGL_DEBUG, "slhc_remember(): index > comp->rslot_limit ==> slhc_toss()\n"); return slhc_toss(comp); } @@ -686,10 +717,9 @@ return isize; } - -int -slhc_toss(struct slcompress *comp) +int slhc_toss(struct slcompress *comp) { + LOGP(DSLHC, LOGL_DEBUG, "slhc_toss(): Reset compression state...\n"); if ( comp == NULLSLCOMPR ) return 0; @@ -697,11 +727,10 @@ return 0; } - void slhc_i_status(struct slcompress *comp) { if (comp != NULLSLCOMPR) { - printk("\t%d Cmp, %d Uncmp, %d Bad, %d Tossed\n", + LOGP(DSLHC, LOGL_DEBUG, "slhc_i_status(): %d Cmp, %d Uncmp, %d Bad, %d Tossed\n", comp->sls_i_compressed, comp->sls_i_uncompressed, comp->sls_i_error, @@ -709,92 +738,16 @@ } } - void slhc_o_status(struct slcompress *comp) { if (comp != NULLSLCOMPR) { - printk("\t%d Cmp, %d Uncmp, %d AsIs, %d NotTCP\n", + LOGP(DSLHC, LOGL_DEBUG, "slhc_o_status(): %d Cmp, %d Uncmp, %d AsIs, %d NotTCP %d Searches, %d Misses\n", comp->sls_o_compressed, comp->sls_o_uncompressed, comp->sls_o_tcp, - comp->sls_o_nontcp); - printk("\t%10d Searches, %10d Misses\n", + comp->sls_o_nontcp, comp->sls_o_searches, comp->sls_o_misses); } } -/* Should this be surrounded with "#ifdef CONFIG_MODULES" ? */ -/* VJ header compression */ -EXPORT_SYMBOL(slhc_init); -EXPORT_SYMBOL(slhc_free); -EXPORT_SYMBOL(slhc_remember); -EXPORT_SYMBOL(slhc_compress); -EXPORT_SYMBOL(slhc_uncompress); -EXPORT_SYMBOL(slhc_toss); - -#ifdef MODULE - -int init_module(void) -{ - printk(KERN_INFO "CSLIP: code copyright 1989 Regents of the University of California\n"); - return 0; -} - -void cleanup_module(void) -{ - return; -} - -#endif /* MODULE */ -#else /* CONFIG_INET */ - - -int -slhc_toss(struct slcompress *comp) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss"); - return -EINVAL; -} -int -slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress"); - return -EINVAL; -} -int -slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, - unsigned char *ocp, unsigned char **cpp, int compress_cid) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress"); - return -EINVAL; -} - -int -slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember"); - return -EINVAL; -} - -void -slhc_free(struct slcompress *comp) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free"); - return; -} -struct slcompress * -slhc_init(int rslots, int tslots) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init"); - return NULL; -} -EXPORT_SYMBOL(slhc_init); -EXPORT_SYMBOL(slhc_free); -EXPORT_SYMBOL(slhc_remember); -EXPORT_SYMBOL(slhc_compress); -EXPORT_SYMBOL(slhc_uncompress); -EXPORT_SYMBOL(slhc_toss); - -#endif /* CONFIG_INET */ -MODULE_LICENSE("Dual BSD/GPL"); -- To view, visit https://gerrit.osmocom.org/635 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 1 14:06:41 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Mon, 1 Aug 2016 14:06:41 +0000 Subject: [PATCH] openbsc[master]: For some reason gprs_sndcp.h was located in src/gprs. It has... In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/636 to look at the new patch set (#2). For some reason gprs_sndcp.h was located in src/gprs. It has now been moved to include Change-Id: If4e4f1252c81d7907c1b4d738c982bb172b128c9 --- R openbsc/include/openbsc/gprs_sndcp.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/gprs_sndcp.c M openbsc/src/gprs/gprs_sndcp_vty.c 4 files changed, 2 insertions(+), 6 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/36/636/2 diff --git a/openbsc/src/gprs/gprs_sndcp.h b/openbsc/include/openbsc/gprs_sndcp.h similarity index 100% rename from openbsc/src/gprs/gprs_sndcp.h rename to openbsc/include/openbsc/gprs_sndcp.h diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 548b38c..a118a19 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -6,8 +6,6 @@ OSMO_LIBS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) \ $(LIBOSMOCTRL_LIBS) $(LIBOSMOGB_LIBS) -noinst_HEADERS = gprs_sndcp.h - bin_PROGRAMS = osmo-gbproxy if HAVE_LIBGTP diff --git a/openbsc/src/gprs/gprs_sndcp.c b/openbsc/src/gprs/gprs_sndcp.c index 75f95c9..4f71121 100644 --- a/openbsc/src/gprs/gprs_sndcp.c +++ b/openbsc/src/gprs/gprs_sndcp.c @@ -34,8 +34,7 @@ #include #include #include - -#include "gprs_sndcp.h" +#include /* Chapter 7.2: SN-PDU Formats */ struct sndcp_common_hdr { diff --git a/openbsc/src/gprs/gprs_sndcp_vty.c b/openbsc/src/gprs/gprs_sndcp_vty.c index deeef07..430881f 100644 --- a/openbsc/src/gprs/gprs_sndcp_vty.c +++ b/openbsc/src/gprs/gprs_sndcp_vty.c @@ -35,8 +35,7 @@ #include #include #include - -#include "gprs_sndcp.h" +#include #include #include -- To view, visit https://gerrit.osmocom.org/636 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: If4e4f1252c81d7907c1b4d738c982bb172b128c9 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 1 14:06:41 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Mon, 1 Aug 2016 14:06:41 +0000 Subject: [PATCH] openbsc[master]: Added llc-xid encoder / decoder In-Reply-To: References: Message-ID: Added llc-xid encoder / decoder Change-Id: Ia06e4cb08bf9b48c2a4682606d1b1a91d19a9d37 --- M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_llc_xid.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_llc_xid.c 4 files changed, 316 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/38/638/2 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 9ef8a15..9e8c554 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,7 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_sndcp.h slhc.h + gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_llc_xid.h b/openbsc/include/openbsc/gprs_llc_xid.h new file mode 100644 index 0000000..c840edb --- /dev/null +++ b/openbsc/include/openbsc/gprs_llc_xid.h @@ -0,0 +1,58 @@ +/* GPRS LLC XID field encoding/decoding as per 3GPP TS 04.64 */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_LLC_XID_H +#define _GPRS_LLC_XID_H + +#include +#include + +/* TS 101 351 6.4.1.6 Exchange Identification (XID) + command/response parameter field */ +struct gprs_llc_xid_field { + struct llist_head list; + uint8_t type; /* See also Table 6: LLC layer parameter + negotiation */ + uint8_t *data; /* Payload data (octets) */ + unsigned int data_len; /* Payload length */ +}; + +/* Transform a list with XID fields into a XID message (bytes) */ +int gprs_llc_compile_xid(struct llist_head *xid_fields, uint8_t * bytes, + int bytes_maxlen); + +/* Transform a XID message (bytes) into a list of XID fields */ +int gprs_llc_parse_xid(struct llist_head *xid_fields, uint8_t * bytes, + int bytes_len); + +/* Free llist with xid fields */ +void gprs_llc_free_xid(struct llist_head *xid_fields); + +/* Create a duplicate of an XID-Field */ +struct gprs_llc_xid_field *gprs_llc_duplicate_xid_field(struct + gprs_llc_xid_field + *xid_field); + +/* Dump a list with XID fields (Debug) */ +void gprs_llc_dump_xid_fields(struct llist_head *xid_fields); + +#endif diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index a118a19..b3a5137 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -23,7 +23,8 @@ osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \ slhc.c \ sgsn_main.c sgsn_vty.c sgsn_libgtp.c \ - gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c crc24.c \ + gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c \ + gprs_llc_xid.c crc24.c \ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ diff --git a/openbsc/src/gprs/gprs_llc_xid.c b/openbsc/src/gprs/gprs_llc_xid.c new file mode 100644 index 0000000..d8c5339 --- /dev/null +++ b/openbsc/src/gprs/gprs_llc_xid.c @@ -0,0 +1,255 @@ +/* GPRS LLC XID field encoding/decoding as per 3GPP TS 04.64 */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +/* Parse XID parameter field */ +static int +decode_xid_field(uint8_t *bytes, uint8_t bytes_len, + struct gprs_llc_xid_field *xid_field) +{ + uint8_t xl; + uint8_t type; + uint8_t len; + int bytes_counter = 0; + + /* Exit immediately if it is clear that no + parseable data is present */ + if ((bytes_len < 1) || (!(bytes))) + return -EINVAL; + + /* Exit immediately if no result can be stored */ + if (!xid_field) + return -EINVAL; + + /* Extract header info */ + xl = (*bytes >> 7) & 1; + type = (*bytes >> 2) & 0x1F; + + /* Extract length field */ + len = (*bytes) & 0x3; + bytes++; + bytes_counter++; + if (xl) { + if (bytes_len < 2) + return -EINVAL; + len = (len << 6) & 0xC0; + len |= ((*bytes) >> 2) & 0x3F; + bytes++; + bytes_counter++; + } + + /* Fill out struct */ + xid_field->type = type; + xid_field->data_len = len; + if (len > 0) { + if (bytes_len < bytes_counter + len) + return -EINVAL; + + xid_field->data = + talloc_zero_size(NULL, xid_field->data_len); + memcpy(xid_field->data, bytes, xid_field->data_len); + } else + xid_field->data = NULL; + + /* Return consumed length */ + return bytes_counter + len; +} + + +/* Encode XID parameter field */ +static int +encode_xid_field(uint8_t *bytes, int bytes_maxlen, + struct gprs_llc_xid_field *xid_field) +{ + int xl = 0; + + /* Exit immediately if no source struct is available */ + if (!xid_field) + return -EINVAL; + + /* When the length does not fit into 2 bits, + we need extended length fields */ + if (xid_field->data_len > 3) + xl = 1; + + /* Exit immediately if it is clear that no + encoding result can be stored */ + if (bytes_maxlen < xid_field->data_len + 1 + xl) + return -EINVAL; + + /* There are only 5 bits reserved for the type, exit on exceed */ + if (xid_field->type > 31) + return -EINVAL; + + /* Encode header */ + memset(bytes, 0, bytes_maxlen); + if (xl) + bytes[0] |= 0x80; + bytes[0] |= (((xid_field->type) & 0x1F) << 2); + + if (xl) { + bytes[0] |= (((xid_field->data_len) >> 6) & 0x03); + bytes[1] = ((xid_field->data_len) << 2) & 0xFC; + } else + bytes[0] |= ((xid_field->data_len) & 0x03); + + /* Append payload data */ + if ((xid_field->data) && (xid_field->data_len)) + memcpy(bytes + 1 + xl, xid_field->data, + xid_field->data_len); + + /* Return generated length */ + return xid_field->data_len + 1 + xl; +} + + +/* Transform a list with XID fields into a XID message (bytes) */ +int +gprs_llc_compile_xid(struct llist_head *xid_fields, uint8_t * bytes, + int bytes_maxlen) +{ + struct gprs_llc_xid_field *xid_field; + int rc; + int byte_counter = 0; + + memset(bytes, 0, bytes_maxlen); + + llist_for_each_entry(xid_field, xid_fields, list) { + /* Encode XID-Field */ + rc = encode_xid_field(bytes, bytes_maxlen, xid_field); + + /* Immediately stop on error */ + if (rc < 0) + return rc; + + /* Advance pointer and lower maxlen for the + next encoding round */ + bytes += rc; + byte_counter += rc; + bytes_maxlen -= rc; + } + + /* Return generated length */ + return byte_counter; +} + + +/* Transform a XID message (bytes) into a list of XID fields */ +int +gprs_llc_parse_xid(struct llist_head *xid_fields, uint8_t * bytes, + int bytes_len) +{ + struct gprs_llc_xid_field *xid_field; + int rc; + + while (1) { + /* Decode XID field */ + xid_field = talloc_zero(NULL, struct gprs_llc_xid_field); + rc = decode_xid_field(bytes, bytes_len, xid_field); + + /* Immediately stop on error */ + if (rc < 0) + return rc; + + /* Add parsed XID field to list */ + llist_add(&xid_field->list, xid_fields); + + /* Advance pointer and lower bytes_len for the next + decoding round */ + bytes += rc; + bytes_len -= rc; + + /* We are (scuccessfully) done when no further byes are left */ + if (bytes_len == 0) + return 0; + } +} + + +/* Free llist with xid fields */ +void gprs_llc_free_xid(struct llist_head *xid_fields) +{ + struct gprs_llc_xid_field *xid_field; + + llist_for_each_entry(xid_field, xid_fields, list) { + if ((xid_field->data) && (xid_field->data_len)) + talloc_free(xid_field->data); + talloc_free(xid_field); + } + +} + + +/* Create a duplicate of an XID-Field */ +struct gprs_llc_xid_field *gprs_llc_duplicate_xid_field(struct + gprs_llc_xid_field + *xid_field) +{ + struct gprs_llc_xid_field *duplicate_of_xid_field; + + /* Create a copy of the XID field in memory */ + duplicate_of_xid_field = + talloc_zero(NULL, struct gprs_llc_xid_field); + memcpy(duplicate_of_xid_field, xid_field, + sizeof(struct gprs_llc_xid_field)); + duplicate_of_xid_field->data = + talloc_zero_size(NULL, xid_field->data_len); + memcpy(duplicate_of_xid_field->data, xid_field->data, + xid_field->data_len); + + /* Wipeout all llist information in the duplicate (just to be sure) */ + memset(&duplicate_of_xid_field->list, 0, + sizeof(struct llist_head)); + + return duplicate_of_xid_field; +} + + +/* Dump a list with XID fields (Debug) */ +void gprs_llc_dump_xid_fields(struct llist_head *xid_fields) +{ + struct gprs_llc_xid_field *xid_field; + + llist_for_each_entry(xid_field, xid_fields, list) { + LOGP(DSNDCP, LOGL_DEBUG, + "XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + osmo_hexdump_nospc(xid_field->data, + xid_field->data_len)); + } +} -- To view, visit https://gerrit.osmocom.org/638 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia06e4cb08bf9b48c2a4682606d1b1a91d19a9d37 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 1 14:54:30 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 1 Aug 2016 14:54:30 +0000 Subject: libosmocore[master]: Extend L1SAP with Measurements In-Reply-To: References: Message-ID: Patch Set 2: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/622 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I2b127eb1856c4cd1bc46490a89592a595f1ee86b Gerrit-PatchSet: 2 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 1 14:55:51 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 1 Aug 2016 14:55:51 +0000 Subject: osmo-bts[master]: Fill measurements data for L1SAP In-Reply-To: References: Message-ID: Patch Set 3: does this commit introduce the feature for all BTS models, or only a sub-set? Please add that to the commit log, and preferrably add it for all models, if possible. -- To view, visit https://gerrit.osmocom.org/623 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ic9693a044756fb1c7bd2ff3cfa0db042c3c4e01c Gerrit-PatchSet: 3 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 1 14:56:28 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 1 Aug 2016 14:56:28 +0000 Subject: osmo-pcu[master]: Extend BTS <-> PCU protocol with measurement In-Reply-To: References: Message-ID: Patch Set 2: Code-Review+1 > I'm not really sure what else can I do. Please have a look at > get_meas() in src/osmo-bts-sysmo/sysmo_l1_if.c - it seems like we > get exactly the same precision loss in there too. Ok, then it is a shortcoming of the existing data model in the PCU which should be adressed in a separate commit. -- To view, visit https://gerrit.osmocom.org/624 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ide0e29b668ee38516605c1763fda85e87e867813 Gerrit-PatchSet: 2 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 1 14:57:48 2016 From: gerrit-no-reply at lists.osmocom.org (daniel) Date: Mon, 1 Aug 2016 14:57:48 +0000 Subject: openbsc[master]: Use random operation id In-Reply-To: References: Message-ID: Patch Set 1: Code-Review-1 (2 comments) With your patch there is now a useless option (-i). Before the builtin id would be shadowed by options.id so it would still use that value as the id. But yeah, the naming of the variables and parameters could be improved. https://gerrit.osmocom.org/#/c/640/1/openbsc/contrib/bsc_control.py File openbsc/contrib/bsc_control.py: Line 39: def do_set(var, value, op_id, sck): I agree, the name should change to avoid shadowing id and the parameter id was not used at all (but options.id directly). Line 57: parser.add_option("-i", "--id", dest="id", default="1", How about setting the random value as a default here? The this option does not become useless. Rename the option to something that is not a keyword/builtin as well (cmd_id?) -- To view, visit https://gerrit.osmocom.org/640 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I87d9ee0e9a87f58702c60bb141c973d41fa06997 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: daniel Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Mon Aug 1 14:58:29 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 1 Aug 2016 14:58:29 +0000 Subject: openbsc[master]: For some reason gprs_sndcp.h was located in src/gprs. It has... In-Reply-To: References: Message-ID: Patch Set 2: Code-Review-1 (1 comment) https://gerrit.osmocom.org/#/c/636/2/openbsc/src/gprs/Makefile.am File openbsc/src/gprs/Makefile.am: Line 9 You remove it from this Makefile.am, but where do you re-introudce it into the Makefile.am of the headers? I'm quite sure this will not pass "make distcheck" after this commit was applied. -- To view, visit https://gerrit.osmocom.org/636 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: If4e4f1252c81d7907c1b4d738c982bb172b128c9 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Mon Aug 1 14:59:57 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 1 Aug 2016 14:59:57 +0000 Subject: openbsc[master]: Modifed version of slhc (RFC1144 implementation) In-Reply-To: References: Message-ID: Patch Set 2: Code-Review+2 (1 comment) https://gerrit.osmocom.org/#/c/635/2/openbsc/include/openbsc/debug.h File openbsc/include/openbsc/debug.h: Line 32: DSLHC, I don't think it matters much, but general practise is to add elements to the bottom of the enum, before Debug_LastEntry -- To view, visit https://gerrit.osmocom.org/635 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Mon Aug 1 15:01:05 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 1 Aug 2016 15:01:05 +0000 Subject: openbsc[master]: Added slhc code from kernel.org. In-Reply-To: References: Message-ID: Patch Set 2: Code-Review-1 I think when importing code it makes sense to start with the latest version from the current mainline kernel version. Otherwise we might have missed any fixes btween the ancient linux-2.4 version you used and the current 4.x version. -- To view, visit https://gerrit.osmocom.org/634 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ied69c143678dc4a64cecc671f5c4dfebe19d8519 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 1 15:04:23 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Mon, 1 Aug 2016 15:04:23 +0000 Subject: libosmocore[master]: Extend L1SAP with Measurements In-Reply-To: References: Message-ID: Patch Set 2: Waiting for reply from Tom regarding possibility of computing C/I or equivalent for osmo-trx. If it's not possible than I'll add versioning. -- To view, visit https://gerrit.osmocom.org/622 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I2b127eb1856c4cd1bc46490a89592a595f1ee86b Gerrit-PatchSet: 2 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 1 15:11:27 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Mon, 1 Aug 2016 15:11:27 +0000 Subject: [PATCH] osmo-bts[master]: Fill measurements data for L1SAP In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/623 to look at the new patch set (#4). Fill measurements data for L1SAP Fill in values for BER, BTO, Link quality in L1SAP and send them to PCU. Note: this increases the version of BTS <-> PCU protocol. It also requires corresponding changes in libosmocore. Note: BTS <-> PCU changes are generic, but the introduced interface change is backward-compatible - the BTS code have to be changed to take advantage of it. SysmoBTS and LC will keep providing direct DSP access, OsmoBTS-TRX requires input from maintainer. Hence only Octphy is changed ATM. Octphy: conversion from sSNRDb to Link Quality uses formulae which works in practice instead of what's documented for sSNRDb value. Subject to change in future revisions. Change-Id: Ic9693a044756fb1c7bd2ff3cfa0db042c3c4e01c Related: OS#1616 --- M include/osmo-bts/pcu_if.h M include/osmo-bts/pcuif_proto.h M src/common/l1sap.c M src/common/pcu_sock.c M src/osmo-bts-octphy/l1_if.c 5 files changed, 26 insertions(+), 6 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/23/623/4 diff --git a/include/osmo-bts/pcu_if.h b/include/osmo-bts/pcu_if.h index 3ce4d0b..efad0c5 100644 --- a/include/osmo-bts/pcu_if.h +++ b/include/osmo-bts/pcu_if.h @@ -10,7 +10,7 @@ uint16_t arfcn, uint8_t block_nr); int pcu_tx_data_ind(struct gsm_bts_trx_ts *ts, uint8_t is_ptcch, uint32_t fn, uint16_t arfcn, uint8_t block_nr, uint8_t *data, uint8_t len, - int8_t rssi); + int8_t rssi, uint16_t ber10k, int16_t bto, int16_t lqual); int pcu_tx_rach_ind(struct gsm_bts *bts, int16_t qta, uint8_t ra, uint32_t fn); int pcu_tx_time_ind(uint32_t fn); int pcu_tx_pag_req(const uint8_t *identity_lv, uint8_t chan_needed); diff --git a/include/osmo-bts/pcuif_proto.h b/include/osmo-bts/pcuif_proto.h index 9d740ac..d320380 100644 --- a/include/osmo-bts/pcuif_proto.h +++ b/include/osmo-bts/pcuif_proto.h @@ -1,7 +1,7 @@ #ifndef _PCUIF_PROTO_H #define _PCUIF_PROTO_H -#define PCU_IF_VERSION 0x05 +#define PCU_IF_VERSION 0x06 /* msg_type */ #define PCU_IF_MSG_DATA_REQ 0x00 /* send data to given channel */ @@ -50,6 +50,9 @@ uint8_t ts_nr; uint8_t block_nr; int8_t rssi; + uint16_t ber10k; /*!< \brief BER in units of 0.01% */ + int16_t ta_offs_qbits; /* !< \brief Burst TA Offset in quarter bits */ + int16_t lqual_cb; /* !< \brief Link quality in centiBel */ } __attribute__ ((packed)); struct gsm_pcu_if_rts_req { diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 7f73e3f..4fc7801 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -812,7 +812,9 @@ if (L1SAP_IS_PTCCH(fn)) { pcu_tx_data_ind(&trx->ts[tn], 1, fn, 0 /* ARFCN */, L1SAP_FN2PTCCHBLOCK(fn), - data, len, rssi); + data, len, rssi, data_ind->ber10k, + data_ind->ta_offs_qbits, + data_ind->lqual_cb); return 0; } @@ -821,7 +823,8 @@ return 0; /* PDTCH / PACCH frame handling */ pcu_tx_data_ind(&trx->ts[tn], 0, fn, 0 /* ARFCN */, - L1SAP_FN2MACBLOCK(fn), data, len, rssi); + L1SAP_FN2MACBLOCK(fn), data, len, rssi, data_ind->ber10k, + data_ind->ta_offs_qbits, data_ind->lqual_cb); return 0; } diff --git a/src/common/pcu_sock.c b/src/common/pcu_sock.c index 22b6fab..fed464f 100644 --- a/src/common/pcu_sock.c +++ b/src/common/pcu_sock.c @@ -337,7 +337,7 @@ int pcu_tx_data_ind(struct gsm_bts_trx_ts *ts, uint8_t is_ptcch, uint32_t fn, uint16_t arfcn, uint8_t block_nr, uint8_t *data, uint8_t len, - int8_t rssi) + int8_t rssi, uint16_t ber10k, int16_t bto, int16_t lqual) { struct msgb *msg; struct gsm_pcu_if *pcu_prim; @@ -362,6 +362,9 @@ data_ind->ts_nr = ts->nr; data_ind->block_nr = block_nr; data_ind->rssi = rssi; + data_ind->ber10k = ber10k; + data_ind->ta_offs_qbits = bto; + data_ind->lqual_cb = lqual; memcpy(data_ind->data, data, len); data_ind->len = len; diff --git a/src/osmo-bts-octphy/l1_if.c b/src/osmo-bts-octphy/l1_if.c index 760c988..d621bcf 100644 --- a/src/osmo-bts-octphy/l1_if.c +++ b/src/osmo-bts-octphy/l1_if.c @@ -961,7 +961,8 @@ struct osmo_phsap_prim *l1sap; uint32_t fn; uint8_t *data; - uint16_t len; + uint16_t len, b_total, b_error; + int16_t snr; int8_t rssi; int rc; @@ -1029,6 +1030,16 @@ l1sap->u.data.chan_nr = chan_nr; l1sap->u.data.fn = fn; l1sap->u.data.rssi = rssi; + b_total = data_ind->MeasurementInfo.usBERTotalBitCnt; + b_error =data_ind->MeasurementInfo.usBERCnt; + l1sap->u.data.ber10k = b_total ? 10000 * b_error / b_total : 0; + l1sap->u.data.ta_offs_qbits = data_ind->MeasurementInfo.sBurstTiming4x; + snr = data_ind->MeasurementInfo.sSNRDb; + /* FIXME: better converion formulae for SnR -> C / I? + l1sap->u.data.lqual_cb = (snr ? snr : (snr - 65536)) * 10 / 256; + LOGP(DL1C, LOGL_ERROR, "SnR: raw %d, computed %d\n", snr, l1sap->u.data.lqual_cb); + */ + l1sap->u.data.lqual_cb = (snr ? snr : (snr - 65536)) * 100; l1sap->u.data.pdch_presence_info = PRES_INFO_BOTH; /* FIXME: consider EDGE support */ l1sap_up(trx, l1sap); -- To view, visit https://gerrit.osmocom.org/623 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ic9693a044756fb1c7bd2ff3cfa0db042c3c4e01c Gerrit-PatchSet: 4 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 1 15:12:25 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Mon, 1 Aug 2016 15:12:25 +0000 Subject: osmo-bts[master]: Fill measurements data for L1SAP In-Reply-To: References: Message-ID: Patch Set 4: I'm not sure if we need to bump BTS<->PCU version here - the change is backward-compatible. Please advice. -- To view, visit https://gerrit.osmocom.org/623 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ic9693a044756fb1c7bd2ff3cfa0db042c3c4e01c Gerrit-PatchSet: 4 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 1 15:14:35 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 1 Aug 2016 15:14:35 +0000 Subject: openbsc[master]: Added llc-xid encoder / decoder In-Reply-To: References: Message-ID: Patch Set 2: Code-Review-1 (16 comments) https://gerrit.osmocom.org/#/c/638/2/openbsc/include/openbsc/gprs_llc_xid.h File openbsc/include/openbsc/gprs_llc_xid.h: Line 40: int gprs_llc_compile_xid(struct llist_head *xid_fields, uint8_t * bytes, the input parameter could deserver a 'const' PS2, Line 44: int gprs_llc_parse_xid(struct llist_head *xid_fields instead of having the caller pass in an already-allocated llist_head, why not make the function return the 'llist_head *'? In case of error, NULL can be returned. PS2, Line 44: uint8_t * bytes the input parameter should use 'const uint8_t *' https://gerrit.osmocom.org/#/c/638/2/openbsc/src/gprs/gprs_llc_xid.c File openbsc/src/gprs/gprs_llc_xid.c: PS2, Line 41: static int : decode_xid_field(uint8_t *bytes, uint8_t bytes_len, : struct gprs_llc_xid_field *xid_field) why not allocate the xid_field (including the required xid_field->data) inside this function and returning a 'struct gprs_llc_xid_field'? It seems a bit odd that the caller has to allocate the structure, but not the data. also, input parameter should be 'const' PS2, Line 83: xid_field->data = : talloc_zero_size(NULL, xid_field->data_len); whenever we talloc() something, we should pass in a meaningful context. if xid_field is itself talloc'ed, we should use xid_field as context. If we don't know any context, the function's first argument should be a 'void *ctx' that is then used as context. PS2, Line 85: memcpy you can use talloc_memdup() as a short hand for allocation + memcpy PS2, Line 97: struct gprs_llc_xid_field *xid_field input parameter should be const Line 150: memset(bytes, 0, bytes_maxlen); I would remove that. we are filling the information in two lines below anyway. PS2, Line 156: /* Immediately stop on error */ commenting is nice, but a "if (rc < 0) return rc" doesn't need one, it's obvious :) PS2, Line 174: extra space; const missing PS2, Line 180: while (1) { endless loops must have a strong exist condition. Are there cases in which the return value of decode_xid_field could be zero? In that case we would loop forever? Line 209: llist_for_each_entry(xid_field, xid_fields, list) { if 'gprs_llc_parse_xid' would itself allocate the initial llist_head and return it (and allocate all xid_fields from it), you could simply replace this entire function with a single call to talloc_free() and let the hierarchical allocator do its work. PS2, Line 227: NULL have caller pass in a context PS2, Line 231: NULL use duplicate_of_xid_field as context Line 236: memset(&duplicate_of_xid_field->list, 0, don't do that, but rather use one of the linuxlist.h macros wich will use well-defined POISON values. PS2, Line 249: LOGL_DEBUG might make sense to have the caller specify the log level (we might want to print it as part of an error, not just debug. -- To view, visit https://gerrit.osmocom.org/638 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia06e4cb08bf9b48c2a4682606d1b1a91d19a9d37 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Mon Aug 1 15:16:03 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 1 Aug 2016 15:16:03 +0000 Subject: openbsc[master]: Added slhc.h to Makefile.am In-Reply-To: References: Message-ID: Patch Set 1: Code-Review-1 as discussed, please squash this into the other commit. -- To view, visit https://gerrit.osmocom.org/637 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ib28596ba5633ae1e9301fd81ed1dbf7236a8805d Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 1 15:20:31 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Mon, 1 Aug 2016 15:20:31 +0000 Subject: [PATCH] openbsc[master]: Use random operation id In-Reply-To: References: Message-ID: Hello daniel, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/640 to look at the new patch set (#2). Use random operation id According to documentation for Control Interface Protocol is "A numeric identifier, uniquely identifying this particular operation", hence it's best to be illustrated with random integer - use it as default. Fix override of id with previously used python-specific objects' id. Change-Id: I87d9ee0e9a87f58702c60bb141c973d41fa06997 Related: OS#1646 --- M openbsc/contrib/bsc_control.py 1 file changed, 10 insertions(+), 8 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/40/640/2 diff --git a/openbsc/contrib/bsc_control.py b/openbsc/contrib/bsc_control.py index 26a421d..4fc8b4d 100755 --- a/openbsc/contrib/bsc_control.py +++ b/openbsc/contrib/bsc_control.py @@ -1,6 +1,6 @@ #!/usr/bin/python -import sys,os +import sys,os, random from optparse import OptionParser import socket import struct @@ -36,15 +36,17 @@ data = prefix_ipa_ctrl_header(data) sck.send(data) -def do_set(var, value, id, sck): - setmsg = "SET %s %s %s" %(options.id, var, value) +def do_set(var, value, op_id, sck): + setmsg = "SET %s %s %s" %(op_id, var, value) send(sck, setmsg) -def do_get(var, id, sck): - getmsg = "GET %s %s" %(options.id, var) +def do_get(var, op_id, sck): + getmsg = "GET %s %s" %(op_id, var) send(sck, getmsg) if __name__ == '__main__': + random.seed() + parser = OptionParser("Usage: %prog [options] var [value]") parser.add_option("-d", "--host", dest="host", help="connect to HOST", metavar="HOST") @@ -54,7 +56,7 @@ dest="cmd_get", help="perform GET operation") parser.add_option("-s", "--set", action="store_true", dest="cmd_set", help="perform SET operation") - parser.add_option("-i", "--id", dest="id", default="1", + parser.add_option("-i", "--id", dest="op_id", default=random.randint(1, sys.maxint), help="set id manually", metavar="ID") parser.add_option("-v", "--verbose", action="store_true", dest="verbose", help="be verbose", default=False) @@ -79,12 +81,12 @@ if options.cmd_set: if len(args) < 2: parser.error("Set requires var and value arguments") - do_set(args[0], ' '.join(args[1:]), options.id, sock) + do_set(args[0], ' '.join(args[1:]), options.op_id, sock) if options.cmd_get: if len(args) != 1: parser.error("Get requires the var argument") - do_get(args[0], options.id, sock) + do_get(args[0], options.op_id, sock) data = sock.recv(1024) while (len(data)>0): -- To view, visit https://gerrit.osmocom.org/640 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I87d9ee0e9a87f58702c60bb141c973d41fa06997 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: daniel From gerrit-no-reply at lists.osmocom.org Mon Aug 1 15:51:45 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Mon, 1 Aug 2016 15:51:45 +0000 Subject: [PATCH] openbsc[master]: Added SNDCP-XID encoder / decoder Message-ID: Review at https://gerrit.osmocom.org/641 Added SNDCP-XID encoder / decoder The SNDCP-XID (or layer-3 xid) is used to exchange layer-3 parameters such as compression. The encoder encodes a bytestream that is then sent as regular XID field from LLC. We will need the SNDCP-XID to negotiate the parameters for our upcomming GPRS data and header compression features Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e --- M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_sndcp_xid.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_sndcp_xid.c 4 files changed, 1,816 insertions(+), 3 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/41/641/1 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 9e8c554..b37103f 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,7 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h + gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h gprs_sndcp_xid.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_sndcp_xid.h b/openbsc/include/openbsc/gprs_sndcp_xid.h new file mode 100644 index 0000000..53e24b8 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_xid.h @@ -0,0 +1,213 @@ +#ifndef _GPRS_SNDCP_XID_H +#define _GPRS_SNDCP_XID_H + +#include +#include + +#define CURRENT_SNDCP_VERSION 0 /* See TS 144 065, clause 8 */ + +/* According to: TS 144 065 6.5.1.1 Format of the protocol control information + compression field (Figure 7) + + TS 144 065 6.6.1.1 Format of the data compression + field (Figure 9) */ + +struct gprs_sndcp_comp_field { + struct llist_head list; + + /* Propose bit (P), see also: 6.5.1.1.2 and 6.6.1.1.2 */ + unsigned int p; + + /* Entity number, see also: 6.5.1.1.3 and 6.6.1.1.3 */ + unsigned int entity; + + /* gorithm identifier, see also: 6.5.1.1.4 and 6.6.1.1.4 */ + unsigned int algo; + + /* Number of contained PCOMP / DCOMP values */ + unsigned int comp_len; + + /* PCOMP / DCOMP values, see also: 6.5.1.1.5 and 6.6.1.1.5 */ + unsigned int comp[16]; + + /* Note: Only one of the following struct pointers may, + be used unused pointers must be set to NULL! */ + struct gprs_sndcp_hdrcomp_rfc1144_params *rfc1144_params; + struct gprs_sndcp_hdrcomp_rfc2507_params *rfc2507_params; + struct gprs_sndcp_hdrcomp_rohc_params *rohc_params; + struct gprs_sndcp_datacomp_v42bis_params *v42bis_params; + struct gprs_sndcp_datacomp_v44_params *v44_params; +}; + +/* According to: TS 144 065 6.5.1.1.4 Algorithm identifier */ +enum gprs_sndcp_hdr_comp_algo { + RFC_1144 = 0, /* TCP/IP header compression, see also 6.5.2 */ + RFC_2507 = 1, /* TCP/UDP/IP header compression, see also: 6.5.3 */ + ROHC = 2, /* Robust Header Compression, see also 6.5.4 */ +}; + +/* According to: TS 144 065 6.5.1.1.4 Algorithm identifier */ +enum gprs_sndcp_data_comp_algo { + V42BIS = 0, /* V42bis data compression, see also 6.6.2 */ + V44 = 1, /* V44 data compression, see also: 6.6.3 */ +}; + +/* According to: TS 144 065 8 SNDCP XID parameters */ +enum gprs_sndcp_xid_param_types { + SNDCP_XID_VERSION_NUMBER = 0, + SNDCP_XID_DATA_COMPRESSION = 1, /* See also: subclause 6.6.1 */ + SNDCP_XID_PROTOCOL_COMPRESSION = 2, /* See also: subclause 6.5.1 */ +}; + +/* When the propose bit in an SNDCP-XID compression field is set to zero, + the algorithm identifier is stripped. The algoritm parameters are specific + for each algorithms. The following struct is used to pass the information + about the referenced algorithm to the parser. */ +struct gprs_sndcp_hdrcomp_entity_algo_table { + unsigned int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + unsigned int algo; /* see also: 6.5.1.1.4 and 6.6.1.1.4 */ + unsigned int compclass; /* Can be either SNDCP_XID_DATA_COMPRESSION or + SNDCP_XID_PROTOCOL_COMPRESSION */ +}; + + + +/* According to: TS 144 065 6.5.2.1 Parameters (Table 5) */ +struct gprs_sndcp_hdrcomp_rfc1144_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + unsigned int s01; /* (default 15) */ +}; + +/* According to: TS 144 065 6.5.2.2 Assignment of PCOMP values */ +enum gprs_sndcp_hdrcomp_rfc1144_pcomp { + RFC1144_PCOMP1 = 0, /* Uncompressed TCP */ + RFC1144_PCOMP2 = 1, /* Compressed TCP */ + RFC1144_PCOMP_LEN = 2 +}; + + + +/* According to: TS 144 065 6.5.3.1 Parameters (Table 6) */ +struct gprs_sndcp_hdrcomp_rfc2507_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + unsigned int f_max_period; /* (default 256) */ + unsigned int f_max_time; /* (default 5) */ + unsigned int max_header; /* (default 168) */ + unsigned int tcp_space; /* (default 15) */ + unsigned int non_tcp_space; /* (default 15) */ +}; + +/* According to: TS 144 065 6.5.3.2 Assignment of PCOMP values for RFC2507 */ +enum gprs_sndcp_hdrcomp_rfc2507_pcomp { + RFC2507_PCOMP1 = 0, /* Full Header */ + RFC2507_PCOMP2 = 1, /* Compressed TCP */ + RFC2507_PCOMP3 = 2, /* Compressed TCP non delta */ + RFC2507_PCOMP4 = 3, /* Compressed non TCP */ + RFC2507_PCOMP5 = 4, /* Context state */ + RFC2507_PCOMP_LEN = 5 +}; + + + +/* According to: TS 144 065 6.5.4.1 Parameter (Table 10) */ +struct gprs_sndcp_hdrcomp_rohc_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + unsigned int max_cid; /* (default 15) */ + unsigned int max_header; /* (default 168) */ + unsigned int profile_len; /* (default 1) */ + uint16_t profile[16]; /* (default 0, ROHC uncompressed) */ +}; + +/* According to: TS 144 065 6.5.4.2 Assignment of PCOMP values for ROHC */ +enum gprs_sndcp_hdrcomp_rohc_pcomp { + ROHC_PCOMP1 = 0, /* ROHC small CIDs */ + ROHC_PCOMP2 = 1, /* ROHC large CIDs */ + ROHC_PCOMP_LEN = 2 +}; + +/* ROHC compression profiles, see also: + http://www.iana.org/assignments/rohc-pro-ids/rohc-pro-ids.xhtml */ +enum gprs_sndcp_xid_rohc_profiles { + ROHC_UNCOMPRESSED = 0x0000, /* ROHC uncompressed [RFC5795] */ + ROHC_RTP = 0x0001, /* ROHC RTP [RFC3095] */ + ROHCV2_RTP = 0x0101, /* ROHCv2 RTP [RFC5225] */ + ROHC_UDP = 0x0002, /* ROHC UDP [RFC3095] */ + ROHCv2_UDP = 0x0102, /* ROHCv2 UDP [RFC5225] */ + ROHC_ESP = 0x0003, /* ROHC ESP [RFC3095] */ + ROHCV2_ESP = 0x0103, /* ROHCv2 ESP [RFC5225] */ + ROHC_IP = 0x0004, /* ROHC IP [RFC3843] */ + ROHCV2_IP = 0x0104, /* ROHCv2 IP [RFC5225] */ + ROHC_LLA = 0x0005, /* ROHC LLA [RFC4362] */ + ROHC_LLA_WITH_R_MODE = 0x0105, /* ROHC LLA with R-mode [RFC3408] */ + ROHC_TCP = 0x0006, /* ROHC TCP [RFC6846] */ + ROHC_RTP_UDP_LITE = 0x0007, /* ROHC RTP/UDP-Lite [RFC4019] */ + ROHCV2_RTP_UDP_LITE = 0x0107, /* ROHCv2 RTP/UDP-Lite [RFC5225] */ + ROHC_UDP_LITE = 0x0008, /* ROHC UDP-Lite [RFC4019] */ + ROHCV2_UDP_LITE = 0x0108, /* ROHCv2 UDP-Lite [RFC5225] */ +}; + + + +/* According to: TS 144 065 6.6.2.1 Parameters (Table 7a) */ +struct gprs_sndcp_datacomp_v42bis_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + unsigned int p0; /* (default 3) */ + unsigned int p1; /* (default 2048) */ + unsigned int p2; /* (default 20) */ + +}; + +/* According to: ETSI TS 144 065 6.6.2.2 Assignment of DCOMP values */ +enum gprs_sndcp_datacomp_v42bis_dcomp { + V42BIS_DCOMP1 = 0, /* V42bis enabled */ + V42BIS_DCOMP_LEN = 1 +}; + + + +/* According to: TS 144 065 6.6.3.1 Parameters (Table 7c) */ +struct gprs_sndcp_datacomp_v44_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + unsigned int c0; /* (default 10000000) */ + unsigned int p0; /* (default 3) */ + unsigned int p1t; /* Refer to subclause 6.6.3.1.4 */ + unsigned int p1r; /* Refer to subclause 6.6.3.1.5 */ + unsigned int p3t; /* (default 3 x p1t) */ + unsigned int p3r; /* (default 3 x p1r) */ +}; + +/* According to: ETSI TS 144 065 6.6.3.2 Assignment of DCOMP values */ +enum gprs_sndcp_datacomp_v44_dcomp { + V44_DCOMP1 = 0, /* Packet method compressed */ + V44_DCOMP2 = 1, /* Multi packet method compressed */ + V44_DCOMP_LEN = 2 +}; + +/* Transform a list with compression fields into an SNDCP-XID message (bytes) */ +int gprs_sndcp_compile_xid(struct llist_head *comp_fields, uint8_t * bytes, + unsigned int bytes_maxlen); + +/* Transform an SNDCP-XID message (bytes) into a list of SNDCP-XID fields */ +int gprs_sndcp_parse_xid(struct llist_head *comp_fields, uint8_t * bytes, + unsigned int bytes_len, + struct gprs_sndcp_hdrcomp_entity_algo_table *lt, + unsigned int lt_len); + +/* Free a list with SNDCP-XID fields */ +void gprs_sndcp_free_comp_fields(struct llist_head *comp_fields); + +/* Find out to which compression class the specified comp-field belongs + (header compression or data compression?) */ +int gprs_sndcp_get_compression_class(struct gprs_sndcp_comp_field + *comp_field); + +/* Dump a list with SNDCP-XID fields (Debug) */ +void gprs_sndcp_dump_comp_fields(struct llist_head *comp_fields); + + +#endif diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index b3a5137..67e9943 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -21,7 +21,7 @@ $(OSMO_LIBS) $(LIBCRYPTO_LIBS) -lrt osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \ - slhc.c \ + slhc.c gprs_sndcp_xid.c \ sgsn_main.c sgsn_vty.c sgsn_libgtp.c \ gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c \ gprs_llc_xid.c crc24.c \ @@ -32,7 +32,7 @@ osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ - $(LIBCRYPTO_LIBS) -lrt + $(LIBCRYPTO_LIBS) -lrt -lm osmo_gtphub_SOURCES = gtphub_main.c gtphub.c gtphub_sock.c gtphub_ares.c \ gtphub_vty.c sgsn_ares.c gprs_utils.c diff --git a/openbsc/src/gprs/gprs_sndcp_xid.c b/openbsc/src/gprs/gprs_sndcp_xid.c new file mode 100644 index 0000000..dd8f535 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_xid.c @@ -0,0 +1,1600 @@ +/* GPRS SNDCP XID field encoding/decoding as per 3GPP TS 144 065 */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +/* + * FUNCTIONS RELATED TO SNDCP-XID ENCODING + */ + +/* Encode applicable sapis (works the same in all three compression schemes) */ +static int encode_hdrcomp_applicable_sapis(uint8_t *bytes, + unsigned int *nsapis, + unsigned int nsapis_len) +{ + uint16_t blob; + unsigned int nsapi; + int i; + + /* Encode applicable SAPIs */ + blob = 0; + for (i = 0; i < nsapis_len; i++) { + nsapi = nsapis[i]; + if ((nsapi < 5) || (nsapi > 15)) + return -EINVAL; + blob |= (1 << nsapi); + } + + /* Store result */ + *bytes = (blob >> 8) & 0xFF; + bytes++; + *bytes = blob & 0xFF; + + return 2; +} + +/* Encode rfc1144 parameter field */ +static int encode_hdrcomp_rfc1144_params(uint8_t *bytes, + unsigned int bytes_maxlen, + struct + gprs_sndcp_hdrcomp_rfc1144_params + *params) +{ + /* NOTE: Buffer *bytes should offer at least 3 bytes + of space to store the generation results */ + + /* NOTE: Do not call manually, will be called by + encode_comp_field on purpose */ + + int bytes_counter = 0; + int rc; + + /* Exit immediately if no source struct is available */ + if (!params) + return -EINVAL; + + /* Exit immediately if no sufficient memory space is supplied */ + if ((bytes_maxlen < 3) || (!(bytes))) + return -EINVAL; + + /* Exit if number of possible nsapis exceeds valid range + (Only 11 nsapis possible for PDP-Contexts) */ + if ((params->nsapi_len < 0) || (params->nsapi_len > 11)) + return -EINVAL; + + /* Zero out buffer */ + memset(bytes, 0, bytes_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_hdrcomp_applicable_sapis(bytes, params->nsapi, + params->nsapi_len); + bytes += rc; + bytes_counter += rc; + + /* Encode s01 */ + *bytes = params->s01; + bytes++; + bytes_counter++; + + /* Return generated length */ + return bytes_counter; +} + + +/* Encode rfc2507 parameter field */ +static int encode_hdrcomp_rfc2507_params(uint8_t *bytes, + unsigned int bytes_maxlen, + struct + gprs_sndcp_hdrcomp_rfc2507_params + *params) +{ + /* NOTE: Buffer *bytes should offer at least 3 bytes + of space to store the generation results */ + + /* NOTE: Do not call manually, will be called + by encode_comp_field on purpose */ + + int bytes_counter = 0; + int rc; + + /* Exit immediately if no source struct is available */ + if (!params) + return -EINVAL; + + /* Exit immediately if no sufficient memory space is supplied */ + if ((bytes_maxlen < 9) || (!(bytes))) + return -EINVAL; + + /* Exit if number of possible nsapis exceeds valid range + (Only 11 nsapis possible for PDP-Contexts) */ + if ((params->nsapi_len < 0) || (params->nsapi_len > 11)) + return -EINVAL; + + /* Zero out buffer */ + memset(bytes, 0, bytes_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_hdrcomp_applicable_sapis(bytes, params->nsapi, + params->nsapi_len); + bytes += rc; + bytes_counter += rc; + + /* Encode F_MAX_PERIOD */ + if ((params->f_max_period < 1) || (params->f_max_period > 65535)) + return -EINVAL; + *bytes = (params->f_max_period >> 8) & 0xFF; + bytes++; + bytes_counter++; + *bytes = (params->f_max_period) & 0xFF; + bytes++; + bytes_counter++; + + /* Encode F_MAX_TIME */ + if ((params->f_max_time < 1) || (params->f_max_time > 255)) + return -EINVAL; + *bytes = params->f_max_time; + bytes++; + bytes_counter++; + + /* Encode MAX_HEADER */ + if ((params->max_header < 60) || (params->max_header > 255)) + return -EINVAL; + *bytes = params->max_header; + bytes++; + bytes_counter++; + + /* Encode TCP_SPACE */ + if ((params->tcp_space < 3) || (params->tcp_space > 255)) + return -EINVAL; + *bytes = params->tcp_space; + bytes++; + bytes_counter++; + + /* Encode NON_TCP_SPACE */ + if ((params->non_tcp_space < 3) || (params->tcp_space > 65535)) + return -EINVAL; + *bytes = (params->non_tcp_space >> 8) & 0xFF; + bytes++; + bytes_counter++; + *bytes = (params->non_tcp_space) & 0xFF; + bytes++; + bytes_counter++; + + /* Return generated length */ + return bytes_counter; +} + + +/* Encode ROHC parameter field */ +static int encode_hdrcomp_rohc_params(uint8_t *bytes, + unsigned int bytes_maxlen, + struct gprs_sndcp_hdrcomp_rohc_params + *params) +{ + /* NOTE: Buffer *bytes should offer at least 36 + (2 * 16 Profiles + 2 * 3 Parameter) + bytes of memory space to store generation results */ + + /* NOTE: Do not call manually, will be called + by encode_comp_field on purpose */ + + int i; + int bytes_counter = 0; + int rc; + + /* Exit immediately if no source struct is available */ + if (!params) + return -EINVAL; + + /* Exit immediately if no sufficient memory space is supplied */ + if ((bytes_maxlen < 38) || (!(bytes))) + return -EINVAL; + + /* Exit if number of possible nsapis exceeds valid range + (Only 11 nsapis possible for PDP-Contexts) */ + if ((params->nsapi_len < 0) || (params->nsapi_len > 11)) + return -EINVAL; + + /* Exit if number of ROHC profiles exceeds limit + (ROHC supports only a maximum of 16 different profiles) */ + if ((params->profile_len < 0) || (params->profile_len > 16)) + return -EINVAL; + + /* Zero out buffer */ + memset(bytes, 0, bytes_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_hdrcomp_applicable_sapis(bytes, params->nsapi, + params->nsapi_len); + bytes += rc; + bytes_counter += rc; + + /* Encode MAX_CID */ + if (params->max_cid > 16383) + return -EINVAL; + *bytes = (params->max_cid >> 8) & 0xFF; + bytes++; + *bytes = params->max_cid & 0xFF; + bytes++; + bytes_counter += 2; + + /* Encode MAX_HEADER */ + if ((params->max_header < 60) || (params->max_header > 255)) + return -EINVAL; + *bytes = (params->max_header >> 8) & 0xFF; + bytes++; + *bytes = params->max_header & 0xFF; + bytes++; + bytes_counter += 2; + + /* Encode ROHC Profiles */ + for (i = 0; i < params->profile_len; i++) { + *bytes = (params->profile[i] >> 8) & 0xFF; + bytes++; + *bytes = params->profile[i] & 0xFF; + bytes++; + bytes_counter += 2; + } + + /* Return generated length */ + return bytes_counter; +} + + +/* Encode V42bis parameter field */ +static int encode_datacomp_v42bis_params(uint8_t *bytes, + unsigned int bytes_maxlen, + struct + gprs_sndcp_datacomp_v42bis_params + *params) +{ + /* NOTE: Buffer *bytes should offer at least 6 bytes + of space to store the generation results */ + + /* NOTE: Do not call manually, will be called + by encode_comp_field on purpose */ + + int bytes_counter = 0; + int rc; + + /* Exit immediately if no source struct is available */ + if (!params) + return -EINVAL; + + /* Exit immediately if no sufficient memory space is supplied */ + if ((bytes_maxlen < 6) || (!(bytes))) + return -EINVAL; + + /* Exit if number of possible nsapis exceeds valid range + (Only 11 nsapis possible for PDP-Contexts) */ + if ((params->nsapi_len < 0) || (params->nsapi_len > 11)) + return -EINVAL; + + /* Zero out buffer */ + memset(bytes, 0, bytes_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_hdrcomp_applicable_sapis(bytes, params->nsapi, + params->nsapi_len); + bytes += rc; + bytes_counter += rc; + + /* Encode P0 */ + if (params->p0 > 3) + return -EINVAL; + *bytes = params->p0 & 0x03; + bytes++; + bytes_counter++; + + /* Encode P1 */ + if ((params->p1 < 512) || (params->p1 > 65535)) + return -EINVAL; + *bytes = (params->p1 >> 8) & 0xFF; + bytes++; + *bytes = params->p1 & 0xFF; + bytes++; + bytes_counter += 2; + + /* Encode P2 */ + if ((params->p2 < 6) || (params->p2 > 250)) + return -EINVAL; + *bytes = params->p2; + bytes++; + bytes_counter++; + + /* Return generated length */ + return bytes_counter; +} + + +/* Encode V44 parameter field */ +static int encode_datacomp_v44_params(uint8_t *bytes, + unsigned int bytes_maxlen, + struct gprs_sndcp_datacomp_v44_params + *params) +{ + /* NOTE: Buffer *bytes should offer at least 12 + bytes of space to store the generation results */ + + /* NOTE: Do not call manually, will be called + by encode_comp_field on purpose */ + + int bytes_counter = 0; + int rc; + + /* Exit immediately if no source struct is available */ + if (!params) + return -EINVAL; + + /* Exit immediately if no sufficient memory space is supplied */ + if ((bytes_maxlen < 12) || (!(bytes))) + return -EINVAL; + + /* Exit if number of possible nsapis exceeds valid range + (Only 11 nsapis possible for PDP-Contexts) */ + if ((params->nsapi_len < 0) || (params->nsapi_len > 11)) + return -EINVAL; + + /* Zero out buffer */ + memset(bytes, 0, bytes_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_hdrcomp_applicable_sapis(bytes, params->nsapi, + params->nsapi_len); + bytes += rc; + bytes_counter += rc; + + /* Encode C0 */ + if ((params->c0 == 0x80) || (params->c0 == 0xC0)) { + *bytes = params->c0 & 0xC0; + bytes++; + bytes_counter++; + } else + return -EINVAL; + + /* Encode P0 */ + if (params->p0 > 3) + return -EINVAL; + *bytes = params->p0 & 0x03; + bytes++; + bytes_counter++; + + /* Encode P1T */ + if ((params->p1t < 256) || (params->p1t > 65535)) + return -EINVAL; + *bytes = (params->p1t >> 8) & 0xFF; + bytes++; + *bytes = params->p1t & 0xFF; + bytes++; + bytes_counter += 2; + + /* Encode P1R */ + if ((params->p1r < 256) || (params->p1r > 65535)) + return -EINVAL; + *bytes = (params->p1r >> 8) & 0xFF; + bytes++; + *bytes = params->p1r & 0xFF; + bytes++; + bytes_counter += 2; + + /* Encode P3T */ + if (params->p3t > 65535) + return -EINVAL; + if (params->p3t < 2 * params->p1t) + return -EINVAL; + *bytes = (params->p3t >> 8) & 0xFF; + bytes++; + *bytes = params->p3t & 0xFF; + bytes++; + bytes_counter += 2; + + /* Encode P3R */ + if (params->p3r > 65535) + return -EINVAL; + if (params->p3r < 2 * params->p1r) + return -EINVAL; + *bytes = (params->p3r >> 8) & 0xFF; + bytes++; + *bytes = params->p3r & 0xFF; + bytes++; + bytes_counter += 2; + + /* Return generated length */ + return bytes_counter; +} + + +/* Encode data or protocol control information compression field */ +static int encode_comp_field(uint8_t *bytes, unsigned int bytes_maxlen, + struct gprs_sndcp_comp_field *comp_field) +{ + int bytes_counter = 0; + int len; + int expected_length; + int i; + + uint8_t payload_bytes[256]; + int payload_bytes_len = -1; + + /* If possible, try do encode payload bytes first */ + if (comp_field->rfc1144_params) + payload_bytes_len = + encode_hdrcomp_rfc1144_params(payload_bytes, + sizeof(payload_bytes), + comp_field-> + rfc1144_params); + else if (comp_field->rfc2507_params) + payload_bytes_len = + encode_hdrcomp_rfc2507_params(payload_bytes, + sizeof(payload_bytes), + comp_field-> + rfc2507_params); + else if (comp_field->rohc_params) + payload_bytes_len = + encode_hdrcomp_rohc_params(payload_bytes, + sizeof(payload_bytes), + comp_field->rohc_params); + else if (comp_field->v42bis_params) + payload_bytes_len = + encode_datacomp_v42bis_params(payload_bytes, + sizeof(payload_bytes), + comp_field-> + v42bis_params); + else if (comp_field->v44_params) + payload_bytes_len = + encode_datacomp_v44_params(payload_bytes, + sizeof(payload_bytes), + comp_field->v44_params); + else + return -EINVAL; + + /* Exit immediately if payload byte generation failed */ + if (payload_bytes_len < 0) + return -EINVAL; + + /* Exit immediately if no source struct is available */ + if (!comp_field) + return -EINVAL; + + /* Check if comp_len is within bounds */ + if ((comp_field->comp_len < 0) || (comp_field->comp_len > 16)) + return -EINVAL; + + /* Calculate length field of the data block */ + if (comp_field->p) { + len = + payload_bytes_len + + ceil((double) (comp_field->comp_len) / 2.0); + expected_length = len + 3; + } else { + len = payload_bytes_len; + expected_length = len + 2; + } + + /* Exit immediately if no sufficient memory space is supplied */ + if ((bytes_maxlen < expected_length) || (!(bytes))) + return -EINVAL; + + /* Check if the entity number is within bounds */ + if ((comp_field->entity < 0) || (comp_field->entity > 0x1f)) + return -EINVAL; + + /* Check if the algorithm number is within bounds */ + if ((comp_field->algo < 0) || (comp_field->algo > 0x1f)) + return -EINVAL; + + /* Zero out buffer */ + memset(bytes, 0, bytes_maxlen); + + /* Encode Propose bit */ + if (comp_field->p) + *bytes |= (1 << 7); + + /* Encode entity number */ + *bytes |= comp_field->entity & 0x1F; + bytes++; + bytes_counter++; + + /* Encode algorithm number */ + if (comp_field->p) { + *bytes |= comp_field->algo & 0x1F; + bytes++; + bytes_counter++; + } + + /* Encode length field */ + *bytes |= len & 0xFF; + bytes++; + bytes_counter++; + + /* Encode PCOMP/DCOMP values */ + if (comp_field->p) { + for (i = 0; i < comp_field->comp_len; i++) { + /* Check if submitted PCOMP/DCOMP + values are within bounds */ + if ((comp_field->comp[i] < 0) + || (comp_field->comp[i] > 0x0F)) + return -EINVAL; + + if (i & 1) { + *bytes |= comp_field->comp[i] & 0x0F; + bytes++; + bytes_counter++; + } else + *bytes |= + (comp_field->comp[i] << 4) & 0xF0; + } + + if (i & 1) { + bytes++; + bytes_counter++; + } + } + + /* Append payload bytes */ + memcpy(bytes, payload_bytes, payload_bytes_len); + bytes_counter += payload_bytes_len; + + /* Return generated length */ + return bytes_counter; +} + + +/* Find out to which compression class the specified comp-field belongs + (header compression or data compression?) */ +int gprs_sndcp_get_compression_class(struct gprs_sndcp_comp_field + *comp_field) +{ + if (comp_field->rfc1144_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->rfc2507_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->rohc_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->v42bis_params) + return SNDCP_XID_DATA_COMPRESSION; + else if (comp_field->v44_params) + return SNDCP_XID_DATA_COMPRESSION; + else + return -EINVAL; +} + + +/* Convert all compression fields to bytstreams */ +static int gprs_sndcp_pack_fields(struct llist_head *comp_fields, + uint8_t * bytes, + unsigned int bytes_maxlen, int class) +{ + struct gprs_sndcp_comp_field *comp_field; + int byte_counter = 0; + int rc; + + llist_for_each_entry(comp_field, comp_fields, list) { + if (class == gprs_sndcp_get_compression_class(comp_field)) { + rc = encode_comp_field(bytes + byte_counter, + bytes_maxlen - byte_counter, + comp_field); + + /* Immediately stop on error */ + if (rc < 0) + return rc; + + byte_counter += rc; + } + } + + /* Return generated length */ + return byte_counter; +} + + +/* Transform a list with compression fields into an SNDCP-XID message (bytes) */ +int gprs_sndcp_compile_xid(struct llist_head *comp_fields, uint8_t *bytes, + unsigned int bytes_maxlen) +{ + int rc; + int byte_counter = 0; + uint8_t comp_bytes[512]; + uint8_t xid_version_number[1] = { CURRENT_SNDCP_VERSION }; + + /* Exit immediately if no sufficient memory space is supplied */ + if ((bytes_maxlen < 2 + sizeof(xid_version_number)) || (!(bytes))) + return -EINVAL; + + /* Zero out buffer (just to be sure) */ + memset(bytes, 0, bytes_maxlen); + + /* Prepend header */ + bytes = + tlv_put(bytes, SNDCP_XID_VERSION_NUMBER, + sizeof(xid_version_number), xid_version_number); + byte_counter += (sizeof(xid_version_number) + 2); + + /* Add data compression fields */ + rc = gprs_sndcp_pack_fields(comp_fields, comp_bytes, + sizeof(comp_bytes), + SNDCP_XID_DATA_COMPRESSION); + if (rc < 0) + return rc; + else if (rc > 0) { + bytes = + tlv_put(bytes, SNDCP_XID_DATA_COMPRESSION, rc, + comp_bytes); + byte_counter += rc + 2; + } + + /* Add header compression fields */ + rc = gprs_sndcp_pack_fields(comp_fields, comp_bytes, + sizeof(comp_bytes), + SNDCP_XID_PROTOCOL_COMPRESSION); + if (rc < 0) + return rc; + else if (rc > 0) { + bytes = + tlv_put(bytes, SNDCP_XID_PROTOCOL_COMPRESSION, rc, + comp_bytes); + byte_counter += rc + 2; + } + + /* Return generated length */ + return byte_counter; +} + + + + + + + + + + +/* + * FUNCTIONS RELATED TO SNDCP-XID DECODING + */ + +/* Decode applicable sapis (works the same in all three compression schemes) */ +static int decode_hdrcomp_applicable_sapis(const uint8_t * bytes, + unsigned int bytes_len, + unsigned int *nsapis, + unsigned int *nsapis_len) +{ + uint16_t blob; + int i; + int nsapi_len = 0; + + /* Exit immediately if no result can be stored */ + if (!nsapis) + return -EINVAL; + + /* Exit immediately if not enough input data is available */ + if (bytes_len < 2) + return -EINVAL; + + /* Read bitmask */ + blob = *bytes; + blob = (blob << 8) & 0xFF00; + bytes++; + blob |= (*bytes) & 0xFF; + blob = (blob >> 5); + + /* Decode applicable SAPIs */ + for (i = 0; i < 15; i++) { + if ((blob >> i) & 1) { + nsapis[nsapi_len] = i + 5; + nsapi_len++; + } + } + + /* Return consumed length */ + *nsapis_len = nsapi_len; + return 2; +} + +/* Decode 16 bit field */ +static int decode_hdrcomp_16_bit_field(const uint8_t * bytes, + unsigned int bytes_len, + int value_min, int value_max, + unsigned int *value_int, + uint16_t * value_uint16) +{ + uint16_t blob; + + /* Reset values to zero (just to be sure) */ + if (value_int) + *value_int = 0; + if (value_uint16) + *value_uint16 = 0; + + /* Exit if not enough bytes are available */ + if (bytes_len < 2) + return -EINVAL; + + /* Decode bit value */ + blob = *bytes; + blob = (blob << 8) & 0xFF00; + bytes++; + blob |= *bytes; + + /* Check if parsed value is within bounds */ + if (blob < value_min) + return -EINVAL; + if (blob > value_max) + return -EINVAL; + + /* Hand back results to the caller */ + if (value_int) + *value_int = blob; + if (value_uint16) + *value_uint16 = blob; + + /* Return consumed length */ + return 2; +} + +/* Decode 8 bit field */ +static int decode_hdrcomp_8_bit_field(const uint8_t * bytes, + unsigned int bytes_len, + int value_min, int value_max, + unsigned int *value_int, + uint8_t * value_uint8) +{ + uint8_t blob; + + /* Reset values to zero (just to be sure) */ + if (value_int) + *value_int = 0; + if (value_uint8) + *value_uint8 = 0; + + /* Exit if not enough bytes are available */ + if (bytes_len < 1) + return -EINVAL; + + /* Decode bit value */ + blob = *bytes; + + /* Check if parsed value is within bounds */ + if (blob < value_min) + return -EINVAL; + if (blob > value_max) + return -EINVAL; + + /* Hand back results to the caller */ + if (value_int) + *value_int = blob; + if (value_uint8) + *value_uint8 = blob; + + /* Return consumed length */ + return 1; +} + + + + +/* Decode rfc1144 parameter field */ +static int decode_hdrcomp_rfc1144_params(const uint8_t * bytes, + unsigned int bytes_len, + struct + gprs_sndcp_hdrcomp_rfc1144_params + *params) +{ + int rc; + int byte_counter = 0; + + /* Exit immediately if no result can be stored */ + if (!params) + return -EINVAL; + + /* Decode applicable SAPIs */ + rc = decode_hdrcomp_applicable_sapis(bytes, bytes_len, + params->nsapi, + ¶ms->nsapi_len); + if (rc > 0) { + byte_counter += rc; + bytes += rc; + } else + return byte_counter; + + /* Decode parameter S0 -1 */ + rc = decode_hdrcomp_8_bit_field(bytes, bytes_len - byte_counter, 0, + 255, ¶ms->s01, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + bytes += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Decode rfc2507 parameter field */ +static int decode_hdrcomp_rfc2507_params(const uint8_t * bytes, + unsigned int bytes_len, + struct + gprs_sndcp_hdrcomp_rfc2507_params + *params) +{ + int rc; + int byte_counter = 0; + + /* Exit immediately if no result can be stored */ + if (!params) + return -EINVAL; + + /* Decode applicable SAPIs */ + rc = decode_hdrcomp_applicable_sapis(bytes, bytes_len, + params->nsapi, + ¶ms->nsapi_len); + if (rc > 0) { + byte_counter += rc; + bytes += rc; + } else + return byte_counter; + + /* Decode F_MAX_PERIOD */ + rc = decode_hdrcomp_16_bit_field(bytes, bytes_len - byte_counter, + 1, 65535, ¶ms->f_max_period, + NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + bytes += rc; + + /* Decode F_MAX_TIME */ + rc = decode_hdrcomp_8_bit_field(bytes, bytes_len - byte_counter, 1, + 255, ¶ms->f_max_time, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + bytes += rc; + + /* Decode MAX_HEADER */ + rc = decode_hdrcomp_8_bit_field(bytes, bytes_len - byte_counter, + 60, 255, ¶ms->max_header, + NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + bytes += rc; + + /* Decode TCP_SPACE */ + rc = decode_hdrcomp_8_bit_field(bytes, bytes_len - byte_counter, 3, + 255, ¶ms->tcp_space, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + bytes += rc; + + /* Decode NON_TCP_SPACE */ + rc = decode_hdrcomp_16_bit_field(bytes, bytes_len - byte_counter, + 3, 65535, ¶ms->non_tcp_space, + NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + bytes += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Decode ROHC parameter field */ +static int decode_hdrcomp_rohc_params(const uint8_t * bytes, + unsigned int bytes_len, + struct gprs_sndcp_hdrcomp_rohc_params + *params) +{ + int rc; + int byte_counter = 0; + int i; + + /* Exit immediately if no result can be stored */ + if (!params) + return -EINVAL; + + /* Decode applicable SAPIs */ + rc = decode_hdrcomp_applicable_sapis(bytes, bytes_len, + params->nsapi, + ¶ms->nsapi_len); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + bytes += rc; + + /* Decode MAX_CID */ + rc = decode_hdrcomp_16_bit_field(bytes, bytes_len - byte_counter, + 0, 16383, ¶ms->max_cid, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + bytes += rc; + + /* Decode MAX_HEADER */ + rc = decode_hdrcomp_16_bit_field(bytes, bytes_len - byte_counter, + 60, 255, ¶ms->max_header, + NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + bytes += rc; + + /* Decode Profiles */ + for (i = 0; i < 16; i++) { + params->profile_len = 0; + rc = decode_hdrcomp_16_bit_field(bytes, + bytes_len - byte_counter, + 0, 65535, NULL, + ¶ms->profile[i]); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + bytes += rc; + params->profile_len = i + 1; + } + + /* Return consumed length */ + return byte_counter; +} + + +/* Decode V42bis parameter field */ +static int decode_datacomp_v42bis_params(const uint8_t * bytes, + unsigned int bytes_len, + struct + gprs_sndcp_datacomp_v42bis_params + *params) +{ + int rc; + int byte_counter = 0; + + /* Exit immediately if no result can be stored */ + if (!params) + return -EINVAL; + + /* Decode applicable SAPIs */ + rc = decode_hdrcomp_applicable_sapis(bytes, bytes_len, + params->nsapi, + ¶ms->nsapi_len); + if (rc > 0) { + byte_counter += rc; + bytes += rc; + } else + return byte_counter; + + /* Decode P0 */ + rc = decode_hdrcomp_8_bit_field(bytes, bytes_len - byte_counter, 0, + 3, ¶ms->p0, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + bytes += rc; + + /* Decode P1 */ + rc = decode_hdrcomp_16_bit_field(bytes, bytes_len - byte_counter, + 512, 65535, ¶ms->p1, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + bytes += rc; + + /* Decode P2 */ + rc = decode_hdrcomp_8_bit_field(bytes, bytes_len - byte_counter, 6, + 250, ¶ms->p2, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + bytes += rc; + + /* Return consumed length */ + return byte_counter; +} + + +/* Decode V44 parameter field */ +static int decode_datacomp_v44_params(const uint8_t * bytes, + unsigned int bytes_len, + struct gprs_sndcp_datacomp_v44_params + *params) +{ + int rc; + int byte_counter = 0; + + /* Exit immediately if no result can be stored */ + if (!params) + return -EINVAL; + + /* Decode applicable SAPIs */ + rc = decode_hdrcomp_applicable_sapis(bytes, bytes_len, + params->nsapi, + ¶ms->nsapi_len); + if (rc > 0) { + byte_counter += rc; + bytes += rc; + } else + return byte_counter; + + /* Decode C0 */ + rc = decode_hdrcomp_8_bit_field(bytes, bytes_len - byte_counter, 0, + 255, ¶ms->c0, NULL); + if (rc <= 0) + return byte_counter; + if ((params->c0 != 0x80) && (params->c0 != 0xC0)) + return -EINVAL; + byte_counter += rc; + bytes += rc; + + /* Decode P0 */ + rc = decode_hdrcomp_8_bit_field(bytes, bytes_len - byte_counter, 0, + 3, ¶ms->p0, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + bytes += rc; + + /* Decode P1T */ + rc = decode_hdrcomp_16_bit_field(bytes, bytes_len - byte_counter, + 265, 65535, ¶ms->p1t, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + bytes += rc; + + /* Decode P1R */ + rc = decode_hdrcomp_16_bit_field(bytes, bytes_len - byte_counter, + 265, 65535, ¶ms->p1r, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + bytes += rc; + + /* Decode P3T */ + rc = decode_hdrcomp_16_bit_field(bytes, bytes_len - byte_counter, + 265, 65535, ¶ms->p3t, NULL); + if (rc <= 0) + return byte_counter; + if (params->p3t < 2 * params->p1t) + return -EINVAL; + byte_counter += rc; + bytes += rc; + + /* Decode P3R */ + rc = decode_hdrcomp_16_bit_field(bytes, bytes_len - byte_counter, + 265, 65535, ¶ms->p3r, NULL); + if (rc <= 0) + return byte_counter; + if (params->p3r < 2 * params->p1r) + return -EINVAL; + byte_counter += rc; + bytes += rc; + + /* Return consumed length */ + return byte_counter; +} + + +/* Lookup algorithm identfier by entity ID */ +static int lookup_algorithm_identifier(int entity, + struct + gprs_sndcp_hdrcomp_entity_algo_table + *lt, unsigned int lt_len, + int compclass) +{ + int i; + if ((lt) && (lt_len > 0)) { + for (i = 0; i < lt_len; i++) { + if ((lt[i].entity == entity) + && (lt[i].compclass == compclass)) + return lt[i].algo; + } + } + + return -1; +} + +/* Decode data or protocol control information compression field */ +static int decode_comp_field(const uint8_t * bytes, unsigned int bytes_len, + struct gprs_sndcp_comp_field *comp_field, + struct + gprs_sndcp_hdrcomp_entity_algo_table + *lt, unsigned int lt_len, int compclass) +{ + int byte_counter = 0; + unsigned int len; + int i; + int rc; + + /* Exit immediately if it is clear that no + parseable data is present */ + if ((bytes_len < 1) || (!(bytes))) + return -EINVAL; + + /* Exit immediately if no result can be stored */ + if (!comp_field) + return -EINVAL; + + /* Zero out target struct */ + memset(comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + + /* Decode Propose bit and Entity number */ + if ((*bytes) & 0x80) + comp_field->p = 1; + comp_field->entity = (*bytes) & 0x1F; + byte_counter++; + bytes++; + + /* Decode algorithm number (if present) */ + if (comp_field->p) { + comp_field->algo = (*bytes) & 0x1F; + byte_counter++; + bytes++; + } + /* Alternatively take the information from the lookup table */ + else + comp_field->algo = + lookup_algorithm_identifier(comp_field->entity, lt, + lt_len, compclass); + + /* Decode length field */ + len = *bytes; + byte_counter++; + bytes++; + + + /* Decode PCOMP/DCOMP values */ + if (comp_field->p) { + /* Determine the number of expected PCOMP/DCOMP values */ + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + /* For protocol compression */ + switch (comp_field->algo) { + case RFC_1144: + comp_field->comp_len = RFC1144_PCOMP_LEN; + break; + case RFC_2507: + comp_field->comp_len = RFC2507_PCOMP_LEN; + break; + case ROHC: + comp_field->comp_len = ROHC_PCOMP_LEN; + break; + + /* Exit if the algorithem type encodes + something unknown / unspecified */ + default: + return -EINVAL; + } + } else { + /* For data compression */ + switch (comp_field->algo) { + case V42BIS: + comp_field->comp_len = V42BIS_DCOMP_LEN; + break; + case V44: + comp_field->comp_len = V44_DCOMP_LEN; + break; + + /* Exit if the algorithem type encodes + something unknown / unspecified */ + default: + return -EINVAL; + } + } + + for (i = 0; i < comp_field->comp_len; i++) { + if (i & 1) { + comp_field->comp[i] = (*bytes) & 0x0F; + bytes++; + byte_counter++; + len--; + } else + comp_field->comp[i] = + ((*bytes) >> 4) & 0x0F; + } + + if (i & 1) { + bytes++; + byte_counter++; + len--; + } + } + + /* Decode algorithm specific payload data */ + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + /* For protocol compression */ + switch (comp_field->algo) { + case RFC_1144: + comp_field->rfc1144_params = + talloc_zero(NULL, + struct + gprs_sndcp_hdrcomp_rfc1144_params); + rc = decode_hdrcomp_rfc1144_params(bytes, len, + comp_field-> + rfc1144_params); + break; + case RFC_2507: + comp_field->rfc2507_params = + talloc_zero(NULL, + struct + gprs_sndcp_hdrcomp_rfc2507_params); + rc = decode_hdrcomp_rfc2507_params(bytes, len, + comp_field-> + rfc2507_params); + break; + case ROHC: + comp_field->rohc_params = + talloc_zero(NULL, + struct + gprs_sndcp_hdrcomp_rohc_params); + rc = decode_hdrcomp_rohc_params(bytes, len, + comp_field-> + rohc_params); + break; + + /* If no suitable decoder is detected, + leave the remaining bytes undecoded */ + default: + rc = len; + } + } else { + /* For data compression */ + switch (comp_field->algo) { + case V42BIS: + comp_field->v42bis_params = + talloc_zero(NULL, + struct + gprs_sndcp_datacomp_v42bis_params); + rc = decode_datacomp_v42bis_params(bytes, len, + comp_field-> + v42bis_params); + break; + case V44: + comp_field->v44_params = + talloc_zero(NULL, + struct + gprs_sndcp_datacomp_v44_params); + rc = decode_datacomp_v44_params(bytes, len, + comp_field-> + v44_params); + break; + + /* If no suitable decoder is detected, + leave the remaining bytes undecoded */ + default: + rc = len; + } + } + + if (rc >= 0) + byte_counter += rc; + else + return -EINVAL; + + + /* Return consumed length */ + return byte_counter; +} + +/* Transform an SNDCP-XID message (bytes) into a list of SNDCP-XID fields */ +int gprs_sndcp_parse_xid(struct llist_head *comp_fields, uint8_t * bytes, + unsigned int bytes_len, + struct gprs_sndcp_hdrcomp_entity_algo_table + *lt, unsigned int lt_len) +{ + int bytes_pos = 0; + uint8_t tag; + uint16_t tag_len; + const uint8_t *val; + struct gprs_sndcp_comp_field *comp_field; + int rc; + int byte_counter = 0; + + /* Valid TLV-Tag and types */ + static const struct tlv_definition sndcp_xid_def = { + .def = { + [SNDCP_XID_VERSION_NUMBER] = {TLV_TYPE_TLV,}, + [SNDCP_XID_DATA_COMPRESSION] = {TLV_TYPE_TLV,}, + [SNDCP_XID_PROTOCOL_COMPRESSION] = {TLV_TYPE_TLV,}, + }, + }; + + /* Parse TLV-Encoded SNDCP-XID message and defer payload + to the apporpiate sub-parser functions */ + while (1) { + bytes_pos += + tlv_parse_one(&tag, &tag_len, &val, &sndcp_xid_def, + bytes + bytes_pos, + bytes_len - bytes_pos); + + /* Decode compression parameters */ + if ((tag == SNDCP_XID_PROTOCOL_COMPRESSION) + || (tag == SNDCP_XID_DATA_COMPRESSION)) { + byte_counter = 0; + do { + comp_field = + talloc_zero(NULL, + struct + gprs_sndcp_comp_field); + rc = decode_comp_field(val + byte_counter, + tag_len - + byte_counter, + comp_field, lt, + lt_len, tag); + + if (rc > 0) { + byte_counter += rc; + llist_add(&comp_field->list, + comp_fields); + } else { + talloc_free(comp_field); + return -EINVAL; + } + } + while (tag_len - byte_counter > 0); + } + + /* Stop when no further TLV elements can be expected */ + if (bytes_len - bytes_pos <= 2) + break; + } + + return 0; +} + +/* Free a list with SNDCP-XID fields */ +void gprs_sndcp_free_comp_fields(struct llist_head *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field; + + /* Exit immediately if no list is present */ + if (!(comp_fields)) + return; + + llist_for_each_entry(comp_field, comp_fields, list) { + if (comp_field->rfc1144_params) + talloc_free(comp_field->rfc1144_params); + if (comp_field->rfc2507_params) + talloc_free(comp_field->rfc2507_params); + if (comp_field->rohc_params) + talloc_free(comp_field->rohc_params); + if (comp_field->v42bis_params) + talloc_free(comp_field->v42bis_params); + if (comp_field->v44_params) + talloc_free(comp_field->v44_params); + + talloc_free(comp_field); + } +} + +/* Dump a list with SNDCP-XID fields (Debug) */ +void gprs_sndcp_dump_comp_fields(struct llist_head *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field; + int i; + int compclass; + + llist_for_each_entry(comp_field, comp_fields, list) { + LOGP(DSNDCP, LOGL_DEBUG, "SNDCP-XID:\n"); + LOGP(DSNDCP, LOGL_DEBUG, + "struct gprs_sndcp_comp_field {\n"); + LOGP(DSNDCP, LOGL_DEBUG, " p=%i;\n", comp_field->p); + LOGP(DSNDCP, LOGL_DEBUG, " entity=%i;\n", + comp_field->entity); + LOGP(DSNDCP, LOGL_DEBUG, " algo=%i;\n", + comp_field->algo); + LOGP(DSNDCP, LOGL_DEBUG, " comp_len=%i;\n", + comp_field->comp_len); + if (comp_field->comp_len == 0) + LOGP(DSNDCP, LOGL_DEBUG, " comp[] = NULL;\n"); + for (i = 0; i < comp_field->comp_len; i++) + LOGP(DSNDCP, LOGL_DEBUG, " comp[%i]=%i;\n", i, + comp_field->comp[i]); + + compclass = gprs_sndcp_get_compression_class(comp_field); + + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + switch (comp_field->algo) { + case RFC_1144: + LOGP(DSNDCP, LOGL_DEBUG, + " gprs_sndcp_hdrcomp_rfc1144_params {\n"); + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi_len=%i;\n", + comp_field->rfc1144_params-> + nsapi_len); + if (comp_field->rfc1144_params-> + nsapi_len == 0) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[] = NULL;\n"); + for (i = 0; + i < + comp_field->rfc1144_params->nsapi_len; + i++) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[%i]=%i;\n", i, + comp_field->rfc1144_params-> + nsapi[i]); + LOGP(DSNDCP, LOGL_DEBUG, " s01=%i;\n", + comp_field->rfc1144_params->s01); + LOGP(DSNDCP, LOGL_DEBUG, " }\n"); + break; + case RFC_2507: + LOGP(DSNDCP, LOGL_DEBUG, + " gprs_sndcp_hdrcomp_rfc2507_params {\n"); + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi_len=%i;\n", + comp_field->rfc2507_params-> + nsapi_len); + if (comp_field->rfc2507_params-> + nsapi_len == 0) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[] = NULL;\n"); + for (i = 0; + i < + comp_field->rfc2507_params->nsapi_len; + i++) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[%i]=%i;\n", i, + comp_field->rfc2507_params-> + nsapi[i]); + LOGP(DSNDCP, LOGL_DEBUG, + " f_max_period=%i;\n", + comp_field->rfc2507_params-> + f_max_period); + LOGP(DSNDCP, LOGL_DEBUG, + " f_max_time=%i;\n", + comp_field->rfc2507_params-> + f_max_time); + LOGP(DSNDCP, LOGL_DEBUG, + " max_header=%i;\n", + comp_field->rfc2507_params-> + max_header); + LOGP(DSNDCP, LOGL_DEBUG, + " tcp_space=%i;\n", + comp_field->rfc2507_params-> + tcp_space); + LOGP(DSNDCP, LOGL_DEBUG, + " non_tcp_space=%i;\n", + comp_field->rfc2507_params-> + non_tcp_space); + LOGP(DSNDCP, LOGL_DEBUG, " }\n"); + break; + case ROHC: + LOGP(DSNDCP, LOGL_DEBUG, + " gprs_sndcp_hdrcomp_rohc_params {\n"); + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi_len=%i;\n", + comp_field->rohc_params->nsapi_len); + if (comp_field->rohc_params->nsapi_len == + 0) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[] = NULL;\n"); + for (i = 0; + i < + comp_field->rohc_params->nsapi_len; + i++) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[%i]=%i;\n", i, + comp_field->rohc_params-> + nsapi[i]); + LOGP(DSNDCP, LOGL_DEBUG, + " max_cid=%i;\n", + comp_field->rohc_params->max_cid); + LOGP(DSNDCP, LOGL_DEBUG, + " max_header=%i;\n", + comp_field->rohc_params->max_header); + if (comp_field->rohc_params->profile_len == + 0) + LOGP(DSNDCP, LOGL_DEBUG, + " profile[] = NULL;\n"); + for (i = 0; + i < + comp_field->rohc_params->profile_len; + i++) + LOGP(DSNDCP, LOGL_DEBUG, + " profile[%i]=%04x;\n", + i, + comp_field->rohc_params-> + profile[i]); + LOGP(DSNDCP, LOGL_DEBUG, " }\n"); + break; + } + } else if (compclass == SNDCP_XID_DATA_COMPRESSION) { + switch (comp_field->algo) { + case V42BIS: + LOGP(DSNDCP, LOGL_DEBUG, + " gprs_sndcp_datacomp_v42bis_params {\n"); + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi_len=%i;\n", + comp_field->v42bis_params->nsapi_len); + if (comp_field->v42bis_params->nsapi_len == + 0) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[] = NULL;\n"); + for (i = 0; + i < + comp_field->v42bis_params->nsapi_len; + i++) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[%i]=%i;\n", i, + comp_field->v42bis_params-> + nsapi[i]); + LOGP(DSNDCP, LOGL_DEBUG, " p0=%i;\n", + comp_field->v42bis_params->p0); + LOGP(DSNDCP, LOGL_DEBUG, " p1=%i;\n", + comp_field->v42bis_params->p1); + LOGP(DSNDCP, LOGL_DEBUG, " p2=%i;\n", + comp_field->v42bis_params->p2); + LOGP(DSNDCP, LOGL_DEBUG, " }\n"); + break; + case V44: + LOGP(DSNDCP, LOGL_DEBUG, + " gprs_sndcp_datacomp_v44_params {\n"); + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi_len=%i;\n", + comp_field->v44_params->nsapi_len); + if (comp_field->v44_params->nsapi_len == 0) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[] = NULL;\n"); + for (i = 0; + i < comp_field->v44_params->nsapi_len; + i++) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[%i]=%i;\n", i, + comp_field->v44_params-> + nsapi[i]); + LOGP(DSNDCP, LOGL_DEBUG, " c0=%i;\n", + comp_field->v44_params->c0); + LOGP(DSNDCP, LOGL_DEBUG, " p0=%i;\n", + comp_field->v44_params->p0); + LOGP(DSNDCP, LOGL_DEBUG, " p1t=%i;\n", + comp_field->v44_params->p1t); + LOGP(DSNDCP, LOGL_DEBUG, " p1r=%i;\n", + comp_field->v44_params->p1r); + LOGP(DSNDCP, LOGL_DEBUG, " p3t=%i;\n", + comp_field->v44_params->p3t); + LOGP(DSNDCP, LOGL_DEBUG, " p3r=%i;\n", + comp_field->v44_params->p3r); + LOGP(DSNDCP, LOGL_DEBUG, " }\n"); + break; + } + } + + LOGP(DSNDCP, LOGL_DEBUG, "}\n"); + LOGP(DSNDCP, LOGL_DEBUG, "\n"); + } + +} -- To view, visit https://gerrit.osmocom.org/641 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter From gerrit-no-reply at lists.osmocom.org Mon Aug 1 15:51:46 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Mon, 1 Aug 2016 15:51:46 +0000 Subject: [PATCH] openbsc[master]: Added code to control GPRS TCP/IP header compression. Message-ID: Review at https://gerrit.osmocom.org/642 Added code to control GPRS TCP/IP header compression. In this commit two modules were added: gprs_sndcp_comp_entity.h/c: This part handles the creation and destruction of conpression entites. It handles the allocation and freeing of the memory and offers functions to query compression parameters (i.e. which compression entity should be used if a packet from NSAPI x has to be compressed?) gprs_sndcp_hdrcomp.c/h: This is the code that performs the actual header compression. It takes care that the packets are compressed/decompressed with the right modes etc. It works, but is not yet ready for merging. Both files depend on each other so that they only can be merged both at the same time. Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 --- M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_sndcp_comp_entity.h A openbsc/include/openbsc/gprs_sndcp_hdrcomp.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_sndcp_comp_entity.c A openbsc/src/gprs/gprs_sndcp_hdrcomp.c 6 files changed, 1,017 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/42/642/1 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index b37103f..e159db5 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,8 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h gprs_sndcp_xid.h + gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h gprs_sndcp_xid.h \ + gprs_sndcp_comp_entity.h gprs_sndcp_hdrcomp.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_sndcp_comp_entity.h b/openbsc/include/openbsc/gprs_sndcp_comp_entity.h new file mode 100644 index 0000000..677b82d --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_comp_entity.h @@ -0,0 +1,91 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_SNDCP_COMP_ENTITY_H +#define _GPRS_SNDCP_COMP_ENTITY_H + +#include +#include +#include + +/* Header / Data compression entity */ +struct gprs_sndcp_comp_entity +{ + struct llist_head list; + + /* Serves as an ID in case we want to delete this entity later */ + int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + + /* Specifies to which NSAPIs the compression entity is assigned */ + int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + int nsapi[11]; /* Applicable NSAPIs (default 0) */ + + /* Assigned pcomp values */ + int comp_len; /* Number of contained PCOMP / DCOMP values */ + int comp[16]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */ + + /* Algorithm parameters */ + int algo; /* Algorithm type (see gprs_sndcp_xid.h) */ + int compclass; /* See gprs_sndcp_xid.h/c */ + void *status; /* Algorithm status and parameters */ +}; + +/* Free a list with compression entities */ +void gprs_sndcp_comp_entities_free (struct llist_head *comp_entities); + +/* Delete a compression entity */ +void gprs_sndcp_comp_entities_delete (struct llist_head *comp_entities, + int entity); + +/* Create and Add a new compression entity +(returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entities_add (struct llist_head *comp_entities, + struct gprs_sndcp_comp_field *comp_field); + +/* Find compression entity by its entity number */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_entity (struct llist_head*comp_entities, + int entity); + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_comp (struct llist_head *comp_entities, + int comp); + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_nsapi (struct llist_head *comp_entities, + int nsapi); + +/* Find a comp_index for a given pcomp/dcomp value */ +int +gprs_sndcp_comp_entity_find_comp_index_by_comp (struct gprs_sndcp_comp_entity + *comp_entity, int comp); + +/* Find a pcomp/dcomp value for a given comp_index */ +int +gprs_sndcp_comp_entity_find_comp_by_comp_index (struct gprs_sndcp_comp_entity + *comp_entity, + int comp_index); + +#endif diff --git a/openbsc/include/openbsc/gprs_sndcp_hdrcomp.h b/openbsc/include/openbsc/gprs_sndcp_hdrcomp.h new file mode 100644 index 0000000..e73bad1 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_hdrcomp.h @@ -0,0 +1,68 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_SNDCP_HDRCOMP_H +#define _GPRS_SNDCP_HDRCOMP_H + +#include +#include +#include + +/* 1=Bypass any header compression, 0=Normal */ +#define GPRS_SNDCP_HDRCOMP_BYPASS 0 + +/* Header compression entity */ +struct gprs_sndcp_hdrcomp_compression_entity { + + /* Specifies to which NSAPIs the compression entity is assigned */ + int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + int nsapi[11]; /* Applicable NSAPIs (default 0) */ + + /* Assigned pcomp values */ + int pcomp_len; /* Number of contained PCOMP / DCOMP values */ + int pcomp[16]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */ + + /* Algorithm parameters */ + int compclass; /* 1=Header compression, 2=Data compression */ + int algo; /* Algorithm type (see gprs_sndcp_xid.h) */ + void *status; /* Algorithm status and parameters */ +}; + + +/* Initalize header compression */ +int gprs_sndcp_hdrcomp_init(struct gprs_sndcp_comp_entity *comp_entity, + struct gprs_sndcp_comp_field *comp_field); + +/* Terminate header compression */ +void gprs_sndcp_hdrcomp_term(struct gprs_sndcp_comp_entity *comp_entity); + +/* Expand header compressed packet */ +int gprs_sndcp_hdrcomp_expand(uint8_t * packet, int packet_len, int pcomp, + struct llist_head *comp_entities); + +/* Expand header compressed packet */ +int gprs_sndcp_hdrcomp_compress(uint8_t * packet, int packet_len, + int *pcomp, + struct llist_head *comp_entities, + int nsapi); + +#endif diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 67e9943..3d6c82a 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -21,7 +21,8 @@ $(OSMO_LIBS) $(LIBCRYPTO_LIBS) -lrt osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \ - slhc.c gprs_sndcp_xid.c \ + slhc.c gprs_sndcp_xid.c gprs_sndcp_comp_entity.c \ + gprs_sndcp_hdrcomp.c \ sgsn_main.c sgsn_vty.c sgsn_libgtp.c \ gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c \ gprs_llc_xid.c crc24.c \ diff --git a/openbsc/src/gprs/gprs_sndcp_comp_entity.c b/openbsc/src/gprs/gprs_sndcp_comp_entity.c new file mode 100644 index 0000000..380b2f0 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_comp_entity.c @@ -0,0 +1,331 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +/* Create a new compression entity from a XID-Field */ +static struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_create (struct gprs_sndcp_comp_field *comp_field) +{ + struct gprs_sndcp_comp_entity *comp_entity; + comp_entity = talloc_zero (NULL, struct gprs_sndcp_comp_entity); + + /* Copy relevant information from the SNDCP-XID field */ + comp_entity->entity = comp_field->entity; + comp_entity->comp_len = comp_field->comp_len; + memcpy (comp_entity->comp, comp_field->comp, + comp_field->comp_len * sizeof (int)); + + if (comp_field->rfc1144_params) { + comp_entity->nsapi_len = + comp_field->rfc1144_params->nsapi_len; + memcpy (comp_entity->nsapi, + comp_field->rfc1144_params->nsapi, + comp_entity->nsapi_len * sizeof (int)); + } + else if (comp_field->rfc2507_params) { + comp_entity->nsapi_len = + comp_field->rfc2507_params->nsapi_len; + memcpy (comp_entity->nsapi, + comp_field->rfc2507_params->nsapi, + comp_entity->nsapi_len * sizeof (int)); + } + else if (comp_field->rohc_params) { + comp_entity->nsapi_len = comp_field->rohc_params->nsapi_len; + memcpy (comp_entity->nsapi, comp_field->rohc_params->nsapi, + comp_entity->nsapi_len * sizeof (int)); + } + else if (comp_field->v42bis_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy (comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + comp_entity->nsapi_len * sizeof (int)); + } + else if (comp_field->v44_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy (comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + comp_entity->nsapi_len * sizeof (int)); + } + else { + talloc_free (comp_entity); + LOGP (DSNDCP, LOGL_ERROR, + "Comp field contained invalid parameters, compression entity not created!\n"); + return NULL; + } + + comp_entity->algo = comp_field->algo; + comp_entity->status = NULL; + + /* Determine of which class our compression entity will be + (Protocol or Data compresson ?) */ + comp_entity->compclass = + gprs_sndcp_get_compression_class (comp_field); + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + if (gprs_sndcp_hdrcomp_init (comp_entity, comp_field) == 0) + LOGP (DSNDCP, LOGL_INFO, + "New header compression entity (%i) created.\n", + comp_entity->entity); + else { + talloc_free (comp_entity); + LOGP (DSNDCP, LOGL_ERROR, + "Header compression entity (%i) creation failed!\n", + comp_entity->entity); + return NULL; + } + } + else + LOGP (DSNDCP, LOGL_INFO, + "New data compression entity (%i) created.\n", + comp_entity->entity); + + return comp_entity; +} + +/* Free a list with compression entities */ +void +gprs_sndcp_comp_entities_free (struct llist_head *comp_entities) +{ + if (comp_entities) { + struct gprs_sndcp_comp_entity *comp_entity; + + llist_for_each_entry (comp_entity, comp_entities, list) { + /* Free compression entity */ + if (comp_entity->compclass == + SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP (DSNDCP, LOGL_INFO, + "Deleting (free) header compression entity %i ...\n", + comp_entity->entity); + gprs_sndcp_hdrcomp_term (comp_entity); + } + else + LOGP (DSNDCP, LOGL_INFO, + "Deleting (free) data compression entity %i ...\n", + comp_entity->entity); + + talloc_free (comp_entity); + } + + } +} + +/* Delete a compression entity */ +void +gprs_sndcp_comp_entities_delete (struct llist_head *comp_entities, int entity) +{ + struct gprs_sndcp_comp_entity *comp_entity; + struct gprs_sndcp_comp_entity *comp_entity_to_delete = NULL; + + if (comp_entities) { + + llist_for_each_entry (comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) + comp_entity_to_delete = comp_entity; + } + + if (comp_entity_to_delete) { + if (comp_entity_to_delete->compclass == + SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP (DSNDCP, LOGL_INFO, + "Deleting header compression entity %i ...\n", + comp_entity_to_delete->entity); + gprs_sndcp_hdrcomp_term + (comp_entity_to_delete); + } + else + LOGP (DSNDCP, LOGL_INFO, + "Deleting data compression entity %i ...\n", + comp_entity_to_delete->entity); + + /* Delete compression entity */ + llist_del (&comp_entity_to_delete->list); + talloc_free (comp_entity_to_delete); + } + } +} + +/* Create and Add a new compression entity +(returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entities_add (struct + llist_head + *comp_entities, struct + gprs_sndcp_comp_field *comp_field) +{ + struct gprs_sndcp_comp_entity *comp_entity; + + /* Just to be sure, if the entity is already in + the list it will be deleted now */ + gprs_sndcp_comp_entities_delete (comp_entities, comp_field->entity); + + /* Create and add a new entity to the list */ + comp_entity = gprs_sndcp_comp_entity_create (comp_field); + + if (comp_entity) { + llist_add (&comp_entity->list, comp_entities); + return comp_entity; + } + + return NULL; +} + +/* Find compression entity by its entity number */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_entity (struct + llist_head *comp_entities, int entity) +{ + struct gprs_sndcp_comp_entity *comp_entity; + + if (comp_entities) { + llist_for_each_entry (comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) + return comp_entity; + } + } + + LOGP (DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given entity number %i.\n", + entity); + return NULL; +} + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_comp (struct + llist_head *comp_entities, int comp) +{ + struct gprs_sndcp_comp_entity *comp_entity; + int i; + + if (comp_entities) { + llist_for_each_entry (comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return comp_entity; + } + } + } + + LOGP (DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given pcomp/dcomp value %i.\n", + comp); + return NULL; +} + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_nsapi (struct + llist_head *comp_entities, int nsapi) +{ + struct gprs_sndcp_comp_entity *comp_entity; + int i; + + if (comp_entities) { + llist_for_each_entry (comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->nsapi_len; i++) { + if (comp_entity->nsapi[i] == nsapi) + return comp_entity; + } + } + + LOGP (DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given nsapi value %i\n", + nsapi); + return NULL; + } + + LOGP (DSNDCP, LOGL_ERROR, + "Compression entity list contained null-pointer!\n"); + return NULL; +} + +/* Find a comp_index for a given pcomp/dcomp value */ +int +gprs_sndcp_comp_entity_find_comp_index_by_comp (struct + gprs_sndcp_comp_entity + *comp_entity, int comp) +{ + int i; + + if (comp_entity) { + /* A pcomp/dcomp field set to zero always disables + all sort of compression and is assigned fix. So we + just return zero in this case */ + if (comp == 0) + return 0; + + /* Look in the pcomp/dcomp list for the index */ + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return i + 1; + } + + LOGP (DSNDCP, LOGL_ERROR, + "Could not find a matching comp_index for given pcomp/dcomp value %i\n", + comp); + return 0; + } + + LOGP (DSNDCP, LOGL_ERROR, + "Compression entity contained null-pointer!\n"); + return 0; +} + +/* Find a pcomp/dcomp value for a given comp_index */ +int +gprs_sndcp_comp_entity_find_comp_by_comp_index (struct + gprs_sndcp_comp_entity + *comp_entity, int comp_index) +{ + if (comp_entity) { + /* A comp_index of zero translates to zero right away. */ + if (comp_index == 0) + return 0; + + if (comp_index > comp_entity->comp_len) { + LOGP (DSNDCP, LOGL_ERROR, + "Could not find a matching pcomp/dcomp value for given comp_index value %i.\n", + comp_index); + return 0; + } + + /* Look in the pcomp/dcomp list for the comp_index */ + return comp_entity->comp[comp_index - 1]; + } + + LOGP (DSNDCP, LOGL_ERROR, + "Compression entity contained null-pointer!\n"); + return 0; +} diff --git a/openbsc/src/gprs/gprs_sndcp_hdrcomp.c b/openbsc/src/gprs/gprs_sndcp_hdrcomp.c new file mode 100644 index 0000000..8796684 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_hdrcomp.c @@ -0,0 +1,523 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* Enable private debug messages */ +#define GPRS_SNDCP_HDRCOMP_DEBUG 1 + +/* Test RFC1144 implementation + (Caution: GPRS_SNDCP_HDRCOMP_BYPASS in .h file has to be set to 1!) */ +#define GPRS_SNDCP_HDRCOMP_RFC1144_TEST 0 + +/* Exit immediately in case of RFC1144 test failure */ +#define GPRS_SNDCP_HDRCOMP_RFC1144_TEST_EXITONERR 1 + +/* For debug/test only! */ +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST == 1 +static struct slcompress *test_compression_state_tx = NULL; +static struct slcompress *test_compression_state_rx = NULL; +static int test_errors = 0; +static int gprs_sndcp_hdrcomp_test_ind(uint8_t * packet, int packet_len); +static int gprs_sndcp_hdrcomp_test_req(uint8_t * packet, int packet_len); +#endif + + +/* Initalize header compression */ +int gprs_sndcp_hdrcomp_init(struct gprs_sndcp_comp_entity *comp_entity, + struct gprs_sndcp_comp_field *comp_field) +{ + /* Note: This function is automatically called from + gprs_sndcp_comp_entity.c when a new header compression + entity is created by gprs_sndcp.c */ + + if ((comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + && (comp_entity->algo == RFC_1144)) { + comp_entity->status = + slhc_init(comp_field->rfc1144_params->s01 + 1, + comp_field->rfc1144_params->s01 + 1); + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression initalized.\n"); + return 0; + } + + /* Just in case someone tries to initalize an unknown or unsupported + header compresson. Since everything is checked during the SNDCP + negotiation process, this should never happen! */ + LOGP(DSNDCP, LOGL_ERROR, + "Unknown or unsupported header compression type requested for initalization, could not initalize...\n"); + return -EINVAL; + +} + + +/* Terminate header compression */ +void gprs_sndcp_hdrcomp_term(struct gprs_sndcp_comp_entity *comp_entity) +{ + /* Note: This function is automatically called from + gprs_sndcp_comp_entity.c when a header compression + entity is deleted by gprs_sndcp.c */ + + if ((comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + && (comp_entity->algo == RFC_1144)) { + if (comp_entity->status) { + slhc_free((struct slcompress *) comp_entity-> + status); + comp_entity->status = NULL; + } + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression terminated.\n"); + return; + } + + /* Just in case someone tries to initalize an unknown or unsupported + header compresson. Since everything is checked during the SNDCP + negotiation process, this should never happen! */ + LOGP(DSNDCP, LOGL_ERROR, + "Unknown or unsupported header compression type requested for termiation, could not initalize...\n"); +} + + +/* Display compressor status */ +static void gprs_sndcp_hdrcomp_rfc1144_stat(struct slcompress *comp) +{ + slhc_i_status(comp); + slhc_o_status(comp); +} + + +/* Compress a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_hdrcomp_rfc1144_compress(struct slcompress *comp, + uint8_t * packet, + int packet_len, + int *pcomp_index) +{ + uint8_t *packet_compressed; + uint8_t *packet_compressed_ptr; /* Not used */ + int packet_compressed_len; + + /* Reserve some space for to store the compression result */ + packet_compressed = talloc_zero_size(NULL, packet_len); + + /* Run compressor */ + memcpy(packet_compressed, packet, packet_len); + packet_compressed_len = + slhc_compress(comp, packet, packet_len, + (uint8_t *) packet_compressed, + &packet_compressed_ptr, 0); + + /* Copy back compression result */ + memcpy(packet, packet_compressed, packet_len); + talloc_free(packet_compressed); + + /* Generate pcomp_index */ + if ((packet[0] & SL_TYPE_COMPRESSED_TCP) == SL_TYPE_COMPRESSED_TCP) { + *pcomp_index = 2; + /* Remove tag for compressed TCP, because the packet + type is already define by pcomp */ + // packet[0] &= 0x7F; + } else if ((packet[0] & SL_TYPE_UNCOMPRESSED_TCP) == + SL_TYPE_UNCOMPRESSED_TCP) { + *pcomp_index = 1; + + /* Remove tag for uncompressed TCP, because the + packet type is already define by pcomp */ + packet[0] &= 0x4F; + } else + *pcomp_index = 0; + + return packet_compressed_len; +} + +/* Expand a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_hdrcomp_rfc1144_expand(struct slcompress *comp, + uint8_t * packet, + int packet_len, + int pcomp_index) +{ + int packet_decompressed_len; + int type = -1; + + /* Note: this function should never be called with pcomp_index=0, + since this condition is already filtered + out by gprs_sndcp_hdrcomp_expand() */ + + /* Determine the packet type by the PCOMP index */ + switch (pcomp_index) { + case 1: + type = SL_TYPE_UNCOMPRESSED_TCP; + break; + case 2: + type = SL_TYPE_COMPRESSED_TCP; + break; + } + + /* Restore the original version nibble on + marked uncompressed packets */ + if (type == SL_TYPE_UNCOMPRESSED_TCP) { + LOGP(DSNDCP, LOGL_INFO, + "Uncompressed rfc1144 packet received...\n"); + + + /* Just in case the phone tags uncompressed tcp-packets + (normally this is handled by pcomp so there is + no need for tagging the packets) */ + packet[0] &= 0x4F; + packet_decompressed_len = + slhc_remember(comp, packet, packet_len); + return packet_decompressed_len; + } + + /* Uncompress compressed packets */ + else if (type == SL_TYPE_COMPRESSED_TCP) { + LOGP(DSNDCP, LOGL_INFO, + "Compressed rfc1144 packet received...\n"); + packet_decompressed_len = + slhc_uncompress(comp, packet, packet_len); + return packet_decompressed_len; + } + + + /* Regular or unknown packets will not be touched */ + return packet_len; +} + + +/* Expand header compressed packet */ +int gprs_sndcp_hdrcomp_expand(uint8_t * packet, int packet_len, int pcomp, + struct llist_head *comp_entities) +{ + int rc; + int pcomp_index = 0; + struct gprs_sndcp_comp_entity *comp_entity; + + /* Skip on pcomp=0 */ + if (pcomp == 0) { + LOGP(DSNDCP, LOGL_INFO, + "Uncompressed packet received (pcomp=0), skipping compression...\n"); + return packet_len; + } + + /* Find out which compression entity handles the packet */ + comp_entity = + gprs_sndcp_comp_entity_find_by_comp(comp_entities, pcomp); + + /* Skip compression if no suitable compression entity can be found! */ + if (comp_entity == NULL) { + LOGP(DSNDCP, LOGL_ERROR, + "Compressed packet received (pcomp=%i) but no suitable compression entity found, skipping compression...\n", + pcomp); + return packet_len; + } + + /* Find pcomp_index */ + pcomp_index = + gprs_sndcp_comp_entity_find_comp_index_by_comp(comp_entity, + pcomp); + +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST == 1 + /* Test mode */ + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_expand(): testing compression...!\n"); + rc = gprs_sndcp_hdrcomp_test_ind(packet, packet_len); +#else + /* Normal operation: */ + rc = gprs_sndcp_hdrcomp_rfc1144_expand((struct slcompress *) + comp_entity->status, packet, + packet_len, pcomp_index); + gprs_sndcp_hdrcomp_rfc1144_stat((struct slcompress *) comp_entity-> + status); +#endif + + LOGP(DSNDCP, LOGL_DEBUG, + "Header expansion done, old length=%i, new length=%i, pcomp=%i, pcomp_index=%i\n", + packet_len, rc, pcomp, pcomp_index); + return rc; +} + + +/* Expand header compressed packet */ +int gprs_sndcp_hdrcomp_compress(uint8_t * packet, int packet_len, + int *pcomp, + struct llist_head *comp_entities, + int nsapi) +{ + int rc; + int pcomp_index = 0; + struct gprs_sndcp_comp_entity *comp_entity; + + /* Find out which compression entity handles the packet */ + comp_entity = + gprs_sndcp_comp_entity_find_by_nsapi(comp_entities, nsapi); + + /* Skip compression if no suitable compression entity can be found! */ + if (comp_entity == NULL) { + LOGP(DSNDCP, LOGL_INFO, + "No suitable compression entity found for nsapi %i, skipping compression...\n", + nsapi); + *pcomp = 0; + return packet_len; + } +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST == 1 + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_expand(): testing compression...!\n"); + rc = gprs_sndcp_hdrcomp_test_req(packet, packet_len); + *pcomp = 0; + return rc; +#else + /* Normal operation: */ + rc = gprs_sndcp_hdrcomp_rfc1144_compress((struct slcompress *) + comp_entity->status, + packet, packet_len, + &pcomp_index); + gprs_sndcp_hdrcomp_rfc1144_stat((struct slcompress *) comp_entity-> + status); +#endif + + /* Find pcomp value */ + *pcomp = + gprs_sndcp_comp_entity_find_comp_by_comp_index(comp_entity, + pcomp_index); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header compression done, old length=%i, new length=%i, pcomp=%i, pcomp_index=%i\n", + packet_len, rc, *pcomp, pcomp_index); + return rc; +} + + + + + + + +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST == 1 + +/* + * This is a test implementation to make sure the rfc1144 compression + * implementation works as expected. All data is first compressed and + * decompressed on both directions. + */ + +/* FIXME: FOR EXPERIMENTATION ONLY! REMOVE AS SOON AS POSSIBLE */ +static uint16_t header_checksum(uint8_t * iph, unsigned int ihl) +{ + int i; + uint16_t temp; + uint32_t accumulator = 0xFFFF; + + for (i = 0; i < ihl * 2; i++) { + temp = ((*iph) << 8) & 0xFF00; + iph++; + temp |= (*iph) & 0xFF; + iph++; + + accumulator += temp; + if (accumulator > 0xFFFF) { + accumulator++; + accumulator &= 0xFFFF; + } + } + + return (uint16_t) (htons(~accumulator) & 0xFFFF); +} + +/* Check packet integrity */ +static int gprs_sndcp_hdrcomp_test_check_packet(uint8_t * packet, + uint8_t * packet_backup, + int packet_len, + int + packet_len_uncompressed) +{ + uint16_t checksum; + + if (packet_len != packet_len_uncompressed) { + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): Error: Packet length mismatch!\n"); +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST_EXITONERR == 1 + exit(1); +#endif + return -1; + } + + /* Check packet integrety */ + if (memcmp(packet, packet_backup, packet_len)) { + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): Warning: Packet content!\n"); + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): %s\n", + osmo_hexdump_nospc(packet_backup, 80)); + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): %s\n", + osmo_hexdump_nospc(packet, 80)); + + checksum = header_checksum(packet, 5); + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): %04x\n", + checksum); + + if (checksum == 0x0000) { + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): Checksum looks good!\n"); + + if (memcmp + (packet + 20, packet_backup + 20, + packet_len - 20)) + test_errors++; + else + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): Packet looks also good!\n"); + } else { + test_errors++; +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST_EXITONERR == 1 + exit(1); +#endif + return -1; + } + } + + return 0; +} + +/* FIXME: FOR EXPERIMENTATION ONLY! REMOVE AS SOON AS POSSIBLE */ +static int gprs_sndcp_hdrcomp_test_ind(uint8_t * packet, int packet_len) +{ + int packet_len_compressed; + int packet_len_uncompressed; + int pcomp; + uint8_t *packet_backup; + + if (test_compression_state_tx == NULL) + test_compression_state_tx = slhc_init(8, 8); + if (test_compression_state_rx == NULL) + test_compression_state_rx = slhc_init(8, 8); + + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): packet_len=%i\n", packet_len); + packet_backup = talloc_zero_size(NULL, packet_len); + memcpy(packet_backup, packet, packet_len); + + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): IND: %s\n", + osmo_hexdump_nospc(packet, packet_len)); + packet_len_compressed = + gprs_sndcp_hdrcomp_rfc1144_compress(test_compression_state_rx, + packet, packet_len, + &pcomp); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): IND (COMP): %s\n", + osmo_hexdump_nospc(packet, packet_len_compressed)); + packet_len_uncompressed = + gprs_sndcp_hdrcomp_rfc1144_expand(test_compression_state_tx, + packet, + packet_len_compressed, + pcomp); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): IND (DECOMP): %s\n", + osmo_hexdump_nospc(packet, packet_len_uncompressed)); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): packet_len=%i packet_len_compressed=%i packet_len_uncompressed=%i\n", + packet_len, packet_len_compressed, packet_len_uncompressed); + + gprs_sndcp_hdrcomp_test_check_packet(packet, packet_backup, + packet_len, + packet_len_uncompressed); + talloc_free(packet_backup); + gprs_sndcp_hdrcomp_rfc1144_stat(test_compression_state_rx); + gprs_sndcp_hdrcomp_rfc1144_stat(test_compression_state_tx); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): Test errors: %i\n", + test_errors); + return packet_len; +} + +/* FIXME: FOR EXPERIMENTATION ONLY! REMOVE AS SOON AS POSSIBLE */ +static int gprs_sndcp_hdrcomp_test_req(uint8_t * packet, int packet_len) +{ + int packet_len_compressed; + int packet_len_uncompressed; + int pcomp; + uint8_t *packet_backup; + + if (test_compression_state_tx == NULL) + test_compression_state_tx = slhc_init(8, 8); + if (test_compression_state_rx == NULL) + test_compression_state_rx = slhc_init(8, 8); + + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_req(): packet_len=%i\n", packet_len); + packet_backup = talloc_zero_size(NULL, packet_len); + memcpy(packet_backup, packet, packet_len); + + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_req(): REQ: %s\n", + osmo_hexdump_nospc(packet, packet_len)); + packet_len_compressed = + gprs_sndcp_hdrcomp_rfc1144_compress(test_compression_state_tx, + packet, packet_len, + &pcomp); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_req(): REQ (COMP): %s\n", + osmo_hexdump_nospc(packet, packet_len_compressed)); + packet_len_uncompressed = + gprs_sndcp_hdrcomp_rfc1144_expand(test_compression_state_rx, + packet, + packet_len_compressed, + pcomp); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_req(): REQ (DECOMP): %s\n", + osmo_hexdump_nospc(packet, packet_len_uncompressed)); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_req(): packet_len=%i packet_len_compressed=%i packet_len_uncompressed=%i\n", + packet_len, packet_len_compressed, packet_len_uncompressed); + + gprs_sndcp_hdrcomp_test_check_packet(packet, packet_backup, + packet_len, + packet_len_uncompressed); + talloc_free(packet_backup); + gprs_sndcp_hdrcomp_rfc1144_stat(test_compression_state_rx); + gprs_sndcp_hdrcomp_rfc1144_stat(test_compression_state_tx); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): Test errors: %i\n", + test_errors); + return packet_len; +} + +#endif -- To view, visit https://gerrit.osmocom.org/642 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter From gerrit-no-reply at lists.osmocom.org Mon Aug 1 16:07:46 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 1 Aug 2016 16:07:46 +0000 Subject: openbsc[master]: Use random operation id In-Reply-To: References: Message-ID: Patch Set 2: Code-Review+1 assuming all of daniels comments are addressed, looks fine to me. -- To view, visit https://gerrit.osmocom.org/640 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I87d9ee0e9a87f58702c60bb141c973d41fa06997 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: daniel Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 1 16:38:56 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Mon, 1 Aug 2016 16:38:56 +0000 Subject: [PATCH] openbsc[master]: Added V42BIS implementation Message-ID: Review at https://gerrit.osmocom.org/643 Added V42BIS implementation V42BIS is a data compression method found in modems. It has also been specified for GPRS as data compression algorithm. The implementation has been taken from SPANDSP. There are several sources around. Asterisk and Freeswitch are using SPANDSP and its also available separately. The implementation in this commit has been taken from: https://github.com/jart/spandsp.git commit 6de1983b251806d59bb3149b7a2d7ebc99ace5aa Change-Id: Iabedece9f97ca944a1e3f747bb073e532c4e9dca --- A openbsc/include/openbsc/private_v42bis.h A openbsc/include/openbsc/v42bis.h A openbsc/src/gprs/v42bis.c 3 files changed, 996 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/43/643/1 diff --git a/openbsc/include/openbsc/private_v42bis.h b/openbsc/include/openbsc/private_v42bis.h new file mode 100644 index 0000000..96538f2 --- /dev/null +++ b/openbsc/include/openbsc/private_v42bis.h @@ -0,0 +1,151 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * private/v42bis.h + * + * Written by Steve Underwood + * + * Copyright (C) 2005 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: v42bis.h,v 1.1 2008/11/15 14:43:08 steveu Exp $ + */ + +#if !defined(_SPANDSP_PRIVATE_V42BIS_H_) +#define _SPANDSP_PRIVATE_V42BIS_H_ + +/*! + V.42bis dictionary node. +*/ +typedef struct +{ + /*! \brief The prior code for each defined code. */ + uint16_t parent_code; + /*! \brief The number of leaf nodes this node has */ + int16_t leaves; + /*! \brief This leaf octet for each defined code. */ + uint8_t node_octet; + /*! \brief Bit map of the children which exist */ + uint32_t children[8]; +} v42bis_dict_node_t; + +/*! + V.42bis compression. This defines the working state for a single instance + of V.42bis compression. +*/ +typedef struct +{ + /*! \brief Compression mode. */ + int compression_mode; + /*! \brief Callback function to handle received frames. */ + v42bis_frame_handler_t handler; + /*! \brief An opaque pointer passed in calls to frame_handler. */ + void *user_data; + /*! \brief The maximum frame length allowed */ + int max_len; + + uint32_t string_code; + uint32_t latest_code; + int string_length; + uint32_t output_bit_buffer; + int output_bit_count; + int output_octet_count; + uint8_t output_buf[1024]; + v42bis_dict_node_t dict[V42BIS_MAX_CODEWORDS]; + /*! \brief TRUE if we are in transparent (i.e. uncompressable) mode */ + int transparent; + int change_transparency; + /*! \brief IIR filter state, used in assessing compressibility. */ + int compressibility_filter; + int compressibility_persistence; + + /*! \brief Next empty dictionary entry */ + uint32_t v42bis_parm_c1; + /*! \brief Current codeword size */ + int v42bis_parm_c2; + /*! \brief Threshold for codeword size change */ + uint32_t v42bis_parm_c3; + + /*! \brief Mark that this is the first octet/code to be processed */ + int first; + uint8_t escape_code; +} v42bis_compress_state_t; + +/*! + V.42bis decompression. This defines the working state for a single instance + of V.42bis decompression. +*/ +typedef struct +{ + /*! \brief Callback function to handle decompressed data. */ + v42bis_data_handler_t handler; + /*! \brief An opaque pointer passed in calls to data_handler. */ + void *user_data; + /*! \brief The maximum decompressed data block length allowed */ + int max_len; + + uint32_t old_code; + uint32_t last_old_code; + uint32_t input_bit_buffer; + int input_bit_count; + int octet; + int last_length; + int output_octet_count; + uint8_t output_buf[1024]; + v42bis_dict_node_t dict[V42BIS_MAX_CODEWORDS]; + /*! \brief TRUE if we are in transparent (i.e. uncompressable) mode */ + int transparent; + + int last_extra_octet; + + /*! \brief Next empty dictionary entry */ + uint32_t v42bis_parm_c1; + /*! \brief Current codeword size */ + int v42bis_parm_c2; + /*! \brief Threshold for codeword size change */ + uint32_t v42bis_parm_c3; + + /*! \brief Mark that this is the first octet/code to be processed */ + int first; + uint8_t escape_code; + int escaped; +} v42bis_decompress_state_t; + +/*! + V.42bis compression/decompression descriptor. This defines the working state for a + single instance of V.42bis compress/decompression. +*/ +struct v42bis_state_s +{ + /*! \brief V.42bis data compression directions. */ + int v42bis_parm_p0; + + /*! \brief Compression state. */ + v42bis_compress_state_t compress; + /*! \brief Decompression state. */ + v42bis_decompress_state_t decompress; + + /*! \brief Maximum codeword size (bits) */ + int v42bis_parm_n1; + /*! \brief Total number of codewords */ + uint32_t v42bis_parm_n2; + /*! \brief Maximum string length */ + int v42bis_parm_n7; +}; + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/openbsc/include/openbsc/v42bis.h b/openbsc/include/openbsc/v42bis.h new file mode 100644 index 0000000..f13e5c5 --- /dev/null +++ b/openbsc/include/openbsc/v42bis.h @@ -0,0 +1,143 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * v42bis.h + * + * Written by Steve Underwood + * + * Copyright (C) 2005 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: v42bis.h,v 1.27 2009/04/11 18:11:19 steveu Exp $ + */ + +/*! \page v42bis_page V.42bis modem data compression +\section v42bis_page_sec_1 What does it do? +The v.42bis specification defines a data compression scheme, to work in +conjunction with the error correction scheme defined in V.42. + +\section v42bis_page_sec_2 How does it work? +*/ + +#if !defined(_SPANDSP_V42BIS_H_) +#define _SPANDSP_V42BIS_H_ + +#define V42BIS_MAX_BITS 12 +#define V42BIS_MAX_CODEWORDS 4096 /* 2^V42BIS_MAX_BITS */ +#define V42BIS_TABLE_SIZE 5021 /* This should be a prime >(2^V42BIS_MAX_BITS) */ +#define V42BIS_MAX_STRING_SIZE 250 + +enum +{ + V42BIS_P0_NEITHER_DIRECTION = 0, + V42BIS_P0_INITIATOR_RESPONDER, + V42BIS_P0_RESPONDER_INITIATOR, + V42BIS_P0_BOTH_DIRECTIONS +}; + +enum +{ + V42BIS_COMPRESSION_MODE_DYNAMIC = 0, + V42BIS_COMPRESSION_MODE_ALWAYS, + V42BIS_COMPRESSION_MODE_NEVER +}; + +typedef void (*v42bis_frame_handler_t)(void *user_data, const uint8_t *pkt, int len); +typedef void (*v42bis_data_handler_t)(void *user_data, const uint8_t *buf, int len); + +/*! + V.42bis compression/decompression descriptor. This defines the working state for a + single instance of V.42bis compress/decompression. +*/ +typedef struct v42bis_state_s v42bis_state_t; + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/*! Compress a block of octets. + \param s The V.42bis context. + \param buf The data to be compressed. + \param len The length of the data buffer. + \return 0 */ +SPAN_DECLARE(int) v42bis_compress(v42bis_state_t *s, const uint8_t *buf, int len); + +/*! Flush out any data remaining in a compression buffer. + \param s The V.42bis context. + \return 0 */ +SPAN_DECLARE(int) v42bis_compress_flush(v42bis_state_t *s); + +/*! Decompress a block of octets. + \param s The V.42bis context. + \param buf The data to be decompressed. + \param len The length of the data buffer. + \return 0 */ +SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *s, const uint8_t *buf, int len); + +/*! Flush out any data remaining in the decompression buffer. + \param s The V.42bis context. + \return 0 */ +SPAN_DECLARE(int) v42bis_decompress_flush(v42bis_state_t *s); + +/*! Set the compression mode. + \param s The V.42bis context. + \param mode One of the V.42bis compression modes - + V42BIS_COMPRESSION_MODE_DYNAMIC, + V42BIS_COMPRESSION_MODE_ALWAYS, + V42BIS_COMPRESSION_MODE_NEVER */ +SPAN_DECLARE(void) v42bis_compression_control(v42bis_state_t *s, int mode); + +/*! Initialise a V.42bis context. + \param s The V.42bis context. + \param negotiated_p0 The negotiated P0 parameter, from the V.42bis spec. + \param negotiated_p1 The negotiated P1 parameter, from the V.42bis spec. + \param negotiated_p2 The negotiated P2 parameter, from the V.42bis spec. + \param frame_handler Frame callback handler. + \param frame_user_data An opaque pointer passed to the frame callback handler. + \param max_frame_len The maximum length that should be passed to the frame handler. + \param data_handler data callback handler. + \param data_user_data An opaque pointer passed to the data callback handler. + \param max_data_len The maximum length that should be passed to the data handler. + \return The V.42bis context. */ +SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, + int negotiated_p0, + int negotiated_p1, + int negotiated_p2, + v42bis_frame_handler_t frame_handler, + void *frame_user_data, + int max_frame_len, + v42bis_data_handler_t data_handler, + void *data_user_data, + int max_data_len); + +/*! Release a V.42bis context. + \param s The V.42bis context. + \return 0 if OK */ +SPAN_DECLARE(int) v42bis_release(v42bis_state_t *s); + +/*! Free a V.42bis context. + \param s The V.42bis context. + \return 0 if OK */ +SPAN_DECLARE(int) v42bis_free(v42bis_state_t *s); + +#if defined(__cplusplus) +} +#endif + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/openbsc/src/gprs/v42bis.c b/openbsc/src/gprs/v42bis.c new file mode 100644 index 0000000..d8d3f3f --- /dev/null +++ b/openbsc/src/gprs/v42bis.c @@ -0,0 +1,702 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * v42bis.c + * + * Written by Steve Underwood + * + * Copyright (C) 2005 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: v42bis.c,v 1.37 2009/02/10 13:06:47 steveu Exp $ + */ + +/* THIS IS A WORK IN PROGRESS. IT IS NOT FINISHED. + Currently it performs the core compression and decompression functions OK. + However, a number of the bells and whistles in V.42bis are incomplete. */ + +/*! \file */ + +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "spandsp/telephony.h" +#include "spandsp/logging.h" +#include "spandsp/bit_operations.h" +#include "spandsp/v42bis.h" + +#include "spandsp/private/logging.h" +#include "spandsp/private/v42bis.h" + +/* Fixed parameters from the spec. */ +#define V42BIS_N3 8 /* Character size (bits) */ +#define V42BIS_N4 256 /* Number of characters in the alphabet */ +#define V42BIS_N5 (V42BIS_N4 + V42BIS_N6) /* Index number of first dictionary entry used to store a string */ +#define V42BIS_N6 3 /* Number of control codewords */ + +/* Control code words in compressed mode */ +enum +{ + V42BIS_ETM = 0, /* Enter transparent mode */ + V42BIS_FLUSH = 1, /* Flush data */ + V42BIS_STEPUP = 2 /* Step up codeword size */ +}; + +/* Command codes in transparent mode */ +enum +{ + V42BIS_ECM = 0, /* Enter compression mode */ + V42BIS_EID = 1, /* Escape character in data */ + V42BIS_RESET = 2 /* Force reinitialisation */ +}; + +static __inline__ void push_compressed_raw_octet(v42bis_compress_state_t *ss, int octet) +{ + ss->output_buf[ss->output_octet_count++] = (uint8_t) octet; + if (ss->output_octet_count >= ss->max_len) + { + ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); + ss->output_octet_count = 0; + } +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ void push_compressed_code(v42bis_compress_state_t *ss, int code) +{ + ss->output_bit_buffer |= code << (32 - ss->v42bis_parm_c2 - ss->output_bit_count); + ss->output_bit_count += ss->v42bis_parm_c2; + while (ss->output_bit_count >= 8) + { + push_compressed_raw_octet(ss, ss->output_bit_buffer >> 24); + ss->output_bit_buffer <<= 8; + ss->output_bit_count -= 8; + } +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ void push_compressed_octet(v42bis_compress_state_t *ss, int code) +{ + ss->output_bit_buffer |= code << (32 - 8 - ss->output_bit_count); + ss->output_bit_count += 8; + while (ss->output_bit_count >= 8) + { + push_compressed_raw_octet(ss, ss->output_bit_buffer >> 24); + ss->output_bit_buffer <<= 8; + ss->output_bit_count -= 8; + } +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v42bis_compress(v42bis_state_t *s, const uint8_t *buf, int len) +{ + int ptr; + int i; + uint32_t octet; + uint32_t code; + v42bis_compress_state_t *ss; + + ss = &s->compress; + if ((s->v42bis_parm_p0 & 2) == 0) + { + /* Compression is off - just push the incoming data out */ + for (i = 0; i < len - ss->max_len; i += ss->max_len) + ss->handler(ss->user_data, buf + i, ss->max_len); + if (i < len) + ss->handler(ss->user_data, buf + i, len - i); + return 0; + } + ptr = 0; + if (ss->first && len > 0) + { + octet = buf[ptr++]; + ss->string_code = octet + V42BIS_N6; + if (ss->transparent) + push_compressed_octet(ss, octet); + ss->first = FALSE; + } + while (ptr < len) + { + octet = buf[ptr++]; + if ((ss->dict[ss->string_code].children[octet >> 5] & (1 << (octet & 0x1F)))) + { + /* The leaf exists. Now find it in the table. */ + /* TODO: This is a brute force scan for a match. We need something better. */ + for (code = 0; code < ss->v42bis_parm_c3; code++) + { + if (ss->dict[code].parent_code == ss->string_code && ss->dict[code].node_octet == octet) + break; + } + } + else + { + /* The leaf does not exist. */ + code = s->v42bis_parm_n2; + } + /* 6.3(b) If the string matches a dictionary entry, and the entry is not that entry + created by the last invocation of the string matching procedure, then the + next character shall be read and appended to the string and this step + repeated. */ + if (code < ss->v42bis_parm_c3 && code != ss->latest_code) + { + /* The string was found */ + ss->string_code = code; + ss->string_length++; + } + else + { + /* The string is not in the table. */ + if (!ss->transparent) + { + /* 7.4 Encoding - we now have the longest matchable string, and will need to output the code for it. */ + while (ss->v42bis_parm_c1 >= ss->v42bis_parm_c3 && ss->v42bis_parm_c3 <= s->v42bis_parm_n2) + { + /* We need to increase the codeword size */ + /* 7.4(a) */ + push_compressed_code(ss, V42BIS_STEPUP); + /* 7.4(b) */ + ss->v42bis_parm_c2++; + /* 7.4(c) */ + ss->v42bis_parm_c3 <<= 1; + /* 7.4(d) this might need to be repeated, so we loop */ + } + /* 7.5 Transfer - output the last state of the string */ + push_compressed_code(ss, ss->string_code); + } + /* 7.6 Dictionary updating */ + /* 6.4 Add the string to the dictionary */ + /* 6.4(b) The string is not in the table. */ + if (code != ss->latest_code && ss->string_length < s->v42bis_parm_n7) + { + ss->latest_code = ss->v42bis_parm_c1; + /* 6.4(a) The length of the string is in range for adding to the dictionary */ + /* If the last code was a leaf, it no longer is */ + ss->dict[ss->string_code].leaves++; + ss->dict[ss->string_code].children[octet >> 5] |= (1 << (octet & 0x1F)); + /* The new one is definitely a leaf */ + ss->dict[ss->v42bis_parm_c1].parent_code = (uint16_t) ss->string_code; + ss->dict[ss->v42bis_parm_c1].leaves = 0; + ss->dict[ss->v42bis_parm_c1].node_octet = (uint8_t) octet; + /* 7.7 Node recovery */ + /* 6.5 Recovering a dictionary entry to use next */ + for (;;) + { + /* 6.5(a) and (b) */ + if ((int) (++ss->v42bis_parm_c1) >= s->v42bis_parm_n2) + ss->v42bis_parm_c1 = V42BIS_N5; + /* 6.5(c) We need to reuse a leaf node */ + if (ss->dict[ss->v42bis_parm_c1].leaves) + continue; + if (ss->dict[ss->v42bis_parm_c1].parent_code == 0xFFFF) + break; + /* 6.5(d) Detach the leaf node from its parent, and re-use it */ + /* Possibly make the parent a leaf node again */ + ss->dict[ss->dict[ss->v42bis_parm_c1].parent_code].leaves--; + ss->dict[ss->dict[ss->v42bis_parm_c1].parent_code].children[ss->dict[ss->v42bis_parm_c1].node_octet >> 5] &= ~(1 << (ss->dict[ss->v42bis_parm_c1].node_octet & 0x1F)); + ss->dict[ss->v42bis_parm_c1].parent_code = 0xFFFF; + break; + } + } + else + { + ss->latest_code = 0xFFFFFFFF; + } + /* 7.8 Data compressibility test */ + /* Filter on the balance of what went into the compressor, and what came out */ + ss->compressibility_filter += ((((8*ss->string_length - ss->v42bis_parm_c2) << 20) - ss->compressibility_filter) >> 10); + if (ss->compression_mode == V42BIS_COMPRESSION_MODE_DYNAMIC) + { + /* Work out if it is appropriate to change between transparent and + compressed mode. */ + if (ss->transparent) + { + if (ss->compressibility_filter > 0) + { + if (++ss->compressibility_persistence > 1000) + { + /* Schedule a switch to compressed mode */ + ss->change_transparency = -1; + ss->compressibility_persistence = 0; + } + } + else + { + ss->compressibility_persistence = 0; + } + } + else + { + if (ss->compressibility_filter < 0) + { + if (++ss->compressibility_persistence > 1000) + { + /* Schedule a switch to transparent mode */ + ss->change_transparency = 1; + ss->compressibility_persistence = 0; + } + } + else + { + ss->compressibility_persistence = 0; + } + } + } + if (ss->change_transparency) + { + if (ss->change_transparency < 0) + { + if (ss->transparent) + { + printf("Going compressed\n"); + /* 7.8.1 Transition to compressed mode */ + /* Switch out of transparent now, between codes. We need to send the octet which did not + match, just before switching. */ + if (octet == ss->escape_code) + { + push_compressed_octet(ss, ss->escape_code++); + push_compressed_octet(ss, V42BIS_EID); + } + else + { + push_compressed_octet(ss, octet); + } + push_compressed_octet(ss, ss->escape_code++); + push_compressed_octet(ss, V42BIS_ECM); + ss->transparent = FALSE; + } + } + else + { + if (!ss->transparent) + { + printf("Going transparent\n"); + /* 7.8.2 Transition to transparent mode */ + /* Switch into transparent now, between codes, and the unmatched octet should + go out in transparent mode, just below */ + push_compressed_code(ss, V42BIS_ETM); + ss->transparent = TRUE; + } + } + ss->change_transparency = 0; + } + /* 7.8.3 Reset function - TODO */ + ss->string_code = octet + V42BIS_N6; + ss->string_length = 1; + } + if (ss->transparent) + { + if (octet == ss->escape_code) + { + push_compressed_octet(ss, ss->escape_code++); + push_compressed_octet(ss, V42BIS_EID); + } + else + { + push_compressed_octet(ss, octet); + } + } + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v42bis_compress_flush(v42bis_state_t *s) +{ + v42bis_compress_state_t *ss; + + ss = &s->compress; + if (!ss->transparent) + { + /* Output the last state of the string */ + push_compressed_code(ss, ss->string_code); + /* TODO: We use a positive FLUSH at all times. It is really needed, if the + previous step resulted in no leftover bits. */ + push_compressed_code(ss, V42BIS_FLUSH); + } + while (ss->output_bit_count > 0) + { + push_compressed_raw_octet(ss, ss->output_bit_buffer >> 24); + ss->output_bit_buffer <<= 8; + ss->output_bit_count -= 8; + } + /* Now push out anything remaining. */ + if (ss->output_octet_count > 0) + { + ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); + ss->output_octet_count = 0; + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +#if 0 +SPAN_DECLARE(int) v42bis_compress_dump(v42bis_state_t *s) +{ + int i; + + for (i = 0; i < V42BIS_MAX_CODEWORDS; i++) + { + if (s->compress.dict[i].parent_code != 0xFFFF) + { + printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); + } + } + return 0; +} +/*- End of function --------------------------------------------------------*/ +#endif + +SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *s, const uint8_t *buf, int len) +{ + int ptr; + int i; + int this_length; + uint8_t *string; + uint32_t code; + uint32_t new_code; + int code_len; + v42bis_decompress_state_t *ss; + uint8_t decode_buf[V42BIS_MAX_STRING_SIZE]; + + ss = &s->decompress; + if ((s->v42bis_parm_p0 & 1) == 0) + { + /* Compression is off - just push the incoming data out */ + for (i = 0; i < len - ss->max_len; i += ss->max_len) + ss->handler(ss->user_data, buf + i, ss->max_len); + if (i < len) + ss->handler(ss->user_data, buf + i, len - i); + return 0; + } + ptr = 0; + code_len = (ss->transparent) ? 8 : ss->v42bis_parm_c2; + for (;;) + { + /* Fill up the bit buffer. */ + while (ss->input_bit_count < 32 - 8 && ptr < len) + { + ss->input_bit_count += 8; + ss->input_bit_buffer |= (uint32_t) buf[ptr++] << (32 - ss->input_bit_count); + } + if (ss->input_bit_count < code_len) + break; + new_code = ss->input_bit_buffer >> (32 - code_len); + ss->input_bit_count -= code_len; + ss->input_bit_buffer <<= code_len; + if (ss->transparent) + { + code = new_code; + if (ss->escaped) + { + ss->escaped = FALSE; + if (code == V42BIS_ECM) + { + printf("Hit V42BIS_ECM\n"); + ss->transparent = FALSE; + code_len = ss->v42bis_parm_c2; + } + else if (code == V42BIS_EID) + { + printf("Hit V42BIS_EID\n"); + ss->output_buf[ss->output_octet_count++] = ss->escape_code - 1; + if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) + { + ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); + ss->output_octet_count = 0; + } + } + else if (code == V42BIS_RESET) + { + printf("Hit V42BIS_RESET\n"); + } + else + { + printf("Hit V42BIS_???? - %" PRIu32 "\n", code); + } + } + else if (code == ss->escape_code) + { + ss->escape_code++; + ss->escaped = TRUE; + } + else + { + ss->output_buf[ss->output_octet_count++] = (uint8_t) code; + if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) + { + ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); + ss->output_octet_count = 0; + } + } + } + else + { + if (new_code < V42BIS_N6) + { + /* We have a control code. */ + switch (new_code) + { + case V42BIS_ETM: + printf("Hit V42BIS_ETM\n"); + ss->transparent = TRUE; + code_len = 8; + break; + case V42BIS_FLUSH: + printf("Hit V42BIS_FLUSH\n"); + v42bis_decompress_flush(s); + break; + case V42BIS_STEPUP: + /* We need to increase the codeword size */ + printf("Hit V42BIS_STEPUP\n"); + if (ss->v42bis_parm_c3 >= s->v42bis_parm_n2) + { + /* Invalid condition */ + return -1; + } + code_len = ++ss->v42bis_parm_c2; + ss->v42bis_parm_c3 <<= 1; + break; + } + continue; + } + if (ss->first) + { + ss->first = FALSE; + ss->octet = new_code - V42BIS_N6; + ss->output_buf[0] = (uint8_t) ss->octet; + ss->output_octet_count = 1; + if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) + { + ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); + ss->output_octet_count = 0; + } + ss->old_code = new_code; + continue; + } + /* Start at the end of the buffer, and decode backwards */ + string = &decode_buf[V42BIS_MAX_STRING_SIZE - 1]; + /* Check the received code is valid. It can't be too big, as we pulled only the expected number + of bits from the input stream. It could, however, be unknown. */ + if (ss->dict[new_code].parent_code == 0xFFFF) + return -1; + /* Otherwise we do a straight decode of the new code. */ + code = new_code; + /* Trace back through the octets which form the string, and output them. */ + while (code >= V42BIS_N5) + { +if (code > 4095) {printf("Code is 0x%" PRIu32 "\n", code); exit(2);} + *string-- = ss->dict[code].node_octet; + code = ss->dict[code].parent_code; + } + *string = (uint8_t) (code - V42BIS_N6); + ss->octet = code - V42BIS_N6; + /* Output the decoded string. */ + this_length = V42BIS_MAX_STRING_SIZE - (int) (string - decode_buf); + memcpy(ss->output_buf + ss->output_octet_count, string, this_length); + ss->output_octet_count += this_length; + if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) + { + ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); + ss->output_octet_count = 0; + } + /* 6.4 Add the string to the dictionary */ + if (ss->last_length < s->v42bis_parm_n7) + { + /* 6.4(a) The string does not exceed N7 in length */ + if (ss->last_old_code != ss->old_code + || + ss->last_extra_octet != *string) + { + /* 6.4(b) The string is not in the table. */ + ss->dict[ss->old_code].leaves++; + /* The new one is definitely a leaf */ + ss->dict[ss->v42bis_parm_c1].parent_code = (uint16_t) ss->old_code; + ss->dict[ss->v42bis_parm_c1].leaves = 0; + ss->dict[ss->v42bis_parm_c1].node_octet = (uint8_t) ss->octet; + /* 6.5 Recovering a dictionary entry to use next */ + for (;;) + { + /* 6.5(a) and (b) */ + if (++ss->v42bis_parm_c1 >= s->v42bis_parm_n2) + ss->v42bis_parm_c1 = V42BIS_N5; + /* 6.5(c) We need to reuse a leaf node */ + if (ss->dict[ss->v42bis_parm_c1].leaves) + continue; + /* 6.5(d) This is a leaf node, so re-use it */ + /* Possibly make the parent a leaf node again */ + if (ss->dict[ss->v42bis_parm_c1].parent_code != 0xFFFF) + ss->dict[ss->dict[ss->v42bis_parm_c1].parent_code].leaves--; + ss->dict[ss->v42bis_parm_c1].parent_code = 0xFFFF; + break; + } + } + } + /* Record the addition to the dictionary, so we can check for repeat attempts + at the next code - see II.4.3 */ + ss->last_old_code = ss->old_code; + ss->last_extra_octet = *string; + + ss->old_code = new_code; + ss->last_length = this_length; + } + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v42bis_decompress_flush(v42bis_state_t *s) +{ + v42bis_decompress_state_t *ss; + + ss = &s->decompress; + /* Push out anything remaining. */ + if (ss->output_octet_count > 0) + { + ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); + ss->output_octet_count = 0; + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +#if 0 +SPAN_DECLARE(int) v42bis_decompress_dump(v42bis_state_t *s) +{ + int i; + + for (i = 0; i < V42BIS_MAX_CODEWORDS; i++) + { + if (s->decompress.dict[i].parent_code != 0xFFFF) + { + printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); + } + } + return 0; +} +/*- End of function --------------------------------------------------------*/ +#endif + +SPAN_DECLARE(void) v42bis_compression_control(v42bis_state_t *s, int mode) +{ + s->compress.compression_mode = mode; + switch (mode) + { + case V42BIS_COMPRESSION_MODE_ALWAYS: + s->compress.change_transparency = -1; + break; + case V42BIS_COMPRESSION_MODE_NEVER: + s->compress.change_transparency = 1; + break; + } +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, + int negotiated_p0, + int negotiated_p1, + int negotiated_p2, + v42bis_frame_handler_t frame_handler, + void *frame_user_data, + int max_frame_len, + v42bis_data_handler_t data_handler, + void *data_user_data, + int max_data_len) +{ + int i; + + if (negotiated_p1 < 512 || negotiated_p1 > 65535) + return NULL; + if (negotiated_p2 < 6 || negotiated_p2 > V42BIS_MAX_STRING_SIZE) + return NULL; + if (s == NULL) + { + if ((s = (v42bis_state_t *) malloc(sizeof(*s))) == NULL) + return NULL; + } + memset(s, 0, sizeof(*s)); + + s->compress.handler = frame_handler; + s->compress.user_data = frame_user_data; + s->compress.max_len = (max_frame_len < 1024) ? max_frame_len : 1024; + + s->decompress.handler = data_handler; + s->decompress.user_data = data_user_data; + s->decompress.max_len = (max_data_len < 1024) ? max_data_len : 1024; + + s->v42bis_parm_p0 = negotiated_p0; /* default is both ways off */ + + s->v42bis_parm_n1 = top_bit(negotiated_p1 - 1) + 1; + s->v42bis_parm_n2 = negotiated_p1; + s->v42bis_parm_n7 = negotiated_p2; + + /* 6.5 */ + s->compress.v42bis_parm_c1 = + s->decompress.v42bis_parm_c1 = V42BIS_N5; + + s->compress.v42bis_parm_c2 = + s->decompress.v42bis_parm_c2 = V42BIS_N3 + 1; + + s->compress.v42bis_parm_c3 = + s->decompress.v42bis_parm_c3 = 2*V42BIS_N4; + + s->compress.first = + s->decompress.first = TRUE; + for (i = 0; i < V42BIS_MAX_CODEWORDS; i++) + { + s->compress.dict[i].parent_code = + s->decompress.dict[i].parent_code = 0xFFFF; + s->compress.dict[i].leaves = + s->decompress.dict[i].leaves = 0; + } + /* Point the root nodes for decompression to themselves. It doesn't matter much what + they are set to, as long as they are considered "known" codes. */ + for (i = 0; i < V42BIS_N5; i++) + s->decompress.dict[i].parent_code = (uint16_t) i; + s->compress.string_code = 0xFFFFFFFF; + s->compress.latest_code = 0xFFFFFFFF; + + s->decompress.last_old_code = 0xFFFFFFFF; + s->decompress.last_extra_octet = -1; + + s->compress.compression_mode = V42BIS_COMPRESSION_MODE_DYNAMIC; + + return s; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v42bis_release(v42bis_state_t *s) +{ + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v42bis_free(v42bis_state_t *s) +{ + free(s); + return 0; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ -- To view, visit https://gerrit.osmocom.org/643 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Iabedece9f97ca944a1e3f747bb073e532c4e9dca Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter From gerrit-no-reply at lists.osmocom.org Mon Aug 1 16:38:56 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Mon, 1 Aug 2016 16:38:56 +0000 Subject: [PATCH] openbsc[master]: V42BIS integration Message-ID: Review at https://gerrit.osmocom.org/644 V42BIS integration The previously committed SPANDSP v42bis implementation has been edited to fit our needs. There was not much to change, other than removing some clutter and merging private_v42bis.h and v42bis.h into one file. The debug printf statements were converted into LOGP statements. Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d --- M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/debug.h D openbsc/include/openbsc/private_v42bis.h M openbsc/include/openbsc/v42bis.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/v42bis.c 6 files changed, 162 insertions(+), 198 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/44/644/1 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index e159db5..bec9e4f 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,7 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h gprs_sndcp_xid.h \ - gprs_sndcp_comp_entity.h gprs_sndcp_hdrcomp.h + gprs_sndcp_comp_entity.h gprs_sndcp_hdrcomp.h v42bis.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 90ddca5..f98439f 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -28,7 +28,6 @@ DNS, DBSSGP, DLLC, - DSNDCP, DSLHC, DNAT, DCTRL, @@ -37,6 +36,8 @@ DGTPHUB, DRANAP, DSUA, + DSNDCP, + DV42BIS, Debug_LastEntry, }; diff --git a/openbsc/include/openbsc/private_v42bis.h b/openbsc/include/openbsc/private_v42bis.h deleted file mode 100644 index 96538f2..0000000 --- a/openbsc/include/openbsc/private_v42bis.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/v42bis.h - * - * Written by Steve Underwood - * - * Copyright (C) 2005 Steve Underwood - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 2.1, - * as published by the Free Software Foundation. - * - * 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Id: v42bis.h,v 1.1 2008/11/15 14:43:08 steveu Exp $ - */ - -#if !defined(_SPANDSP_PRIVATE_V42BIS_H_) -#define _SPANDSP_PRIVATE_V42BIS_H_ - -/*! - V.42bis dictionary node. -*/ -typedef struct -{ - /*! \brief The prior code for each defined code. */ - uint16_t parent_code; - /*! \brief The number of leaf nodes this node has */ - int16_t leaves; - /*! \brief This leaf octet for each defined code. */ - uint8_t node_octet; - /*! \brief Bit map of the children which exist */ - uint32_t children[8]; -} v42bis_dict_node_t; - -/*! - V.42bis compression. This defines the working state for a single instance - of V.42bis compression. -*/ -typedef struct -{ - /*! \brief Compression mode. */ - int compression_mode; - /*! \brief Callback function to handle received frames. */ - v42bis_frame_handler_t handler; - /*! \brief An opaque pointer passed in calls to frame_handler. */ - void *user_data; - /*! \brief The maximum frame length allowed */ - int max_len; - - uint32_t string_code; - uint32_t latest_code; - int string_length; - uint32_t output_bit_buffer; - int output_bit_count; - int output_octet_count; - uint8_t output_buf[1024]; - v42bis_dict_node_t dict[V42BIS_MAX_CODEWORDS]; - /*! \brief TRUE if we are in transparent (i.e. uncompressable) mode */ - int transparent; - int change_transparency; - /*! \brief IIR filter state, used in assessing compressibility. */ - int compressibility_filter; - int compressibility_persistence; - - /*! \brief Next empty dictionary entry */ - uint32_t v42bis_parm_c1; - /*! \brief Current codeword size */ - int v42bis_parm_c2; - /*! \brief Threshold for codeword size change */ - uint32_t v42bis_parm_c3; - - /*! \brief Mark that this is the first octet/code to be processed */ - int first; - uint8_t escape_code; -} v42bis_compress_state_t; - -/*! - V.42bis decompression. This defines the working state for a single instance - of V.42bis decompression. -*/ -typedef struct -{ - /*! \brief Callback function to handle decompressed data. */ - v42bis_data_handler_t handler; - /*! \brief An opaque pointer passed in calls to data_handler. */ - void *user_data; - /*! \brief The maximum decompressed data block length allowed */ - int max_len; - - uint32_t old_code; - uint32_t last_old_code; - uint32_t input_bit_buffer; - int input_bit_count; - int octet; - int last_length; - int output_octet_count; - uint8_t output_buf[1024]; - v42bis_dict_node_t dict[V42BIS_MAX_CODEWORDS]; - /*! \brief TRUE if we are in transparent (i.e. uncompressable) mode */ - int transparent; - - int last_extra_octet; - - /*! \brief Next empty dictionary entry */ - uint32_t v42bis_parm_c1; - /*! \brief Current codeword size */ - int v42bis_parm_c2; - /*! \brief Threshold for codeword size change */ - uint32_t v42bis_parm_c3; - - /*! \brief Mark that this is the first octet/code to be processed */ - int first; - uint8_t escape_code; - int escaped; -} v42bis_decompress_state_t; - -/*! - V.42bis compression/decompression descriptor. This defines the working state for a - single instance of V.42bis compress/decompression. -*/ -struct v42bis_state_s -{ - /*! \brief V.42bis data compression directions. */ - int v42bis_parm_p0; - - /*! \brief Compression state. */ - v42bis_compress_state_t compress; - /*! \brief Decompression state. */ - v42bis_decompress_state_t decompress; - - /*! \brief Maximum codeword size (bits) */ - int v42bis_parm_n1; - /*! \brief Total number of codewords */ - uint32_t v42bis_parm_n2; - /*! \brief Maximum string length */ - int v42bis_parm_n7; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/openbsc/include/openbsc/v42bis.h b/openbsc/include/openbsc/v42bis.h index f13e5c5..a05a169 100644 --- a/openbsc/include/openbsc/v42bis.h +++ b/openbsc/include/openbsc/v42bis.h @@ -33,13 +33,16 @@ \section v42bis_page_sec_2 How does it work? */ -#if !defined(_SPANDSP_V42BIS_H_) -#define _SPANDSP_V42BIS_H_ +#ifndef V42BIS_H +#define V42BIS_H #define V42BIS_MAX_BITS 12 #define V42BIS_MAX_CODEWORDS 4096 /* 2^V42BIS_MAX_BITS */ #define V42BIS_TABLE_SIZE 5021 /* This should be a prime >(2^V42BIS_MAX_BITS) */ #define V42BIS_MAX_STRING_SIZE 250 + +#define TRUE 1 +#define FALSE 0 enum { @@ -60,39 +63,156 @@ typedef void (*v42bis_data_handler_t)(void *user_data, const uint8_t *buf, int len); /*! + V.42bis dictionary node. +*/ +typedef struct +{ + /*! \brief The prior code for each defined code. */ + uint16_t parent_code; + /*! \brief The number of leaf nodes this node has */ + int16_t leaves; + /*! \brief This leaf octet for each defined code. */ + uint8_t node_octet; + /*! \brief Bit map of the children which exist */ + uint32_t children[8]; +} v42bis_dict_node_t; + +/*! + V.42bis compression. This defines the working state for a single instance + of V.42bis compression. +*/ +typedef struct +{ + /*! \brief Compression mode. */ + int compression_mode; + /*! \brief Callback function to handle received frames. */ + v42bis_frame_handler_t handler; + /*! \brief An opaque pointer passed in calls to frame_handler. */ + void *user_data; + /*! \brief The maximum frame length allowed */ + int max_len; + + uint32_t string_code; + uint32_t latest_code; + int string_length; + uint32_t output_bit_buffer; + int output_bit_count; + int output_octet_count; + uint8_t output_buf[1024]; + v42bis_dict_node_t dict[V42BIS_MAX_CODEWORDS]; + /*! \brief TRUE if we are in transparent (i.e. uncompressable) mode */ + int transparent; + int change_transparency; + /*! \brief IIR filter state, used in assessing compressibility. */ + int compressibility_filter; + int compressibility_persistence; + + /*! \brief Next empty dictionary entry */ + uint32_t v42bis_parm_c1; + /*! \brief Current codeword size */ + int v42bis_parm_c2; + /*! \brief Threshold for codeword size change */ + uint32_t v42bis_parm_c3; + + /*! \brief Mark that this is the first octet/code to be processed */ + int first; + uint8_t escape_code; +} v42bis_compress_state_t; + +/*! + V.42bis decompression. This defines the working state for a single instance + of V.42bis decompression. +*/ +typedef struct +{ + /*! \brief Callback function to handle decompressed data. */ + v42bis_data_handler_t handler; + /*! \brief An opaque pointer passed in calls to data_handler. */ + void *user_data; + /*! \brief The maximum decompressed data block length allowed */ + int max_len; + + uint32_t old_code; + uint32_t last_old_code; + uint32_t input_bit_buffer; + int input_bit_count; + int octet; + int last_length; + int output_octet_count; + uint8_t output_buf[1024]; + v42bis_dict_node_t dict[V42BIS_MAX_CODEWORDS]; + /*! \brief TRUE if we are in transparent (i.e. uncompressable) mode */ + int transparent; + + int last_extra_octet; + + /*! \brief Next empty dictionary entry */ + uint32_t v42bis_parm_c1; + /*! \brief Current codeword size */ + int v42bis_parm_c2; + /*! \brief Threshold for codeword size change */ + uint32_t v42bis_parm_c3; + + /*! \brief Mark that this is the first octet/code to be processed */ + int first; + uint8_t escape_code; + int escaped; +} v42bis_decompress_state_t; + +/*! + V.42bis compression/decompression descriptor. This defines the working state for a + single instance of V.42bis compress/decompression. +*/ +struct v42bis_state_s +{ + /*! \brief V.42bis data compression directions. */ + int v42bis_parm_p0; + + /*! \brief Compression state. */ + v42bis_compress_state_t compress; + /*! \brief Decompression state. */ + v42bis_decompress_state_t decompress; + + /*! \brief Maximum codeword size (bits) */ + int v42bis_parm_n1; + /*! \brief Total number of codewords */ + uint32_t v42bis_parm_n2; + /*! \brief Maximum string length */ + int v42bis_parm_n7; +}; + + +/*! V.42bis compression/decompression descriptor. This defines the working state for a single instance of V.42bis compress/decompression. */ typedef struct v42bis_state_s v42bis_state_t; -#if defined(__cplusplus) -extern "C" -{ -#endif + /*! Compress a block of octets. \param s The V.42bis context. \param buf The data to be compressed. \param len The length of the data buffer. \return 0 */ -SPAN_DECLARE(int) v42bis_compress(v42bis_state_t *s, const uint8_t *buf, int len); +int v42bis_compress(v42bis_state_t *s, const uint8_t *buf, int len); /*! Flush out any data remaining in a compression buffer. \param s The V.42bis context. \return 0 */ -SPAN_DECLARE(int) v42bis_compress_flush(v42bis_state_t *s); +int v42bis_compress_flush(v42bis_state_t *s); /*! Decompress a block of octets. \param s The V.42bis context. \param buf The data to be decompressed. \param len The length of the data buffer. \return 0 */ -SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *s, const uint8_t *buf, int len); +int v42bis_decompress(v42bis_state_t *s, const uint8_t *buf, int len); /*! Flush out any data remaining in the decompression buffer. \param s The V.42bis context. \return 0 */ -SPAN_DECLARE(int) v42bis_decompress_flush(v42bis_state_t *s); +int v42bis_decompress_flush(v42bis_state_t *s); /*! Set the compression mode. \param s The V.42bis context. @@ -100,7 +220,7 @@ V42BIS_COMPRESSION_MODE_DYNAMIC, V42BIS_COMPRESSION_MODE_ALWAYS, V42BIS_COMPRESSION_MODE_NEVER */ -SPAN_DECLARE(void) v42bis_compression_control(v42bis_state_t *s, int mode); +void v42bis_compression_control(v42bis_state_t *s, int mode); /*! Initialise a V.42bis context. \param s The V.42bis context. @@ -114,7 +234,7 @@ \param data_user_data An opaque pointer passed to the data callback handler. \param max_data_len The maximum length that should be passed to the data handler. \return The V.42bis context. */ -SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, +v42bis_state_t *v42bis_init(v42bis_state_t *s, int negotiated_p0, int negotiated_p1, int negotiated_p2, @@ -128,16 +248,12 @@ /*! Release a V.42bis context. \param s The V.42bis context. \return 0 if OK */ -SPAN_DECLARE(int) v42bis_release(v42bis_state_t *s); +int v42bis_release(v42bis_state_t *s); /*! Free a V.42bis context. \param s The V.42bis context. \return 0 if OK */ -SPAN_DECLARE(int) v42bis_free(v42bis_state_t *s); - -#if defined(__cplusplus) -} -#endif +int v42bis_free(v42bis_state_t *s); #endif /*- End of file ------------------------------------------------------------*/ diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 3d6c82a..2c03a45 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -22,7 +22,7 @@ osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \ slhc.c gprs_sndcp_xid.c gprs_sndcp_comp_entity.c \ - gprs_sndcp_hdrcomp.c \ + gprs_sndcp_hdrcomp.c v42bis.c \ sgsn_main.c sgsn_vty.c sgsn_libgtp.c \ gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c \ gprs_llc_xid.c crc24.c \ diff --git a/openbsc/src/gprs/v42bis.c b/openbsc/src/gprs/v42bis.c index d8d3f3f..049a8ac 100644 --- a/openbsc/src/gprs/v42bis.c +++ b/openbsc/src/gprs/v42bis.c @@ -31,10 +31,6 @@ /*! \file */ -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - #include #include #include @@ -43,6 +39,7 @@ #include #include #include +#include #include "spandsp/telephony.h" #include "spandsp/logging.h" @@ -51,6 +48,7 @@ #include "spandsp/private/logging.h" #include "spandsp/private/v42bis.h" + /* Fixed parameters from the spec. */ #define V42BIS_N3 8 /* Character size (bits) */ @@ -111,7 +109,7 @@ } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) v42bis_compress(v42bis_state_t *s, const uint8_t *buf, int len) +int v42bis_compress(v42bis_state_t *s, const uint8_t *buf, int len) { int ptr; int i; @@ -270,7 +268,7 @@ { if (ss->transparent) { - printf("Going compressed\n"); + LOGP(DV42BIS, LOGL_DEBUG, "Going compressed\n"); /* 7.8.1 Transition to compressed mode */ /* Switch out of transparent now, between codes. We need to send the octet which did not match, just before switching. */ @@ -292,7 +290,7 @@ { if (!ss->transparent) { - printf("Going transparent\n"); + LOGP(DV42BIS, LOGL_DEBUG, "Going transparent\n"); /* 7.8.2 Transition to transparent mode */ /* Switch into transparent now, between codes, and the unmatched octet should go out in transparent mode, just below */ @@ -323,7 +321,7 @@ } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) v42bis_compress_flush(v42bis_state_t *s) +int v42bis_compress_flush(v42bis_state_t *s) { v42bis_compress_state_t *ss; @@ -353,7 +351,7 @@ /*- End of function --------------------------------------------------------*/ #if 0 -SPAN_DECLARE(int) v42bis_compress_dump(v42bis_state_t *s) +int v42bis_compress_dump(v42bis_state_t *s) { int i; @@ -361,7 +359,7 @@ { if (s->compress.dict[i].parent_code != 0xFFFF) { - printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); + LOGP(DV42BIS, LOGL_DEBUG, "Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); } } return 0; @@ -369,7 +367,7 @@ /*- End of function --------------------------------------------------------*/ #endif -SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *s, const uint8_t *buf, int len) +int v42bis_decompress(v42bis_state_t *s, const uint8_t *buf, int len) { int ptr; int i; @@ -414,13 +412,13 @@ ss->escaped = FALSE; if (code == V42BIS_ECM) { - printf("Hit V42BIS_ECM\n"); + LOGP(DV42BIS, LOGL_DEBUG, "Hit V42BIS_ECM\n"); ss->transparent = FALSE; code_len = ss->v42bis_parm_c2; } else if (code == V42BIS_EID) { - printf("Hit V42BIS_EID\n"); + LOGP(DV42BIS, LOGL_DEBUG, "Hit V42BIS_EID\n"); ss->output_buf[ss->output_octet_count++] = ss->escape_code - 1; if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) { @@ -430,11 +428,11 @@ } else if (code == V42BIS_RESET) { - printf("Hit V42BIS_RESET\n"); + LOGP(DV42BIS, LOGL_DEBUG, "Hit V42BIS_RESET\n"); } else { - printf("Hit V42BIS_???? - %" PRIu32 "\n", code); + LOGP(DV42BIS, LOGL_DEBUG, "Hit V42BIS_???? - %" PRIu32 "\n", code); } } else if (code == ss->escape_code) @@ -460,17 +458,17 @@ switch (new_code) { case V42BIS_ETM: - printf("Hit V42BIS_ETM\n"); + LOGP(DV42BIS, LOGL_DEBUG, "Hit V42BIS_ETM\n"); ss->transparent = TRUE; code_len = 8; break; case V42BIS_FLUSH: - printf("Hit V42BIS_FLUSH\n"); + LOGP(DV42BIS, LOGL_DEBUG, "Hit V42BIS_FLUSH\n"); v42bis_decompress_flush(s); break; case V42BIS_STEPUP: /* We need to increase the codeword size */ - printf("Hit V42BIS_STEPUP\n"); + LOGP(DV42BIS, LOGL_DEBUG, "Hit V42BIS_STEPUP\n"); if (ss->v42bis_parm_c3 >= s->v42bis_parm_n2) { /* Invalid condition */ @@ -507,7 +505,7 @@ /* Trace back through the octets which form the string, and output them. */ while (code >= V42BIS_N5) { -if (code > 4095) {printf("Code is 0x%" PRIu32 "\n", code); exit(2);} +if (code > 4095) {LOGP(DV42BIS, LOGL_DEBUG, "Code is 0x%" PRIu32 "\n", code); exit(2);} *string-- = ss->dict[code].node_octet; code = ss->dict[code].parent_code; } @@ -567,7 +565,7 @@ } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) v42bis_decompress_flush(v42bis_state_t *s) +int v42bis_decompress_flush(v42bis_state_t *s) { v42bis_decompress_state_t *ss; @@ -583,7 +581,7 @@ /*- End of function --------------------------------------------------------*/ #if 0 -SPAN_DECLARE(int) v42bis_decompress_dump(v42bis_state_t *s) +int v42bis_decompress_dump(v42bis_state_t *s) { int i; @@ -591,7 +589,7 @@ { if (s->decompress.dict[i].parent_code != 0xFFFF) { - printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); + LOGP(DV42BIS, LOGL_DEBUG, "Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); } } return 0; @@ -599,7 +597,7 @@ /*- End of function --------------------------------------------------------*/ #endif -SPAN_DECLARE(void) v42bis_compression_control(v42bis_state_t *s, int mode) +void v42bis_compression_control(v42bis_state_t *s, int mode) { s->compress.compression_mode = mode; switch (mode) @@ -614,7 +612,7 @@ } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, +v42bis_state_t *v42bis_init(v42bis_state_t *s, int negotiated_p0, int negotiated_p1, int negotiated_p2, @@ -687,13 +685,13 @@ } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) v42bis_release(v42bis_state_t *s) +int v42bis_release(v42bis_state_t *s) { return 0; } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) v42bis_free(v42bis_state_t *s) +int v42bis_free(v42bis_state_t *s) { free(s); return 0; -- To view, visit https://gerrit.osmocom.org/644 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter From gerrit-no-reply at lists.osmocom.org Mon Aug 1 16:56:45 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Mon, 1 Aug 2016 16:56:45 +0000 Subject: [PATCH] openbsc[master]: Add python function to get ctrl variable Message-ID: Review at https://gerrit.osmocom.org/645 Add python function to get ctrl variable Add get_var function which obtains requested variable while checking for proper response and id. Change-Id: I2bc275b801a4b78642653f5b0a91e8cbea25422a Related: OS#1646 --- M openbsc/contrib/bsc_control.py 1 file changed, 9 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/45/645/1 diff --git a/openbsc/contrib/bsc_control.py b/openbsc/contrib/bsc_control.py index 4fc8b4d..f8136f1 100755 --- a/openbsc/contrib/bsc_control.py +++ b/openbsc/contrib/bsc_control.py @@ -44,6 +44,15 @@ getmsg = "GET %s %s" %(op_id, var) send(sck, getmsg) +def get_var(var, sck): + r = random.randint(1, sys.maxint) + do_get(var, r, sck) + (answer, data) = remove_ipa_ctrl_header(sck.recv(4096)) + x = answer.split() + if ('GET_REPLY' == x[0] and str(r) == x[1] and var == x[2]): + return x[3] + return None + if __name__ == '__main__': random.seed() -- To view, visit https://gerrit.osmocom.org/645 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I2bc275b801a4b78642653f5b0a91e8cbea25422a Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max From gerrit-no-reply at lists.osmocom.org Mon Aug 1 18:27:45 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 1 Aug 2016 18:27:45 +0000 Subject: openbsc[master]: Added SNDCP-XID encoder / decoder In-Reply-To: References: Message-ID: Patch Set 1: Code-Review-1 (10 comments) https://gerrit.osmocom.org/#/c/641/1/openbsc/src/gprs/gprs_sndcp_xid.c File openbsc/src/gprs/gprs_sndcp_xid.c: Line 45: /* Encode applicable sapis (works the same in all three compression schemes) */ make sense to indicate that the caller is expected to provide a pre-allocated 'bytes' of length 2. PS1, Line 46: bytes let's call it 'out' or 'dst' instead of bytes to maeke sure it is the output Line 58: if ((nsapi < 5) || (nsapi > 15)) might make sense to state why < 5 // > 15 is not permitted. PS1, Line 92: (!(bytes))) we don't write lisp. "|| !bytes)" is sufficient ;) Line 248: if (params->max_cid > 16383) bei diesen magischen nummern waere es schoen zu wissen, wo sie herkommen. Entweder Kommentar (wenn nur einmal benutzt), oder #define mit kommentar + spec-referenz beim #define. Line 442: /* Encode data or protocol control information compression field */ In general it is good practise to always refer the specific specification chapter that defines the encoding of a message or information element above the function encoding it. Line 1132: static int decode_comp_field(const uint8_t * bytes, unsigned int bytes_len, function is long and has high indent level, should be split up Line 1352: rc = decode_comp_field(val + byte_counter, can this ever return 0 and cause an endless loop? Line 1406: struct gprs_sndcp_comp_field *comp_field; function is too long, indent level too deep. please split in multiple functions. Line 1411: LOGP(DSNDCP, LOGL_DEBUG, "SNDCP-XID:\n"); use DEBUGP when LOGP.... LOGL_DEBUG results in a longer command. -- To view, visit https://gerrit.osmocom.org/641 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Mon Aug 1 18:28:21 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 1 Aug 2016 18:28:21 +0000 Subject: openbsc[master]: Add python function to get ctrl variable In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+1 -- To view, visit https://gerrit.osmocom.org/645 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I2bc275b801a4b78642653f5b0a91e8cbea25422a Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 1 18:33:17 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 1 Aug 2016 18:33:17 +0000 Subject: openbsc[master]: V42BIS integration In-Reply-To: References: Message-ID: Patch Set 1: Code-Review-1 (2 comments) pleae split the pcomp(slhc) and dcomp(v42) in different topic branches, and not have them in one 'compression' topic branch. https://gerrit.osmocom.org/#/c/644/1/openbsc/include/openbsc/v42bis.h File openbsc/include/openbsc/v42bis.h: Line 68 Leaving this identical with the original code might make sense. It doesn't hurt to have this c++ compatibility stuff.. Line 78 it might make sense to simply have a #define SPAN_DECLARE(x) x and keep the original code as-is. Makes it easier if we ever have to apply any upstream patches/fixes to our copy without too many fixes. -- To view, visit https://gerrit.osmocom.org/644 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 2 06:57:51 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Tue, 2 Aug 2016 06:57:51 +0000 Subject: openbsc[master]: ussd: Add band-aid for interrogationSS In-Reply-To: References: Message-ID: Patch Set 1: Code-Review-2 (1 comment) https://gerrit.osmocom.org/#/c/503/1/openbsc/src/libmsc/ussd.c File openbsc/src/libmsc/ussd.c: Line 67: } > before this patch, we returned 0 if req.text[0] == '\0', Good catch. Besides not compiling.. it is bullshit. :) -- To view, visit https://gerrit.osmocom.org/503 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ib0dc4485388f030eb172fe21f5327b7ab94751f5 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 2 06:58:37 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Tue, 2 Aug 2016 06:58:37 +0000 Subject: osmo-pcu[master]: Add support for SPB handling for EGPRS UL TBF In-Reply-To: References: Message-ID: Patch Set 8: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/537 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I39ca53218b6e0982abc2ab9c703c24c8bf0a09c0 Gerrit-PatchSet: 8 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 2 06:58:49 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Tue, 2 Aug 2016 06:58:49 +0000 Subject: osmo-pcu[master]: Add data structure for SPB in EGPRS UL In-Reply-To: References: Message-ID: Patch Set 6: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/536 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I83ccd136bb361adcfd511c57c5a9d95ed72c36c2 Gerrit-PatchSet: 6 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 2 06:58:58 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Tue, 2 Aug 2016 06:58:58 +0000 Subject: [MERGED] osmo-pcu[master]: Add data structure for SPB in EGPRS UL In-Reply-To: References: Message-ID: Holger Freyther has submitted this change and it was merged. Change subject: Add data structure for SPB in EGPRS UL ...................................................................... Add data structure for SPB in EGPRS UL Modify header files with data structures required to support split blocks for EGPRS UL TBF This feature provides provision for MS to retransmit RLC blocks of HeaderType1, HeaderType2 by segmenting them to 2 HeaderType3 blocks(Example MCS5 will be retransmitted as 2 MCS2 blocks). Table 10.4.8b.1 of 44.060 explains the possible values of SPB in HeadrType3 for UL direction. When the MCS is changed at the PCU, PCU directs the changed MCS to MS by PUAN or UPLINK ASSIGNMENT message along with RESEGMENT flag, Then MS may decide to retransmit the blocks by resegmenting it based on Table 8.1.1.1 of 44.060. The retransmission MCS is calculated based on current MCS of the Block and demanded MCS by PCU. Section 10.3a.4.3 of 44.060 shows the HeadrType3 with SPB field present in it. Change-Id: I83ccd136bb361adcfd511c57c5a9d95ed72c36c2 --- M src/rlc.h 1 file changed, 40 insertions(+), 0 deletions(-) Approvals: Jenkins Builder: Verified Holger Freyther: Looks good to me, approved diff --git a/src/rlc.h b/src/rlc.h index 057e838..bf2d70a 100644 --- a/src/rlc.h +++ b/src/rlc.h @@ -56,6 +56,34 @@ }; /* + * EGPRS resegment status information for UL + * When only first split block is received bsn state + * will be set to EGPRS_RESEG_FIRST_SEG_RXD and when + * only second segment is received the state will be + * set to EGPRS_RESEG_SECOND_SEG_RXD. When both Split + * blocks are received the state will be set to + * EGPRS_RESEG_DEFAULT + * The EGPRS resegmentation feature allows MS to retransmit + * RLC blocks of HeaderType1, HeaderType2 by segmenting + * them to 2 HeaderType3 blocks(Example MCS5 will be + * retransmitted as 2 MCS2 blocks). Table 10.4.8b.1 of 44.060 + * explains the possible values of SPB in HeadrType3 for UL + * direction. When the MCS is changed at the PCU, PCU directs the + * changed MCS to MS by PUAN or UPLINK ASSIGNMENT message along + * with RESEGMENT flag, Then MS may decide to retransmit the + * blocks by resegmenting it based on Table 8.1.1.1 of 44.060. + * The retransmission MCS is calculated based on current MCS of + * the Block and demanded MCS by PCU. Section 10.3a.4.3 of 44.060 + * shows the HeadrType3 with SPB field present in it +*/ +enum egprs_rlc_ul_reseg_bsn_state { + EGPRS_RESEG_DEFAULT = 0, + EGPRS_RESEG_FIRST_SEG_RXD = 0x01, + EGPRS_RESEG_SECOND_SEG_RXD = 0x02, + EGPRS_RESEG_INVALID = 0x04 +}; + +/* * Valid puncturing scheme values * TS 44.060 10.4.8a.3.1, 10.4.8a.2.1, 10.4.8a.1.1 */ @@ -109,6 +137,15 @@ struct gprs_rlc_data_block_info block_info[2]; }; +/* holds the current status of the block w.r.t UL/DL split blocks */ +union split_block_status { + egprs_rlc_ul_reseg_bsn_state block_status_ul; + /* + * TODO: DL split block status need to be supported + * for EGPRS DL + */ +}; + struct gprs_rlc_data { uint8_t *prepare(size_t block_data_length); void put_data(const uint8_t *data, size_t len); @@ -133,6 +170,9 @@ /* puncturing scheme value to be used for next transmission*/ enum egprs_puncturing_values next_ps; + + /* holds the status of the block w.r.t UL/DL split blocks*/ + union split_block_status spb_status; }; void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, -- To view, visit https://gerrit.osmocom.org/536 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I83ccd136bb361adcfd511c57c5a9d95ed72c36c2 Gerrit-PatchSet: 7 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Tue Aug 2 06:58:59 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Tue, 2 Aug 2016 06:58:59 +0000 Subject: [MERGED] osmo-pcu[master]: Add support for SPB handling for EGPRS UL TBF In-Reply-To: References: Message-ID: Holger Freyther has submitted this change and it was merged. Change subject: Add support for SPB handling for EGPRS UL TBF ...................................................................... Add support for SPB handling for EGPRS UL TBF This patch will modify the EGPRS UL TBF flow to support Split block handling. This patch also contains test suite modification for SPB UL. Scenarios like MCS6->MCS3, MCS4->MCS1, MCS5->MCS2, MCS9->MCS3 MCS7->MCS2, MCS8->MCS3 have been simulated and Integration tested in NuRAN 1.0 hardware thoroughly. The scope of Unit testing is limited. Change-Id: I39ca53218b6e0982abc2ab9c703c24c8bf0a09c0 --- M src/encoding.cpp M src/tbf.h M src/tbf_ul.cpp M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 6 files changed, 909 insertions(+), 26 deletions(-) Approvals: Jenkins Builder: Verified Holger Freyther: Looks good to me, approved diff --git a/src/encoding.cpp b/src/encoding.cpp index a778ef0..63049ac 100644 --- a/src/encoding.cpp +++ b/src/encoding.cpp @@ -283,7 +283,8 @@ bitvec_write_field(dest, wp,0x0,1); // No CONTENTION_RESOLUTION_TLLI bitvec_write_field(dest, wp,0x0,1); // No COMPACT reduced MA bitvec_write_field(dest, wp,tbf->current_cs().to_num()-1, 4); // EGPRS Modulation and Coding IE - bitvec_write_field(dest, wp,0x0,1); // No RESEGMENT + /* 0: no RESEGMENT, 1: Segmentation*/ + bitvec_write_field(dest, wp, 0x1, 1); bitvec_write_field(dest, wp,ws_enc,5); // EGPRS Window Size bitvec_write_field(dest, wp,0x0,1); // No Access Technologies Request bitvec_write_field(dest, wp,0x0,1); // No ARAC RETRANSMISSION REQUEST @@ -620,7 +621,8 @@ /* CHANNEL_CODING_COMMAND */ bitvec_write_field(dest, wp, tbf->current_cs().to_num() - 1, 4); - bitvec_write_field(dest, wp, 0, 1); // 0: no RESEGMENT (nyi) + /* 0: no RESEGMENT, 1: Segmentation*/ + bitvec_write_field(dest, wp, 1, 1); bitvec_write_field(dest, wp, 1, 1); // PRE_EMPTIVE_TRANSMISSION, TODO: This resembles GPRS, change it? bitvec_write_field(dest, wp, 0, 1); // 0: no PRR_RETRANSMISSION_REQUEST, TODO: clarify bitvec_write_field(dest, wp, 0, 1); // 0: no ARAC_RETRANSMISSION_REQUEST, TODO: clarify diff --git a/src/tbf.h b/src/tbf.h index ad8ad4c..1bd7878 100644 --- a/src/tbf.h +++ b/src/tbf.h @@ -439,6 +439,21 @@ int assemble_forward_llc(const gprs_rlc_data *data); int snd_ul_ud(); + egprs_rlc_ul_reseg_bsn_state handle_egprs_ul_spb( + const struct gprs_rlc_data_info *rlc, + struct gprs_rlc_data *block, + uint8_t *data, const uint8_t block_idx); + + egprs_rlc_ul_reseg_bsn_state handle_egprs_ul_first_seg( + const struct gprs_rlc_data_info *rlc, + struct gprs_rlc_data *block, + uint8_t *data, const uint8_t block_idx); + + egprs_rlc_ul_reseg_bsn_state handle_egprs_ul_second_seg( + const struct gprs_rlc_data_info *rlc, + struct gprs_rlc_data *block, + uint8_t *data, const uint8_t block_idx); + /* Please note that all variables here will be reset when changing * from WAIT RELEASE back to FLOW state (re-use of TBF). * All states that need reset must be in this struct, so this is why diff --git a/src/tbf_ul.cpp b/src/tbf_ul.cpp index 9c9154b..7e0732c 100644 --- a/src/tbf_ul.cpp +++ b/src/tbf_ul.cpp @@ -223,36 +223,28 @@ rdbi->bsn, m_window.v_q(), m_window.mod_sns(m_window.v_q() + ws - 1)); block = m_rlc.block(rdbi->bsn); - block->block_info = *rdbi; - block->cs_last = rlc->cs; OSMO_ASSERT(rdbi->data_len <= sizeof(block->block)); rlc_data = &(block->block[0]); - /* TODO: Handle SPB != 0 -> Set length to 2*len, add offset if - * 2nd part. Note that resegmentation is currently disabled - * within the UL assignment. - */ - if (rdbi->spb) { - LOGP(DRLCMACUL, LOGL_NOTICE, - "Got SPB != 0 but resegmentation has been " - "disabled, skipping %s data block with BSN %d, " - "TFI=%d.\n", rlc->cs.name(), rdbi->bsn, - rlc->tfi); - continue; - } - block->len = - Decoding::rlc_copy_to_aligned_buffer(rlc, block_idx, data, - rlc_data); + if (rdbi->spb) { + egprs_rlc_ul_reseg_bsn_state assemble_status; + + assemble_status = handle_egprs_ul_spb(rlc, + block, data, block_idx); + + if (assemble_status != EGPRS_RESEG_DEFAULT) + return 0; + } else { + block->block_info = *rdbi; + block->cs_last = rlc->cs; + block->len = + Decoding::rlc_copy_to_aligned_buffer(rlc, + block_idx, data, rlc_data); + } LOGP(DRLCMACUL, LOGL_DEBUG, "%s: data_length=%d, data=%s\n", name(), block->len, osmo_hexdump(rlc_data, block->len)); - - /* TODO: Handle SPB != 0 -> set state to partly received - * (upper/lower) and continue with the loop, unless the other - * part is already present. - */ - /* Get/Handle TLLI */ if (rdbi->ti) { num_chunks = Decoding::rlc_data_from_ul_data( @@ -393,3 +385,131 @@ return 0; } +egprs_rlc_ul_reseg_bsn_state gprs_rlcmac_ul_tbf::handle_egprs_ul_second_seg( + const struct gprs_rlc_data_info *rlc, struct gprs_rlc_data *block, + uint8_t *data, const uint8_t block_idx) +{ + const gprs_rlc_data_block_info *rdbi = &rlc->block_info[block_idx]; + union split_block_status *spb_status = &block->spb_status; + uint8_t *rlc_data = &block->block[0]; + + if (spb_status->block_status_ul & + EGPRS_RESEG_FIRST_SEG_RXD) { + LOGP(DRLCMACUL, LOGL_DEBUG, + "---%s: Second seg is received " + "first seg is already present " + "set the status to complete\n", name()); + spb_status->block_status_ul = EGPRS_RESEG_DEFAULT; + + block->len += Decoding::rlc_copy_to_aligned_buffer(rlc, + block_idx, data, rlc_data + block->len); + block->block_info.data_len += rdbi->data_len; + } else if (spb_status->block_status_ul == EGPRS_RESEG_DEFAULT) { + LOGP(DRLCMACUL, LOGL_DEBUG, + "---%s: Second seg is received " + "first seg is not received " + "set the status to second seg received\n", + name()); + + block->len = Decoding::rlc_copy_to_aligned_buffer(rlc, + block_idx, data, + rlc_data + rlc->block_info[block_idx].data_len); + + spb_status->block_status_ul = EGPRS_RESEG_SECOND_SEG_RXD; + block->block_info = *rdbi; + } + return spb_status->block_status_ul; +} + +egprs_rlc_ul_reseg_bsn_state gprs_rlcmac_ul_tbf::handle_egprs_ul_first_seg( + const struct gprs_rlc_data_info *rlc, struct gprs_rlc_data *block, + uint8_t *data, const uint8_t block_idx) +{ + const gprs_rlc_data_block_info *rdbi = &rlc->block_info[block_idx]; + uint8_t *rlc_data = &block->block[0]; + union split_block_status *spb_status = &block->spb_status; + + if (spb_status->block_status_ul & EGPRS_RESEG_SECOND_SEG_RXD) { + LOGP(DRLCMACUL, LOGL_DEBUG, + "---%s: First seg is received " + "second seg is already present " + "set the status to complete\n", name()); + + block->len += Decoding::rlc_copy_to_aligned_buffer(rlc, + block_idx, data, rlc_data); + + block->block_info.data_len = block->len; + spb_status->block_status_ul = EGPRS_RESEG_DEFAULT; + } else if (spb_status->block_status_ul == EGPRS_RESEG_DEFAULT) { + LOGP(DRLCMACUL, LOGL_DEBUG, + "---%s: First seg is received " + "second seg is not received " + "set the status to first seg " + "received\n", name()); + + spb_status->block_status_ul = EGPRS_RESEG_FIRST_SEG_RXD; + block->len = Decoding::rlc_copy_to_aligned_buffer(rlc, + block_idx, data, rlc_data); + block->block_info = *rdbi; + } + return spb_status->block_status_ul; +} + +egprs_rlc_ul_reseg_bsn_state gprs_rlcmac_ul_tbf::handle_egprs_ul_spb( + const struct gprs_rlc_data_info *rlc, struct gprs_rlc_data *block, + uint8_t *data, const uint8_t block_idx) +{ + const gprs_rlc_data_block_info *rdbi = &rlc->block_info[block_idx]; + + LOGP(DRLCMACUL, LOGL_DEBUG, + "--%s: Got SPB(%d) " + "cs(%s) data block with BSN (%d), " + "TFI(%d).\n", name(), rdbi->spb, rlc->cs.name(), rdbi->bsn, + rlc->tfi); + + egprs_rlc_ul_reseg_bsn_state assemble_status = EGPRS_RESEG_INVALID; + + /* Section 10.4.8b of 44.060*/ + if (rdbi->spb == 2) + assemble_status = handle_egprs_ul_first_seg(rlc, + block, data, block_idx); + else if (rdbi->spb == 3) + assemble_status = handle_egprs_ul_second_seg(rlc, + block, data, block_idx); + else { + LOGP(DRLCMACUL, LOGL_ERROR, + "--%s: spb(%d) Not supported SPB for this EGPRS " + "configuration\n", + name(), rdbi->spb); + } + + /* + * When the block is successfully constructed out of segmented blocks + * upgrade the MCS to the type 2 + */ + if (assemble_status == EGPRS_RESEG_DEFAULT) { + switch (GprsCodingScheme::Scheme(rlc->cs)) { + case GprsCodingScheme::MCS3 : + block->cs_last = GprsCodingScheme::MCS6; + LOGP(DRLCMACUL, LOGL_DEBUG, + "--%s: Upgrading to MCS6\n", name()); + break; + case GprsCodingScheme::MCS2 : + block->cs_last = GprsCodingScheme::MCS5; + LOGP(DRLCMACUL, LOGL_DEBUG, + "--%s: Upgrading to MCS5\n", name()); + break; + case GprsCodingScheme::MCS1 : + LOGP(DRLCMACUL, LOGL_DEBUG, + "--%s: Upgrading to MCS4\n", name()); + block->cs_last = GprsCodingScheme::MCS4; + break; + default: + LOGP(DRLCMACUL, LOGL_ERROR, + "--%s: cs(%s) Error in Upgrading to higher MCS\n", + name(), rlc->cs.name()); + break; + } + } + return assemble_status; +} diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 1071ba3..90253b0 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -35,6 +35,7 @@ #include #include #include +#include } #include @@ -617,6 +618,457 @@ &ulreq, tbf->poll_fn); } +static gprs_rlcmac_ul_tbf *establish_ul_tbf_two_phase_spb(BTS *the_bts, + uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, + uint8_t ms_class, uint8_t egprs_ms_class) +{ + GprsMs *ms; + uint32_t rach_fn = *fn - 51; + uint32_t sba_fn = *fn + 52; + uint8_t trx_no = 0; + int tfi = 0, i = 0; + gprs_rlcmac_ul_tbf *ul_tbf; + struct gprs_rlcmac_pdch *pdch; + gprs_rlcmac_bts *bts; + RlcMacUplink_t ulreq = {0}; + struct pcu_l1_meas meas; + struct gprs_rlc_ul_header_egprs_3 *egprs3 = NULL; + GprsCodingScheme cs; + + meas.set_rssi(31); + bts = the_bts->bts_data(); + + /* needed to set last_rts_fn in the PDCH object */ + request_dl_rlc_block(bts, trx_no, ts_no, fn); + + /* + * simulate RACH, this sends an Immediate + * Assignment Uplink on the AGCH + */ + the_bts->rcv_rach(0x73, rach_fn, qta); + + /* get next free TFI */ + tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1); + + /* fake a resource request */ + ulreq.u.MESSAGE_TYPE = MT_PACKET_RESOURCE_REQUEST; + ulreq.u.Packet_Resource_Request.PayloadType = GPRS_RLCMAC_CONTROL_BLOCK; + ulreq.u.Packet_Resource_Request.ID.UnionType = 1; /* != 0 */ + ulreq.u.Packet_Resource_Request.ID.u.TLLI = tlli; + ulreq.u.Packet_Resource_Request.Exist_MS_Radio_Access_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + Count_MS_RA_capability_value = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Exist_Multislot_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + Exist_GPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + GPRS_multislot_class = ms_class; + if (egprs_ms_class) { + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Multislot_capability.Exist_EGPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Multislot_capability.EGPRS_multislot_class = ms_class; + } + + send_ul_mac_block(the_bts, trx_no, ts_no, &ulreq, sba_fn); + + /* check the TBF */ + ul_tbf = the_bts->ul_tbf_by_tfi(tfi, trx_no, ts_no); + OSMO_ASSERT(ul_tbf != NULL); + OSMO_ASSERT(ul_tbf->ta() == qta / 4); + + /* send packet uplink assignment */ + *fn = sba_fn; + request_dl_rlc_block(ul_tbf, fn); + + /* send real acknowledgement */ + send_control_ack(ul_tbf); + + check_tbf(ul_tbf); + + /* send fake data */ + uint8_t data_msg[42] = { + 0x00 | 0xf << 2, /* GPRS_RLCMAC_DATA_BLOCK << 6, CV = 15 */ + uint8_t(0 | (tfi << 1)), + uint8_t(1), /* BSN:7, E:1 */ + }; + + pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no]; + pdch->rcv_block(&data_msg[0], 23, *fn, &meas); + + ms = the_bts->ms_by_tlli(tlli); + OSMO_ASSERT(ms != NULL); + OSMO_ASSERT(ms->ta() == qta/4); + OSMO_ASSERT(ms->ul_tbf() == ul_tbf); + + /* + * TS 44.060, B.8.1 + * first seg received first, later second seg + */ + cs = GprsCodingScheme::MCS3; + egprs3 = (struct gprs_rlc_ul_header_egprs_3 *) data_msg; + egprs3->si = 1; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 1; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 2; + egprs3->pi = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + struct gprs_rlc_data *block = ul_tbf->m_rlc.block(1); + + /* check the status of the block */ + OSMO_ASSERT(block->spb_status.block_status_ul == + EGPRS_RESEG_FIRST_SEG_RXD); + + egprs3->si = 1; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 1; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 3; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + /* check the status of the block */ + OSMO_ASSERT(block->spb_status.block_status_ul == + EGPRS_RESEG_DEFAULT); + OSMO_ASSERT(block->cs_last == + GprsCodingScheme::MCS6); + /* Assembled MCS is MCS6. so the size is 74 */ + OSMO_ASSERT(block->len == 74); + + /* + * TS 44.060, B.8.1 + * second seg first, later first seg + */ + memset(data_msg, 0, sizeof(data_msg)); + + cs = GprsCodingScheme::MCS3; + egprs3 = (struct gprs_rlc_ul_header_egprs_3 *) data_msg; + egprs3->si = 1; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 2; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 3; + egprs3->pi = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + block = ul_tbf->m_rlc.block(2); + /* check the status of the block */ + OSMO_ASSERT(block->spb_status.block_status_ul == + EGPRS_RESEG_SECOND_SEG_RXD); + + egprs3->si = 1; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 2; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 2; + egprs3->pi = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + /* check the status of the block */ + OSMO_ASSERT(block->spb_status.block_status_ul == + EGPRS_RESEG_DEFAULT); + OSMO_ASSERT(block->cs_last == + GprsCodingScheme::MCS6); + /* Assembled MCS is MCS6. so the size is 74 */ + OSMO_ASSERT(block->len == 74); + + /* + * TS 44.060, B.8.1 + * Error scenario with spb as 1 + */ + cs = GprsCodingScheme::MCS3; + egprs3 = (struct gprs_rlc_ul_header_egprs_3 *) data_msg; + egprs3->si = 1; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 3; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 1; + egprs3->pi = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + block = ul_tbf->m_rlc.block(3); + /* check the status of the block */ + OSMO_ASSERT(block->spb_status.block_status_ul == + EGPRS_RESEG_DEFAULT); + /* + * TS 44.060, B.8.1 + * comparison of rlc_data for multiple scenarios + * Receive First, the second(BSN 3) + * Receive First, First then Second(BSN 4) + * Receive Second then First(BSN 5) + * after above 3 scenarios are triggered, + * rlc_data of all 3 BSN are compared + */ + + /* Initialize the data_msg */ + for (i = 0; i < 42; i++) + data_msg[i] = i; + + cs = GprsCodingScheme::MCS3; + egprs3 = (struct gprs_rlc_ul_header_egprs_3 *) data_msg; + egprs3->si = 1; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 3; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 2; + egprs3->pi = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + block = ul_tbf->m_rlc.block(3); + /* check the status of the block */ + OSMO_ASSERT(block->spb_status.block_status_ul == + EGPRS_RESEG_FIRST_SEG_RXD); + + cs = GprsCodingScheme::MCS3; + egprs3 = (struct gprs_rlc_ul_header_egprs_3 *) data_msg; + egprs3->si = 1; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 3; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 3; + egprs3->pi = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + block = ul_tbf->m_rlc.block(3); + /* check the status of the block */ + OSMO_ASSERT(block->spb_status.block_status_ul == + EGPRS_RESEG_DEFAULT); + /* Assembled MCS is MCS6. so the size is 74 */ + OSMO_ASSERT(block->len == 74); + OSMO_ASSERT(block->cs_last == + GprsCodingScheme::MCS6); + + cs = GprsCodingScheme::MCS3; + egprs3 = (struct gprs_rlc_ul_header_egprs_3 *) data_msg; + egprs3->si = 1; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 4; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 2; + egprs3->pi = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + block = ul_tbf->m_rlc.block(4); + /* check the status of the block */ + OSMO_ASSERT(block->spb_status.block_status_ul == + EGPRS_RESEG_FIRST_SEG_RXD); + + cs = GprsCodingScheme::MCS3; + egprs3 = (struct gprs_rlc_ul_header_egprs_3 *) data_msg; + egprs3->si = 1; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 4; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 2; + egprs3->pi = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + block = ul_tbf->m_rlc.block(4); + /* check the status of the block */ + OSMO_ASSERT(block->spb_status.block_status_ul == + EGPRS_RESEG_FIRST_SEG_RXD); + + cs = GprsCodingScheme::MCS3; + egprs3 = (struct gprs_rlc_ul_header_egprs_3 *) data_msg; + egprs3->si = 1; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 4; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 3; + egprs3->pi = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + block = ul_tbf->m_rlc.block(4); + /* check the status of the block */ + OSMO_ASSERT(block->spb_status.block_status_ul == + EGPRS_RESEG_DEFAULT); + OSMO_ASSERT(block->cs_last == + GprsCodingScheme::MCS6); + /* Assembled MCS is MCS6. so the size is 74 */ + OSMO_ASSERT(block->len == 74); + + cs = GprsCodingScheme::MCS3; + egprs3 = (struct gprs_rlc_ul_header_egprs_3 *) data_msg; + egprs3->si = 1; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 5; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 3; + egprs3->pi = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + block = ul_tbf->m_rlc.block(5); + /* check the status of the block */ + OSMO_ASSERT(block->spb_status.block_status_ul == + EGPRS_RESEG_SECOND_SEG_RXD); + + cs = GprsCodingScheme::MCS3; + egprs3 = (struct gprs_rlc_ul_header_egprs_3 *) data_msg; + egprs3->si = 1; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 5; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 2; + egprs3->pi = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + block = ul_tbf->m_rlc.block(5); + + /* check the status of the block */ + OSMO_ASSERT(block->spb_status.block_status_ul == + EGPRS_RESEG_DEFAULT); + OSMO_ASSERT(block->cs_last == + GprsCodingScheme::MCS6); + /* Assembled MCS is MCS6. so the size is 74 */ + OSMO_ASSERT(block->len == 74); + + OSMO_ASSERT(ul_tbf->m_rlc.block(5)->len == + ul_tbf->m_rlc.block(4)->len); + OSMO_ASSERT(ul_tbf->m_rlc.block(5)->len == + ul_tbf->m_rlc.block(3)->len); + + /* Compare the spb status of each BSNs(3,4,5). should be same */ + OSMO_ASSERT( + ul_tbf->m_rlc.block(5)->spb_status.block_status_ul == + ul_tbf->m_rlc.block(4)->spb_status.block_status_ul); + OSMO_ASSERT( + ul_tbf->m_rlc.block(5)->spb_status.block_status_ul == + ul_tbf->m_rlc.block(3)->spb_status.block_status_ul); + + /* Compare the Assembled MCS of each BSNs(3,4,5). should be same */ + OSMO_ASSERT(ul_tbf->m_rlc.block(5)->cs_last == + ul_tbf->m_rlc.block(4)->cs_last); + OSMO_ASSERT(ul_tbf->m_rlc.block(5)->cs_last == + ul_tbf->m_rlc.block(3)->cs_last); + + /* Compare the data of each BSNs(3,4,5). should be same */ + OSMO_ASSERT( + !memcmp(ul_tbf->m_rlc.block(5)->block, + ul_tbf->m_rlc.block(4)->block, ul_tbf->m_rlc.block(5)->len + )); + OSMO_ASSERT( + !memcmp(ul_tbf->m_rlc.block(5)->block, + ul_tbf->m_rlc.block(3)->block, ul_tbf->m_rlc.block(5)->len + )); + + return ul_tbf; +} + static gprs_rlcmac_ul_tbf *establish_ul_tbf_two_phase(BTS *the_bts, uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, uint8_t ms_class, uint8_t egprs_ms_class) @@ -1179,6 +1631,41 @@ gprs_bssgp_destroy(); } +static void test_tbf_egprs_two_phase_spb(void) +{ + BTS the_bts; + int ts_no = 7; + uint32_t fn = 2654218; + uint16_t qta = 31; + uint32_t tlli = 0xf1223344; + const char *imsi = "0011223344"; + uint8_t ms_class = 1; + uint8_t egprs_ms_class = 1; + gprs_rlcmac_ul_tbf *ul_tbf; + GprsMs *ms; + uint8_t test_data[256]; + + printf("=== start %s ===\n", __func__); + + memset(test_data, 1, sizeof(test_data)); + + setup_bts(&the_bts, ts_no, 4); + the_bts.bts_data()->initial_mcs_dl = 9; + the_bts.bts_data()->egprs_enabled = 1; + + ul_tbf = establish_ul_tbf_two_phase_spb(&the_bts, ts_no, tlli, &fn, qta, + ms_class, egprs_ms_class); + + ms = ul_tbf->ms(); + fprintf(stderr, "Got '%s', TA=%d\n", ul_tbf->name(), ul_tbf->ta()); + fprintf(stderr, + "Got MS: TLLI = 0x%08x, TA = %d\n", ms->tlli(), ms->ta()); + + send_dl_data(&the_bts, tlli, imsi, test_data, sizeof(test_data)); + + printf("=== end %s ===\n", __func__); +} + static void test_tbf_egprs_two_phase() { BTS the_bts; @@ -1581,6 +2068,7 @@ test_tbf_gprs_egprs(); test_tbf_ws(); test_tbf_egprs_two_phase(); + test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index dc984af..3eebe1a 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -3351,7 +3351,7 @@ TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS) changes state from ASSIGN to WAIT ASSIGN TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Scheduled UL Assignment polling on FN=2654283, TS=7 Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) (TRX=0, TS=7) -Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654270 block=8 data=4f 28 5e 24 46 68 90 f0 0a 39 00 00 88 00 08 2b 2b 2b 2b 2b 2b 2b 2b +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654270 block=8 data=4f 28 5e 24 46 68 90 f8 0a 39 00 00 88 00 08 2b 2b 2b 2b 2b 2b 2b 2b Got RLC block, coding scheme: CS-1, length: 23 (23)) +++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ ------------------------- RX : Uplink Control Block ------------------------- @@ -3398,6 +3398,262 @@ TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) changes state from NULL to ASSIGN TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) starting timer 0. TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) append +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654218 block=8 data=47 94 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +MS requests UL TBF on RACH, so we provide one: +MS requests single block allocation +RX: [PCU <- BTS] RACH qbit-ta=31 ra=0x73, Fn=2654167 (17,25,9), SBFn=2654270 +TX: Immediate Assignment Uplink (AGCH) + - TRX=0 (0) TS=7 TA=7 TSC=0 TFI=-1 USF=7 +Sending data request: trx=0 ts=0 sapi=2 arfcn=0 fn=0 block=0 data=2d 06 3f 10 0f 00 00 73 8b 29 07 00 c0 0c 5a 43 2b 2b 2b 2b 2b 2b 2b +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +MS requests UL TBF in packet resource request of single block, so we provide one: +MS supports EGPRS multislot class 1. +********** TBF starts here ********** +Allocating UL TBF: MS_CLASS=1/1 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 1 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 1 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign uplink TS=7 TFI=0 USF=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 00 +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=ASSIGN EGPRS) starting timer 3169. +Modifying MS object, UL TLLI: 0x00000000 -> 0xf1223344, not yet confirmed +Modifying MS object, TLLI = 0xf1223344, TA 0 -> 7 +Change control TS to 7 until assinment is complete. +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS)s start Packet Uplink Assignment (PACCH) ++++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++ +------------------------- TX : Packet Uplink Assignment ------------------------- +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS): Scheduling polling at FN 2654283 TS 7 +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS) changes state from ASSIGN to WAIT ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Scheduled UL Assignment polling on FN=2654283, TS=7 +Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) (TRX=0, TS=7) +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654270 block=8 data=4f 28 5e 24 46 68 90 f8 0a 39 00 00 88 00 08 2b 2b 2b 2b 2b 2b 2b 2b +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Packet Control Ack +TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) changes state from WAIT ASSIGN to FLOW +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=0 .. V(R)=0) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got CS-1 RLC data block: CV=15, BSN=0, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 0 storing in window (0..63) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 1 +- Taking block 0 out, raising V(Q) to 1 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=0 CV=15 +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1f 08 40 c9 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=1, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=1) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=1, SPB=2, PI=0, E=1, TI=0, bitoffs=33 +- BSN 1 storing in window (1..64) +--TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got SPB(2) cs(MCS-3) data block with BSN (1), TFI(0). +---TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): First seg is received second seg is not received set the status to first seg received +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1f 08 40 cd 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=1, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=1) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=1, SPB=3, PI=0, E=1, TI=0, bitoffs=33 +- BSN 1 storing in window (1..64) +--TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got SPB(3) cs(MCS-3) data block with BSN (1), TFI(0). +---TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Second seg is received first seg is already present set the status to complete +--TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Upgrading to MCS6 +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=74, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 2 +- Taking block 1 out, raising V(Q) to 2 +- Assembling frames: (len=74) +-- Frame 1 starts at offset 0, length=74, is_complete=0 +- No gaps in received block, last block: BSN=1 CV=7 +- Scheduling Ack/Nack, because MS is stalled. +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1f 10 40 cd 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=1, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=2 .. V(R)=2) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=2, SPB=3, PI=0, E=1, TI=0, bitoffs=33 +- BSN 2 storing in window (2..65) +--TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got SPB(3) cs(MCS-3) data block with BSN (2), TFI(0). +---TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Second seg is received first seg is not received set the status to second seg received +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1f 10 40 c9 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=1, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=2 .. V(R)=2) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=2, SPB=2, PI=0, E=1, TI=0, bitoffs=33 +- BSN 2 storing in window (2..65) +--TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got SPB(2) cs(MCS-3) data block with BSN (2), TFI(0). +---TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): First seg is received second seg is already present set the status to complete +--TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Upgrading to MCS6 +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=74, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 3 +- Taking block 2 out, raising V(Q) to 3 +- Assembling frames: (len=74) +-- Frame 1 starts at offset 0, length=74, is_complete=0 +- No gaps in received block, last block: BSN=2 CV=7 +- Scheduling Ack/Nack, because MS is stalled. +- Sending Ack/Nack is already triggered, don't schedule! +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1f 18 40 c5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=1, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=3 .. V(R)=3) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=3, SPB=1, PI=0, E=1, TI=0, bitoffs=33 +- BSN 3 storing in window (3..66) +--TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got SPB(1) cs(MCS-3) data block with BSN (3), TFI(0). +--TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): spb(1) Not supported SPB for this EGPRS configuration +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1f 18 40 c9 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 +Got MCS-3 RLC block: R=1, SI=1, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=3 .. V(R)=3) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=3, SPB=2, PI=0, E=1, TI=0, bitoffs=33 +- BSN 3 storing in window (3..66) +--TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got SPB(2) cs(MCS-3) data block with BSN (3), TFI(0). +---TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): First seg is received second seg is not received set the status to first seg received +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1f 18 40 cd 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 +Got MCS-3 RLC block: R=1, SI=1, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=3 .. V(R)=3) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=3, SPB=3, PI=0, E=1, TI=0, bitoffs=33 +- BSN 3 storing in window (3..66) +--TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got SPB(3) cs(MCS-3) data block with BSN (3), TFI(0). +---TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Second seg is received first seg is already present set the status to complete +--TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Upgrading to MCS6 +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=74, data=82 02 83 03 84 04 85 05 86 06 87 07 88 08 89 09 8a 0a 8b 0b 8c 0c 8d 0d 8e 0e 8f 0f 90 10 91 11 92 12 93 13 94 82 02 83 03 84 04 85 05 86 06 87 07 88 08 89 09 8a 0a 8b 0b 8c 0c 8d 0d 8e 0e 8f 0f 90 10 91 11 92 12 93 13 94 +- Raising V(R) to 4 +- Taking block 3 out, raising V(Q) to 4 +- Assembling frames: (len=74) +-- Frame 1 starts at offset 0, length=74, is_complete=0 +- No gaps in received block, last block: BSN=3 CV=7 +- Scheduling Ack/Nack, because MS is stalled. +- Sending Ack/Nack is already triggered, don't schedule! +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1f 20 40 c9 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 +Got MCS-3 RLC block: R=1, SI=1, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=4 .. V(R)=4) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=4, SPB=2, PI=0, E=1, TI=0, bitoffs=33 +- BSN 4 storing in window (4..67) +--TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got SPB(2) cs(MCS-3) data block with BSN (4), TFI(0). +---TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): First seg is received second seg is not received set the status to first seg received +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1f 20 40 c9 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 +Got MCS-3 RLC block: R=1, SI=1, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=4 .. V(R)=4) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=4, SPB=2, PI=0, E=1, TI=0, bitoffs=33 +- BSN 4 storing in window (4..67) +--TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got SPB(2) cs(MCS-3) data block with BSN (4), TFI(0). +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1f 20 40 cd 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 +Got MCS-3 RLC block: R=1, SI=1, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=4 .. V(R)=4) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=4, SPB=3, PI=0, E=1, TI=0, bitoffs=33 +- BSN 4 storing in window (4..67) +--TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got SPB(3) cs(MCS-3) data block with BSN (4), TFI(0). +---TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Second seg is received first seg is already present set the status to complete +--TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Upgrading to MCS6 +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=74, data=82 02 83 03 84 04 85 05 86 06 87 07 88 08 89 09 8a 0a 8b 0b 8c 0c 8d 0d 8e 0e 8f 0f 90 10 91 11 92 12 93 13 94 82 02 83 03 84 04 85 05 86 06 87 07 88 08 89 09 8a 0a 8b 0b 8c 0c 8d 0d 8e 0e 8f 0f 90 10 91 11 92 12 93 13 94 +- Raising V(R) to 5 +- Taking block 4 out, raising V(Q) to 5 +- Assembling frames: (len=74) +-- Frame 1 starts at offset 0, length=74, is_complete=0 +- No gaps in received block, last block: BSN=4 CV=7 +- Scheduling Ack/Nack, because MS is stalled. +- Sending Ack/Nack is already triggered, don't schedule! +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1f 28 40 cd 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 +Got MCS-3 RLC block: R=1, SI=1, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=5 .. V(R)=5) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=5, SPB=3, PI=0, E=1, TI=0, bitoffs=33 +- BSN 5 storing in window (5..68) +--TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got SPB(3) cs(MCS-3) data block with BSN (5), TFI(0). +---TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Second seg is received first seg is not received set the status to second seg received +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1f 28 40 c9 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 +Got MCS-3 RLC block: R=1, SI=1, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=5 .. V(R)=5) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=5, SPB=2, PI=0, E=1, TI=0, bitoffs=33 +- BSN 5 storing in window (5..68) +--TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got SPB(2) cs(MCS-3) data block with BSN (5), TFI(0). +---TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): First seg is received second seg is already present set the status to complete +--TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Upgrading to MCS6 +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=74, data=82 02 83 03 84 04 85 05 86 06 87 07 88 08 89 09 8a 0a 8b 0b 8c 0c 8d 0d 8e 0e 8f 0f 90 10 91 11 92 12 93 13 94 82 02 83 03 84 04 85 05 86 06 87 07 88 08 89 09 8a 0a 8b 0b 8c 0c 8d 0d 8e 0e 8f 0f 90 10 91 11 92 12 93 13 94 +- Raising V(R) to 6 +- Taking block 5 out, raising V(Q) to 6 +- Assembling frames: (len=74) +-- Frame 1 starts at offset 0, length=74, is_complete=0 +- No gaps in received block, last block: BSN=5 CV=7 +- Scheduling Ack/Nack, because MS is stalled. +- Sending Ack/Nack is already triggered, don't schedule! +Got 'TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS)', TA=7 +Got MS: TLLI = 0xf1223344, TA = 7 +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=1/1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign downlink TS=7 TFI=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0xf1223344, TBF = TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 80 +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +Modifying MS object, TLLI: 0xf1223344 confirmed +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) [DOWNLINK] START +Modifying MS object, TLLI = 0xf1223344, IMSI '' -> '0011223344' +Send dowlink assignment on PACCH, because TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) exists +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) starting timer 0. +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) append Searching for first unallocated TFI: TRX=0 Found TFI=0. ********** TBF starts here ********** diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 8a7862f..0e2edc4 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -32,6 +32,8 @@ === end test_tbf_ws === === start test_tbf_egprs_two_phase === === end test_tbf_egprs_two_phase === +=== start test_tbf_egprs_two_phase_spb === +=== end test_tbf_egprs_two_phase_spb === === start test_tbf_egprs_dl === Testing MCS-1 Testing MCS-2 -- To view, visit https://gerrit.osmocom.org/537 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I39ca53218b6e0982abc2ab9c703c24c8bf0a09c0 Gerrit-PatchSet: 9 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Tue Aug 2 07:01:25 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Tue, 2 Aug 2016 07:01:25 +0000 Subject: [PATCH] openbsc[master]: ci: Attempt to disable doxygen warnings of dependencies In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/616 to look at the new patch set (#2). ci: Attempt to disable doxygen warnings of dependencies We do not want to see doxygen warnings when building the libosmocore dependency. Change-Id: I4640cb5b91d54641e8e5b2f096c3bca49bfff60e --- M contrib/jenkins.sh 1 file changed, 3 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/16/616/2 diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index 755ff1c..3c60996 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -12,6 +12,7 @@ build_dep() { project="$1" branch="$2" + cfg="$3" set +x echo echo @@ -32,11 +33,11 @@ fi git rev-parse HEAD autoreconf --install --force - ./configure --prefix="$inst" + ./configure --prefix="$inst" $cfg $MAKE $PARALLEL_MAKE install } -build_dep libosmocore +build_dep libosmocore "" ac_cv_path_DOXYGEN=false # All below builds want this PKG_CONFIG_PATH export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH" -- To view, visit https://gerrit.osmocom.org/616 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I4640cb5b91d54641e8e5b2f096c3bca49bfff60e Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Tue Aug 2 07:04:24 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Tue, 2 Aug 2016 07:04:24 +0000 Subject: openbsc[master]: ci: Attempt to disable doxygen warnings of dependencies In-Reply-To: References: Message-ID: Patch Set 1: (1 comment) https://gerrit.osmocom.org/#/c/616/1/contrib/jenkins.sh File contrib/jenkins.sh: Line 40: build_dep libosmocore master ac_cv_path_DOXYGEN=false > you could pass "" instead of master :) Using "" now well, I am lazy right now and would just inject the result. Cross compiling a lot of software helps understanding autoconf. E.g. some tests are compiled and then executed and this doesn't work on cross compiling, so for certain standard tests we injected the test result. -- To view, visit https://gerrit.osmocom.org/616 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I4640cb5b91d54641e8e5b2f096c3bca49bfff60e Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 2 07:07:05 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Tue, 2 Aug 2016 07:07:05 +0000 Subject: osmo-bts[master]: Simplify pcu_tx_data_ind() In-Reply-To: References: Message-ID: Patch Set 2: (1 comment) https://gerrit.osmocom.org/#/c/611/2/src/common/pcu_sock.c File src/common/pcu_sock.c: Line 362: data_ind->arfcn = 0; /* FIXME: do we really need actual ARFCN value? */ A refactoring should preserve semantic and I don't know if the arfcn is useful here. -- To view, visit https://gerrit.osmocom.org/611 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ib196a36ae2bae36d37144337bed71f40414dbb64 Gerrit-PatchSet: 2 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 2 07:08:15 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Tue, 2 Aug 2016 07:08:15 +0000 Subject: osmo-pcu[master]: Handle Timing Advance IE properly In-Reply-To: References: Message-ID: Patch Set 5: Not having verified the actual csn1 write code, the structure looks fine to me. -- To view, visit https://gerrit.osmocom.org/552 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I786bf7fc999d401cc3d9e7f1e7a1fba953b5d458 Gerrit-PatchSet: 5 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 2 07:09:23 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Tue, 2 Aug 2016 07:09:23 +0000 Subject: osmo-pcu[master]: Handle Timing Advance IE properly In-Reply-To: References: Message-ID: Patch Set 5: (1 comment) https://gerrit.osmocom.org/#/c/552/5/src/tbf.cpp File src/tbf.cpp: Line 1067: bts_data()->gamma, -1, 0, is_egprs_enabled()); Hmm, maybe remove that 0 here and have that inside the write_packet_uplink_assignment until we make use of TA in the TBF? -- To view, visit https://gerrit.osmocom.org/552 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I786bf7fc999d401cc3d9e7f1e7a1fba953b5d458 Gerrit-PatchSet: 5 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 2 07:10:47 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Tue, 2 Aug 2016 07:10:47 +0000 Subject: osmo-pcu[master]: Use qbit-TA to update Timing Advance In-Reply-To: References: Message-ID: Patch Set 6: (1 comment) https://gerrit.osmocom.org/#/c/544/6/src/pcu_l1_if.h File src/pcu_l1_if.h: Line 36: void bts_update_tbf_ta(const char *p, uint32_t fn, uint8_t trx_no, uint8_t ts, don't we have a header file for the bts? -- To view, visit https://gerrit.osmocom.org/544 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I96fdbb20b09fb85fdd9fb6dcf3c25f6bee7f80e4 Gerrit-PatchSet: 6 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 2 07:12:57 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Tue, 2 Aug 2016 07:12:57 +0000 Subject: openbsc[master]: Improve code re-use In-Reply-To: References: Message-ID: Patch Set 1: So who wants to use this as a module? If there is a user split codec/net from app? -- To view, visit https://gerrit.osmocom.org/631 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I9bad8f0dd1d69bd28816bf047d85840e3411bb9c Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: daniel Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 2 07:34:16 2016 From: gerrit-no-reply at lists.osmocom.org (pravin) Date: Tue, 2 Aug 2016 07:34:16 +0000 Subject: osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Patch Set 7: (1 comment) https://gerrit.osmocom.org/#/c/416/7/tests/tbf/TbfTest.cpp File tests/tbf/TbfTest.cpp: PS7, Line 71: }, 1 is missing to enable verify -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 7 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: pravin Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 2 07:36:40 2016 From: gerrit-no-reply at lists.osmocom.org (pravin) Date: Tue, 2 Aug 2016 07:36:40 +0000 Subject: [PATCH] osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Hello Max, Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/416 to look at the new patch set (#8). Add decoding of compressed bitmap in EPDAN Implemented tree based algorithm to decode compressed bitmap in EPDAN as described in section 9.1.10 of 3GPP 44.060. This algorithm intends to improve the performance over existing method. Test case is added to validate decompressed result of the bitmap Present in EPDAN. Test is done for multiple bitmaps of varying length. Invalid inputs are also part of the test vector. Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce --- M src/Makefile.am M src/decoding.cpp M src/decoding.h A src/egprs_rlc_compression.cpp A src/egprs_rlc_compression.h M src/pcu_main.cpp M tests/tbf/TbfTest.cpp 7 files changed, 490 insertions(+), 38 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/16/416/8 diff --git a/src/Makefile.am b/src/Makefile.am index 9bdec2f..9b047e7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -62,7 +62,8 @@ rlc.cpp \ osmobts_sock.cpp \ gprs_codel.c \ - gprs_coding_scheme.cpp + gprs_coding_scheme.cpp \ + egprs_rlc_compression.cpp bin_PROGRAMS = \ osmo-pcu @@ -94,7 +95,8 @@ pcu_utils.h \ cxx_linuxlist.h \ gprs_codel.h \ - gprs_coding_scheme.h + gprs_coding_scheme.h \ + egprs_rlc_compression.h osmo_pcu_SOURCES = pcu_main.cpp diff --git a/src/decoding.cpp b/src/decoding.cpp index 7c00ff7..3f8b11b 100644 --- a/src/decoding.cpp +++ b/src/decoding.cpp @@ -651,11 +651,10 @@ int crbb_len = 0; int num_blocks = 0; struct bitvec urbb; - int i; + int i, rc; bool have_bitmap; int implicitly_acked_blocks; int ssn = desc->STARTING_SEQUENCE_NUMBER; - int rc; if (desc->FINAL_ACK_INDICATION) return handle_final_ack(bits, bsn_begin, bsn_end, window); @@ -695,27 +694,22 @@ if (crbb_len > 0) { int old_len = bits->cur_bit; - struct bitvec crbb; - crbb.data = (uint8_t *)desc->CRBB; - crbb.data_len = sizeof(desc->CRBB); - crbb.cur_bit = desc->CRBB_LENGTH; - - rc = osmo_t4_decode(&crbb, desc->CRBB_STARTING_COLOR_CODE, - bits); - + LOGP(DRLCMACDL, LOGL_DEBUG, "Compress bitmap exist," + "CRBB LEN =%d and Starting color code =%d", + desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE); + rc = decompress_crbb(desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE, + desc->CRBB, bits); if (rc < 0) { LOGP(DRLCMACUL, LOGL_NOTICE, - "Failed to decode CRBB: " - "length %d, data '%s'\n", - desc->CRBB_LENGTH, - osmo_hexdump(crbb.data, crbb.data_len)); + "Failed to decode CRBB: length %d, data '%s'\n", + desc->CRBB_LENGTH, osmo_hexdump( + desc->CRBB, (desc->CRBB_LENGTH + 7)/8)); /* We don't know the SSN offset for the URBB, - * return what we have so far and assume the - * bitmap has stopped here */ + * return what we have so far and assume the + * bitmap has stopped here */ goto aborted; } - LOGP(DRLCMACDL, LOGL_DEBUG, "CRBB len: %d, decoded len: %d, cc: %d, crbb: '%s'\n", desc->CRBB_LENGTH, bits->cur_bit - old_len, diff --git a/src/decoding.h b/src/decoding.h index d1371d5..cb18fcb 100644 --- a/src/decoding.h +++ b/src/decoding.h @@ -76,6 +76,12 @@ struct gprs_rlc_dl_window *window); static int decode_gprs_acknack_bits( const Ack_Nack_Description_t *desc, - bitvec *bits, int *bsn_begin, int *bsn_end, - gprs_rlc_dl_window *window); + bitvec * bits, int *bsn_begin, int *bsn_end, + gprs_rlc_dl_window * window); + static int decompress_crbb( + int8_t compress_bmap_len, + uint8_t clr_code_bit, + const uint8_t *orig_buf, + bitvec * dest + ); }; diff --git a/src/egprs_rlc_compression.cpp b/src/egprs_rlc_compression.cpp new file mode 100644 index 0000000..b9e15f2 --- /dev/null +++ b/src/egprs_rlc_compression.cpp @@ -0,0 +1,310 @@ +/* egprs_rlc_compression.h +* Routines for EGPRS RLC bitmap compression handling +*/ +#include +#include +#include + +extern "C" { +#include +#include +#include +} + +void *tall_tree_ctx; +egprs_compress *egprs_compress::s_instance = 0; +Node *egprs_compress::ones_list = NULL; +Node *egprs_compress::zeros_list = NULL; + +Node *egprs_compress::create_tree_node() +{ + Node *new_node; + new_node = talloc(tall_tree_ctx, Node); + new_node->left = NULL; + new_node->right = NULL; + new_node->run_length = -1; + return new_node; +} + +void egprs_compress::build_codeword(Node *root, const char *cdwd[]) +{ + Node *iter; /* iterate the node on the tree */ + int len; /* length of the code word */ + int i; /* iterater */ + int idx; /* interate index of the code word table */ + + root->left = NULL; + root->right = NULL; + root->run_length = -1; + + for (idx = 0; idx < MAX_CDWDTBL_LEN; idx++) { + len = strlen((const char *)cdwd[idx]); + iter = root; + for (i = 0; i < len; i++) { + if (cdwd[idx][i] == '0') { + if (iter->left == NULL) + iter->left = create_tree_node(); + iter = iter->left; + } else if (cdwd[idx][i] == '1') { + if (iter->right == NULL) + iter->right = create_tree_node(); + iter = iter->right; + } + } + if (iter != NULL) { + if (idx < 64) + (iter->run_length) = idx; + else + (iter->run_length) = (idx - 63) * 64; + } + } +} + +const char *one_run_len_code_list[MAX_CDWDTBL_LEN] = { + "00110101", + "000111", + "0111", + "1000", + "1011", + "1100", + "1110", + "1111", + "10011", + "10100", + "00111", + "01000", + "001000", + "000011", + "110100", + "110101", + "101010", + "101011", + "0100111", + "0001100", + "0001000", + "0010111", + "0000011", + "0000100", + "0101000", + "0101011", + "0010011", + "0100100", + "0011000", + "00000010", + "00000011", + "00011010", + "00011011", + "00010010", + "00010011", + "00010100", + "00010101", + "00010110", + "00010111", + "00101000", + "00101001", + "00101010", + "00101011", + "00101100", + "00101101", + "00000100", + "00000101", + "00001010", + "00001011", + "01010010", + "01010011", + "01010100", + "01010101", + "00100100", + "00100101", + "01011000", + "01011001", + "01011010", + "01011011", + "01001010", + "01001011", + "00110010", + "00110011", + "00110100", + "11011", + "10010", + "010111", + "0110111", + "00110110", + "00110111", + "01100100", + "01100101", + "01101000", + "01100111", + "011001100", + "011001101", + "011010010", + "011010011", + "011010100" +}; + +const char *zero_run_len_code_list[MAX_CDWDTBL_LEN] = { + "0000110111", + "10", + "11", + "010", + "011", + "0011", + "0010", + "00011", + "000101", + "000100", + "0000100", + "0000101", + "0000111", + "00000100", + "00000111", + "000011000", + "0000010111", + "0000011000", + "0000001000", + "00001100111", + "00001101000", + "00001101100", + "00000110111", + "00000101000", + "00000010111", + "00000011000", + "000011001010", + "000011001011", + "000011001100", + "000011001101", + "000001101000", + "000001101001", + "000001101010", + "000001101011", + "000011010010", + "000011010011", + "000011010100", + "000011010101", + "000011010110", + "000011010111", + "000001101100", + "000001101101", + "000011011010", + "000011011011", + "000001010100", + "000001010101", + "000001010110", + "000001010111", + "000001100100", + "000001100101", + "000001010010", + "000001010011", + "000000100100", + "000000110111", + "000000111000", + "000000100111", + "000000101000", + "000001011000", + "000001011001", + "000000101011", + "000000101100", + "000001011010", + "000001100110", + "000001100111", + "0000001111", + "000011001000", + "000011001001", + "000001011011", + "000000110011", + "000000110100", + "000000110101", + "0000001101100", + "0000001101101", + "0000001001010", + "0000001001011", + "0000001001100", + "0000001001101", + "0000001110010", + "0000001110011" +}; + +int search_runlen( + Node *root, /* root of Ones or Zeros tree */ + const uint8_t *bmbuf, /* Received compressed bitmap buf */ + uint8_t bit_pos, /* the start bit pos to read codeword */ + uint8_t *len_codewd, /* length of code word */ + uint16_t *rlen) +{ + Node *iter; + uint8_t dir; + + iter = root; + *len_codewd = 0; + + while (iter->run_length == -1) { + if ((iter->left == NULL) && (iter->right == NULL)) + return -1; + + /* get the bit value at the bitpos and put it in right most of dir */ + dir = ((bmbuf[BITS_TO_BYTES(bit_pos)-1] + >>(7-(MOD8(bit_pos)))) & 0x01); + (bit_pos)++; + (*len_codewd)++; + + if (((dir&0x01) == 0) && (iter->left != NULL)) + iter = iter->left; + + else if (((dir&0x01) == 1) && (iter->right != NULL)) + iter = iter->right; + else + return -1; + } + (*rlen) = (iter->run_length); + + return 1; +} /* search_runlen */ + +int Decoding::decompress_crbb( + int8_t compress_bmap_len, /* compressed bitmap length */ + uint8_t clr_code_bit, /* run length of Ones or Zeros */ + const uint8_t *orig_crbb_buf, /* received block crbb bitmap */ + bitvec * dest) +{ + + uint8_t bit_pos = 0; + uint8_t data = 0x0; + node *list = NULL; + uint8_t nbits = 0; /* number of bits of codeword */ + uint16_t run_length = 0; + uint16_t cbmaplen = 0; /* compressed bitmap part after decompression */ + unsigned wp = dest->cur_bit; + int rc = 0; + egprs_compress *compress = egprs_compress::instance(); + + while (compress_bmap_len > 0) { + if (clr_code_bit == 1) { + data = 0xff; + list = compress->ones_list; + } else { + data = 0x00; + list = compress->zeros_list; + } + rc = search_runlen(list, orig_crbb_buf, + bit_pos, &nbits, &run_length); + if (rc == -1) + return -1; + /*If run length > 64, need makeup and terminating code*/ + if (run_length < 64) + clr_code_bit ? clr_code_bit = 0 : clr_code_bit = 1; + cbmaplen = cbmaplen + run_length; + /* put run length of Ones in uncompressed bitmap */ + while (run_length != 0) { + if (run_length > 8) { + bitvec_write_field(dest, wp, data, 8); + run_length = run_length - 8; + } else { + bitvec_write_field(dest, wp, data, run_length); + run_length = 0; + } + } + bit_pos = bit_pos + nbits; + compress_bmap_len = compress_bmap_len - nbits; + } + return 0; +} /* Decompress_CRBB */ diff --git a/src/egprs_rlc_compression.h b/src/egprs_rlc_compression.h new file mode 100644 index 0000000..78a6d12 --- /dev/null +++ b/src/egprs_rlc_compression.h @@ -0,0 +1,64 @@ +/* egprs_rlc_compression.h + * Routines for EGPRS RLC bitmap compression handling + */ +#include +#include + +extern "C" { +#include +} + +#include +#include +#include + +#define MAX_CDWDTBL_LEN 79 /* total number of codewords */ +#define BITS_TO_BYTES(X) ((X ? (X/8):0)+1) +#define MOD8(X) (((X)+8) & (0x07)) + +typedef struct node { + struct node *left; + struct node *right; + int run_length; +} Node; + +extern const char *one_run_len_code_list[MAX_CDWDTBL_LEN]; +extern const char *zero_run_len_code_list[MAX_CDWDTBL_LEN]; +extern void *tall_tree_ctx; + +/* Creating singleton class + */ +class egprs_compress +{ + static egprs_compress *s_instance; + egprs_compress() + { + ones_list = talloc(tall_tree_ctx, Node); + zeros_list = talloc(tall_tree_ctx, Node); + } + Node *create_tree_node(); + void build_codeword(Node *root, const char *cdwd[]); + void free_codeword(Node *root); + ~egprs_compress() + { + s_instance = NULL; + } +public: + static Node *ones_list; + static Node *zeros_list; + + void decode_tree_init(void) + { + instance()->build_codeword( + ones_list, one_run_len_code_list); + instance()->build_codeword( + zeros_list, zero_run_len_code_list); + } + static egprs_compress *instance() + { + if (!s_instance) + s_instance = new egprs_compress; + + return s_instance; + } +}; diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2d86cda..ea23ba1 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -28,6 +28,7 @@ #include #include #include +#include extern "C" { #include "pcu_vty.h" #include @@ -168,6 +169,9 @@ if (!tall_pcu_ctx) return -ENOMEM; bv_tall_ctx = tall_pcu_ctx; + tall_tree_ctx = talloc_named_const(tall_pcu_ctx, 0, "decode-tree context"); + if (!tall_tree_ctx) + return -ENOMEM; bts = bts_main_data(); bts->fc_interval = 1; @@ -253,6 +257,8 @@ if (!bts->alloc_algorithm) bts->alloc_algorithm = alloc_algorithm_dynamic; + egprs_compress::instance()->decode_tree_init(); + rc = pcu_l1if_open(); if (rc < 0) @@ -292,6 +298,5 @@ talloc_report_full(tall_pcu_ctx, stderr); talloc_free(tall_pcu_ctx); - return 0; } diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 1071ba3..a404f29 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -26,10 +26,11 @@ #include "pcu_utils.h" #include "gprs_bssgp_pcu.h" #include "pcu_l1_if.h" - +#include "egprs_rlc_compression.h" +#include "decoding.h" extern "C" { #include "pcu_vty.h" - +#include #include #include #include @@ -39,8 +40,41 @@ #include +#define NUMBER_OF_TEST_CASE 9 +#define NEW 1 +#define DELTA 1000 +#define MASK(n) (0xFF << (8-n)) void *tall_pcu_ctx; +extern void *tall_tree_ctx; int16_t spoof_mnc = 0, spoof_mcc = 0; +struct test_data { + int8_t crbb_len; + uint8_t cc; + uint8_t crbb_data[23]; /* compressed data */ + uint8_t ucmp_data[40]; /* uncompressed data */ + int ucmp_len; + int verify; +}test[NUMBER_OF_TEST_CASE] = { { (int8_t)67, (uint8_t)1, {0x02, 0x0c, 0xa0, 0x30, 0xcb, 0x1a, 0x0c, 0xe3, 0x6c}, + {0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xf8, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, + 0xdb}, (int)194, 1}, + {(int8_t)40, (uint8_t)1, {0x53, 0x06, 0xc5, 0x40, 0x6d}, {0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, + 0x00, 0x00, 0x00, 0x03}, (int)182, 1}, + { (int8_t)8, (uint8_t)1, {0x02}, {0xff, 0xff, 0xff, 0xf8}, (int)29, 1}, + { (int8_t)103, (uint8_t)1, {0x02, 0x0c, 0xe0, 0x41, 0xa0, 0x0c, 0x36, 0x0d, 0x03, + 0x71, 0xb0, 0x6e, 0x24}, {0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xf8, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, + 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff}, + (int)288, 1}, + /* Test vector from libosmocore test */ + { (int8_t)32, (uint8_t)0, {0xde, 0x88, 0x75, 0x65, 0x80}, {0x37, 0x47, 0x81, 0xf0}, (int)28, 1}, + { (int8_t)18, (uint8_t)1, {0xdd, 0x41, 0x00}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00}, (int)90, 1}, + /*Invalid inputs*/ + { (int8_t)18, (uint8_t)1, {0x1E, 0x70, 0xc0}, {0x0}, (int)0, 0}, + { (int8_t)14, (uint8_t)1, {0x00, 0x1E, 0x7c}, {0x0}, (int)0, 0}, + { (int8_t)24, (uint8_t)0, {0x00, 0x00, 0x00}, {0x0}, (int)0, 0} }; static void check_tbf(gprs_rlcmac_tbf *tbf) { @@ -51,19 +85,52 @@ OSMO_ASSERT(tbf->T != 0); } -/* -static unsigned inc_fn(fn) +/* To verify the result with expected result */ +int check_result(bitvec bits, uint8_t *exp_data, int exp_len) { - unsigned next_fn; - - next_fn = fn + 4; - if ((block_nr % 3) == 2) - next_fn ++; - next_fn = next_fn % 2715648; - - return next_fn; + if (bits.cur_bit != exp_len) + return 0; + size_t n = (exp_len / 8); + int rem = (exp_len % 8); + if (memcmp (exp_data, bits.data, n) == 0) { + if (rem == 0) + return 1; + if ((bits.data[n] & MASK(rem)) == ((*(exp_data + n)) & MASK(rem))) + return 1; + else + return 0; + } else { + return 0; + } } -*/ + +/* To test decoding of compressed bitmap by Tree based method + * and to verify the result with expected result + * for invalid input verfication is suppressed */ +static void test_EPDAN_decode_tree() +{ + bitvec dest; + int init_flag = 1; + int itr; + uint8_t bits_data[RLC_EGPRS_MAX_WS/8]; + + for (itr = 0 ; itr < NUMBER_OF_TEST_CASE ; itr++) { + dest.data = bits_data; + dest.data_len = sizeof(bits_data); + dest.cur_bit = 0; + memset(dest.data, 0, sizeof(bits_data)); + Decoding::decompress_crbb(test[itr].crbb_len, test[itr].cc, test[itr].crbb_data, &dest); + + if (init_flag) + init_flag = 0; + if (test[itr].verify) { + if (check_result(dest, test[itr].ucmp_data, test[itr].ucmp_len) == 0) { + LOGP (DRLCMACDL, LOGL_DEBUG, "Tree based decoding :Error\n"); + OSMO_ASSERT(0); + } + } + } +} static void test_tbf_base() { @@ -1554,7 +1621,9 @@ tall_pcu_ctx = talloc_named_const(NULL, 1, "moiji-mobile TbfTest context"); if (!tall_pcu_ctx) abort(); - + tall_tree_ctx = talloc_named_const(tall_pcu_ctx, 0, "decode-tree context"); + if (!tall_tree_ctx) + abort(); msgb_set_talloc_ctx(tall_pcu_ctx); osmo_init_logging(&debug_log_info); log_set_use_color(osmo_stderr_target, 0); @@ -1563,7 +1632,8 @@ vty_init(&pcu_vty_info); pcu_vty_init(&debug_log_info); - + /*initialization_of_tree*/ + egprs_compress::instance()->decode_tree_init(); test_tbf_base(); test_tbf_tlli_update(); test_tbf_final_ack(TEST_MODE_STANDARD); @@ -1583,9 +1653,10 @@ test_tbf_egprs_two_phase(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); - + test_EPDAN_decode_tree(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); + talloc_free(tall_pcu_ctx); return EXIT_SUCCESS; } -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 8 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: pravin From gerrit-no-reply at lists.osmocom.org Tue Aug 2 07:42:03 2016 From: gerrit-no-reply at lists.osmocom.org (pravin) Date: Tue, 2 Aug 2016 07:42:03 +0000 Subject: osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Patch Set 8: I have tried to address all the comments. please let me know if anything need to be updated further. -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 8 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: pravin Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 2 08:04:38 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Tue, 2 Aug 2016 08:04:38 +0000 Subject: openbsc[master]: Improve code re-use In-Reply-To: References: Message-ID: Patch Set 1: It'll be used by another app developed as part of OS#1646. -- To view, visit https://gerrit.osmocom.org/631 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I9bad8f0dd1d69bd28816bf047d85840e3411bb9c Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: daniel Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 2 09:20:35 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Tue, 2 Aug 2016 09:20:35 +0000 Subject: [PATCH] osmo-pcu[master]: Use qbit-TA to update Timing Advance In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/544 to look at the new patch set (#7). Use qbit-TA to update Timing Advance Separate qbit-TA to TA conversion into separate function and use it for computing and updating Timing Advance. Note: the code was tested with TA=0 only to make sure it does not introduce regressions. Change-Id: I96fdbb20b09fb85fdd9fb6dcf3c25f6bee7f80e4 Fixes: OS#1531 --- M src/bts.cpp M src/bts.h M src/osmo-bts-litecell15/lc15_l1_if.c M src/osmo-bts-sysmo/sysmo_l1_if.c M src/pcu_l1_if.h 5 files changed, 39 insertions(+), 49 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/44/544/7 diff --git a/src/bts.cpp b/src/bts.cpp index c53c92c..763079f 100644 --- a/src/bts.cpp +++ b/src/bts.cpp @@ -477,7 +477,7 @@ int plen; uint8_t usf = 7; uint8_t tsc; - uint16_t ta; + uint8_t ta = qta2ta(qta); rach_frame(); @@ -492,12 +492,6 @@ "but we force two phase access\n"); sb = 1; } - if (qta < 0) - qta = 0; - if (qta > 252) - qta = 252; - - ta = qta >> 2; if (sb) { rc = sba()->alloc(&trx_no, &ts_no, &sb_fn, ta); @@ -1407,6 +1401,24 @@ return rc; } +void bts_update_tbf_ta(const char *p, uint32_t fn, uint8_t trx_no, uint8_t ts, + uint8_t ta) +{ + struct gprs_rlcmac_bts *bts_data = bts_main_data(); + BTS *bts = bts_data->bts; + struct gprs_rlcmac_ul_tbf *tbf = bts->ul_tbf_by_poll_fn(fn, trx_no, ts); + if(!tbf) + LOGP(DL1IF, LOGL_DEBUG, "[%s] update TA = %u ignored due to " + "unknown UL TBF on TRX = %d, TS = %d, FN = %d\n", + p, ta, trx_no, ts, fn); + else if (tbf->ta() != ta) { + LOGP(DL1IF, LOGL_INFO, "[%s] Updating TA %u -> %u on " + "TRX = %d, TS = %d, FN = %d\n", + p, tbf->ta(), ta, trx_no, ts, fn); + tbf->set_ta(ta); + } +} + gprs_rlcmac_tbf *gprs_rlcmac_pdch::tbf_from_list_by_tfi( LListHead *tbf_list, uint8_t tfi, enum gprs_rlcmac_tbf_direction dir) diff --git a/src/bts.h b/src/bts.h index 807ce08..2960203 100644 --- a/src/bts.h +++ b/src/bts.h @@ -142,6 +142,9 @@ #endif }; +void bts_update_tbf_ta(const char *p, uint32_t fn, uint8_t trx_no, uint8_t ts, + uint8_t ta); + /** * This is the data from C. As soon as our minimal compiler is gcc 4.7 * we can start to compile pcu_vty.c with c++ and remove the split. diff --git a/src/osmo-bts-litecell15/lc15_l1_if.c b/src/osmo-bts-litecell15/lc15_l1_if.c index a2189f0..eb680b2 100644 --- a/src/osmo-bts-litecell15/lc15_l1_if.c +++ b/src/osmo-bts-litecell15/lc15_l1_if.c @@ -204,6 +204,8 @@ data_ind->msgUnitParam.u8Size-1); get_meas(&meas, &data_ind->measParam); + bts_update_tbf_ta("PH-DATA", data_ind->u32Fn, fl1h->trx_no, + data_ind->u8Tn, qta2ta(meas.bto)); switch (data_ind->sapi) { case GsmL1_Sapi_Pdtch: @@ -235,31 +237,12 @@ static int handle_ph_ra_ind(struct lc15l1_hdl *fl1h, GsmL1_PhRaInd_t *ra_ind) { - uint8_t acc_delay; - if (ra_ind->measParam.fLinkQuality < MIN_QUAL_RACH) return 0; DEBUGP(DL1IF, "Rx PH-RA.ind"); - - /* check for under/overflow / sign */ - if (ra_ind->measParam.i16BurstTiming < 0) - acc_delay = 0; - else - acc_delay = ra_ind->measParam.i16BurstTiming >> 2; - - LOGP(DL1IF, LOGL_NOTICE, "got (P)RACH request, TA = %u (ignored)\n", - acc_delay); - -#warning "The (P)RACH request is just dropped here" - -#if 0 - if (acc_delay > bts->max_ta) { - LOGP(DL1C, LOGL_INFO, "ignoring RACH request %u > max_ta(%u)\n", - acc_delay, btsb->max_ta); - return 0; - } -#endif + bts_update_tbf_ta("PH-RA", ra_ind->u32Fn, fl1h->trx_no, ra_ind->u8Tn, + qta2ta(ra_ind->measParam.i16BurstTiming)); return 0; } diff --git a/src/osmo-bts-sysmo/sysmo_l1_if.c b/src/osmo-bts-sysmo/sysmo_l1_if.c index 75a2d5f..4ebabc5 100644 --- a/src/osmo-bts-sysmo/sysmo_l1_if.c +++ b/src/osmo-bts-sysmo/sysmo_l1_if.c @@ -189,6 +189,8 @@ data_ind->msgUnitParam.u8Size-1); get_meas(&meas, &data_ind->measParam); + bts_update_tbf_ta("PH-DATA", data_ind->u32Fn, fl1h->trx_no, + data_ind->u8Tn, qta2ta(meas.bto)); switch (data_ind->sapi) { case GsmL1_Sapi_Pdtch: @@ -220,33 +222,14 @@ static int handle_ph_ra_ind(struct femtol1_hdl *fl1h, GsmL1_PhRaInd_t *ra_ind) { - uint8_t acc_delay; - pcu_rx_ra_time(ra_ind->u16Arfcn, ra_ind->u32Fn, ra_ind->u8Tn); if (ra_ind->measParam.fLinkQuality < MIN_QUAL_RACH) return 0; DEBUGP(DL1IF, "Rx PH-RA.ind"); - - /* check for under/overflow / sign */ - if (ra_ind->measParam.i16BurstTiming < 0) - acc_delay = 0; - else - acc_delay = ra_ind->measParam.i16BurstTiming >> 2; - - LOGP(DL1IF, LOGL_NOTICE, "got (P)RACH request, TA = %u (ignored)\n", - acc_delay); - -#warning "The (P)RACH request is just dropped here" - -#if 0 - if (acc_delay > bts->max_ta) { - LOGP(DL1C, LOGL_INFO, "ignoring RACH request %u > max_ta(%u)\n", - acc_delay, btsb->max_ta); - return 0; - } -#endif + bts_update_tbf_ta("PH-RA", ra_ind->u32Fn, fl1h->trx_no, ra_ind->u8Tn, + qta2ta(ra_ind->measParam.i16BurstTiming)); return 0; } diff --git a/src/pcu_l1_if.h b/src/pcu_l1_if.h index b2a9832..d9d970d 100644 --- a/src/pcu_l1_if.h +++ b/src/pcu_l1_if.h @@ -33,6 +33,15 @@ } #endif +static inline uint8_t qta2ta(int16_t qta) +{ + if (qta < 0) + return 0; + if (qta > 252) + qta = 252; + return qta >> 2; +} + /* * L1 Measurement values */ -- To view, visit https://gerrit.osmocom.org/544 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I96fdbb20b09fb85fdd9fb6dcf3c25f6bee7f80e4 Gerrit-PatchSet: 7 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max From gerrit-no-reply at lists.osmocom.org Tue Aug 2 09:24:10 2016 From: gerrit-no-reply at lists.osmocom.org (daniel) Date: Tue, 2 Aug 2016 09:24:10 +0000 Subject: openbsc[master]: Improve code re-use In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+1 -- To view, visit https://gerrit.osmocom.org/631 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I9bad8f0dd1d69bd28816bf047d85840e3411bb9c Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: daniel Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 2 09:25:56 2016 From: gerrit-no-reply at lists.osmocom.org (daniel) Date: Tue, 2 Aug 2016 09:25:56 +0000 Subject: openbsc[master]: Use random operation id In-Reply-To: References: Message-ID: Patch Set 2: Code-Review+1 Looks good! -- To view, visit https://gerrit.osmocom.org/640 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I87d9ee0e9a87f58702c60bb141c973d41fa06997 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: daniel Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 2 09:28:51 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Tue, 2 Aug 2016 09:28:51 +0000 Subject: [PATCH] osmo-pcu[master]: Handle Timing Advance IE properly In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/552 to look at the new patch set (#6). Handle Timing Advance IE properly Move writing Timing Advance IE and Timing Advance Index into separate functions to simplify adding PTCCH support. This also fixes previous incorrect (and unused) code for writing Packet TA IE which has not set TS for TA. Change-Id: I786bf7fc999d401cc3d9e7f1e7a1fba953b5d458 Related: OS#1545 --- M src/encoding.cpp 1 file changed, 38 insertions(+), 31 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/52/552/6 diff --git a/src/encoding.cpp b/src/encoding.cpp index a778ef0..2439c41 100644 --- a/src/encoding.cpp +++ b/src/encoding.cpp @@ -35,6 +35,39 @@ #include #include +/* { 0 | 1 < TIMING_ADVANCE_INDEX : bit (4) > } */ +static inline bool write_tai(bitvec *dest, unsigned& wp, int8_t tai) +{ + if (tai < 0) { /* No TIMING_ADVANCE_INDEX: */ + bitvec_write_field(dest, wp, 0, 1); + return false; + } + /* TIMING_ADVANCE_INDEX: */ + bitvec_write_field(dest, wp, 1, 1); + bitvec_write_field(dest, wp, tai, 4); + return true; +} + +/* { 0 | 1 < TIMING_ADVANCE_VALUE : bit (6) > } */ +static inline void write_ta(bitvec *dest, unsigned& wp, int8_t ta) +{ + if (ta < 0) /* No TIMING_ADVANCE_VALUE: */ + bitvec_write_field(dest, wp, 0, 1); + else { /* TIMING_ADVANCE_VALUE: */ + bitvec_write_field(dest, wp, 1, 1); + bitvec_write_field(dest, wp, ta, 6); + } +} + +/* 3GPP TS 44.060 ? 12.12 */ +static inline void write_ta_ie(bitvec *dest, unsigned& wp, + int8_t ta, int8_t tai, uint8_t ts) +{ + write_ta(dest, wp, ta); + if (write_tai(dest, wp, tai)) /* TIMING_ADVANCE_TIMESLOT_NUMBER: */ + bitvec_write_field(dest, wp, ts, 3); +} + static int write_ia_rest_downlink( gprs_rlcmac_dl_tbf *tbf, bitvec * dest, unsigned& wp, @@ -62,12 +95,7 @@ bitvec_write_field(dest, wp,gamma,5); // GAMMA power control parameter bitvec_write_field(dest, wp,polling,1); // Polling Bit bitvec_write_field(dest, wp, ta_valid, 1); // N. B: NOT related to TAI! - if (ta_idx < 0) { - bitvec_write_field(dest, wp,0x0,1); // switch TIMING_ADVANCE_INDEX = off - } else { - bitvec_write_field(dest, wp,0x1,1); // switch TIMING_ADVANCE_INDEX = on - bitvec_write_field(dest, wp,ta_idx,4); // TIMING_ADVANCE_INDEX - } + write_tai(dest, wp, ta_idx); if (polling) { bitvec_write_field(dest, wp,0x1,1); // TBF Starting TIME present bitvec_write_field(dest, wp,(fn / (26 * 51)) % 32,5); // T1' @@ -110,12 +138,7 @@ } else bitvec_write_field(dest, wp,0x0,1); // ALPHA = not present bitvec_write_field(dest, wp,gamma,5); // GAMMA power control parameter - if (ta_idx < 0) { - bitvec_write_field(dest, wp,0x0,1); // switch TIMING_ADVANCE_INDEX = off - } else { - bitvec_write_field(dest, wp,0x1,1); // switch TIMING_ADVANCE_INDEX = on - bitvec_write_field(dest, wp,ta_idx,4); // TIMING_ADVANCE_INDEX - } + write_tai(dest, wp, ta_idx); bitvec_write_field(dest, wp, 1, 1); // TBF_STARTING_TIME_FLAG bitvec_write_field(dest, wp,(fn / (26 * 51)) % 32,5); // T1' bitvec_write_field(dest, wp,fn % 51,6); // T3 @@ -244,6 +267,7 @@ // TODO We should use our implementation of encode RLC/MAC Control messages. unsigned wp = 0; uint8_t ts; + uint8_t ta_ts = 0; /* FIXME: supply it as parameter from caller */ bitvec_write_field(dest, wp,0x1,2); // Payload Type bitvec_write_field(dest, wp,0x0,2); // Uplink block with TDMA framenumber (N+13) @@ -267,15 +291,7 @@ bitvec_write_field(dest, wp,0x0,1); // Message escape bitvec_write_field(dest, wp,tbf->current_cs().to_num()-1, 2); // CHANNEL_CODING_COMMAND bitvec_write_field(dest, wp,0x1,1); // TLLI_BLOCK_CHANNEL_CODING - bitvec_write_field(dest, wp,0x1,1); // switch TIMING_ADVANCE_VALUE = on - bitvec_write_field(dest, wp,tbf->ta(),6); // TIMING_ADVANCE_VALUE - if (ta_idx < 0) { - bitvec_write_field(dest, wp,0x0,1); // switch TIMING_ADVANCE_INDEX = off - } else { - bitvec_write_field(dest, wp,0x1,1); // switch TIMING_ADVANCE_INDEX = on - bitvec_write_field(dest, wp,ta_idx,4); // TIMING_ADVANCE_INDEX - } - + write_ta_ie(dest, wp,tbf->ta(), ta_idx, ta_ts); } else { /* EPGRS */ unsigned int ws_enc = (tbf->m_window.ws() - 64) / 32; bitvec_write_field(dest, wp,0x1,1); // Message escape @@ -289,16 +305,7 @@ bitvec_write_field(dest, wp,0x0,1); // No ARAC RETRANSMISSION REQUEST bitvec_write_field(dest, wp,0x1,1); // TLLI_BLOCK_CHANNEL_CODING bitvec_write_field(dest, wp,0x0,1); // No BEP_PERIOD2 - - bitvec_write_field(dest, wp,0x1,1); // switch TIMING_ADVANCE_VALUE = on - bitvec_write_field(dest, wp,tbf->ta(),6); // TIMING_ADVANCE_VALUE - if (ta_idx < 0) { - bitvec_write_field(dest, wp,0x0,1); // switch TIMING_ADVANCE_INDEX = off - } else { - bitvec_write_field(dest, wp,0x1,1); // switch TIMING_ADVANCE_INDEX = on - bitvec_write_field(dest, wp,ta_idx,4); // TIMING_ADVANCE_INDEX - } - + write_ta_ie(dest, wp,tbf->ta(), ta_idx, ta_ts); bitvec_write_field(dest, wp,0x0,1); // No Packet Extended Timing Advance } -- To view, visit https://gerrit.osmocom.org/552 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I786bf7fc999d401cc3d9e7f1e7a1fba953b5d458 Gerrit-PatchSet: 6 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max From gerrit-no-reply at lists.osmocom.org Tue Aug 2 09:30:48 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Tue, 2 Aug 2016 09:30:48 +0000 Subject: libosmocore[master]: Extend L1SAP with Measurements In-Reply-To: References: Message-ID: Patch Set 2: Ok, osmo-bts-trx can compute C/I, so all available BTS models can supply this information. Hence we do not have to have presence field for ber/bto/link quality. Shall I add it just in case? -- To view, visit https://gerrit.osmocom.org/622 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I2b127eb1856c4cd1bc46490a89592a595f1ee86b Gerrit-PatchSet: 2 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 2 09:35:18 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Tue, 2 Aug 2016 09:35:18 +0000 Subject: [PATCH] openbsc[master]: V42BIS integration In-Reply-To: References: Message-ID: Hello Harald Welte, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/644 to look at the new patch set (#2). V42BIS integration The previously committed SPANDSP v42bis implementation has been minimaly edited to fit our needs Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d --- M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/debug.h M openbsc/include/openbsc/v42bis.h R openbsc/include/openbsc/v42bis_private.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/v42bis.c 6 files changed, 117 insertions(+), 9 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/44/644/2 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index e159db5..e404b17 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,8 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h gprs_sndcp_xid.h \ - gprs_sndcp_comp_entity.h gprs_sndcp_hdrcomp.h + gprs_sndcp_comp_entity.h gprs_sndcp_hdrcomp.h v42bis.h \ + v42bis_private.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 90ddca5..f98439f 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -28,7 +28,6 @@ DNS, DBSSGP, DLLC, - DSNDCP, DSLHC, DNAT, DCTRL, @@ -37,6 +36,8 @@ DGTPHUB, DRANAP, DSUA, + DSNDCP, + DV42BIS, Debug_LastEntry, }; diff --git a/openbsc/include/openbsc/v42bis.h b/openbsc/include/openbsc/v42bis.h index f13e5c5..e7592e8 100644 --- a/openbsc/include/openbsc/v42bis.h +++ b/openbsc/include/openbsc/v42bis.h @@ -36,6 +36,8 @@ #if !defined(_SPANDSP_V42BIS_H_) #define _SPANDSP_V42BIS_H_ +#define SPAN_DECLARE(x) x + #define V42BIS_MAX_BITS 12 #define V42BIS_MAX_CODEWORDS 4096 /* 2^V42BIS_MAX_BITS */ #define V42BIS_TABLE_SIZE 5021 /* This should be a prime >(2^V42BIS_MAX_BITS) */ diff --git a/openbsc/include/openbsc/private_v42bis.h b/openbsc/include/openbsc/v42bis_private.h similarity index 100% rename from openbsc/include/openbsc/private_v42bis.h rename to openbsc/include/openbsc/v42bis_private.h diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 3d6c82a..2c03a45 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -22,7 +22,7 @@ osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \ slhc.c gprs_sndcp_xid.c gprs_sndcp_comp_entity.c \ - gprs_sndcp_hdrcomp.c \ + gprs_sndcp_hdrcomp.c v42bis.c \ sgsn_main.c sgsn_vty.c sgsn_libgtp.c \ gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c \ gprs_llc_xid.c crc24.c \ diff --git a/openbsc/src/gprs/v42bis.c b/openbsc/src/gprs/v42bis.c index d8d3f3f..d77db5b 100644 --- a/openbsc/src/gprs/v42bis.c +++ b/openbsc/src/gprs/v42bis.c @@ -35,6 +35,9 @@ #include "config.h" #endif +#define FALSE 0 +#define TRUE 1 + #include #include #include @@ -44,13 +47,9 @@ #include #include -#include "spandsp/telephony.h" -#include "spandsp/logging.h" -#include "spandsp/bit_operations.h" -#include "spandsp/v42bis.h" +#include "v42bis.h" +#include "v42bis_private.h" -#include "spandsp/private/logging.h" -#include "spandsp/private/v42bis.h" /* Fixed parameters from the spec. */ #define V42BIS_N3 8 /* Character size (bits) */ @@ -74,6 +73,111 @@ V42BIS_RESET = 2 /* Force reinitialisation */ }; +/*! \brief Find the bit position of the highest set bit in a word + \param bits The word to be searched + \return The bit number of the highest set bit, or -1 if the word is zero. */ +static __inline__ int top_bit(unsigned int bits) +{ +/* + * Note: This function was taken from spandsp/bit_operations.h + * without modification + */ + +#if defined(SPANDSP_USE_86_ASM) + int res; + + __asm__ (" xorl %[res],%[res];\n" + " decl %[res];\n" + " bsrl %[bits],%[res]\n" + : [res] "=&r" (res) + : [bits] "rm" (bits)); + return res; +#elif defined(__ppc__) || defined(__powerpc__) + int res; + + __asm__ ("cntlzw %[res],%[bits];\n" + : [res] "=&r" (res) + : [bits] "r" (bits)); + return 31 - res; +#elif defined(_M_IX86) + /* Visual Studio i386 */ + __asm + { + xor eax, eax + dec eax + bsr eax, bits + } +#elif defined(_M_X64) + /* Visual Studio x86_64 */ + /* TODO: Need the appropriate x86_64 code */ + int res; + + if (bits == 0) + return -1; + res = 0; + if (bits & 0xFFFF0000) + { + bits &= 0xFFFF0000; + res += 16; + } + if (bits & 0xFF00FF00) + { + bits &= 0xFF00FF00; + res += 8; + } + if (bits & 0xF0F0F0F0) + { + bits &= 0xF0F0F0F0; + res += 4; + } + if (bits & 0xCCCCCCCC) + { + bits &= 0xCCCCCCCC; + res += 2; + } + if (bits & 0xAAAAAAAA) + { + bits &= 0xAAAAAAAA; + res += 1; + } + return res; +#else + int res; + + if (bits == 0) + return -1; + res = 0; + if (bits & 0xFFFF0000) + { + bits &= 0xFFFF0000; + res += 16; + } + if (bits & 0xFF00FF00) + { + bits &= 0xFF00FF00; + res += 8; + } + if (bits & 0xF0F0F0F0) + { + bits &= 0xF0F0F0F0; + res += 4; + } + if (bits & 0xCCCCCCCC) + { + bits &= 0xCCCCCCCC; + res += 2; + } + if (bits & 0xAAAAAAAA) + { + bits &= 0xAAAAAAAA; + res += 1; + } + return res; +#endif +} +/*- End of function --------------------------------------------------------*/ + + static __inline__ void push_compressed_raw_octet(v42bis_compress_state_t *ss, int octet) { ss->output_buf[ss->output_octet_count++] = (uint8_t) octet; -- To view, visit https://gerrit.osmocom.org/644 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte From gerrit-no-reply at lists.osmocom.org Tue Aug 2 09:48:41 2016 From: gerrit-no-reply at lists.osmocom.org (lynxis lazus) Date: Tue, 2 Aug 2016 09:48:41 +0000 Subject: [PATCH] openbsc[master]: libbsc/libmsc: convert old osmo counter into rate_ctrgs In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/500 to look at the new patch set (#6). libbsc/libmsc: convert old osmo counter into rate_ctrgs rate counters support the export to statsd and can have a delta value. Change-Id: Ie749cebd53a0bb618d0e23d375885712078bf8dd --- M openbsc/include/openbsc/gsm_data.h M openbsc/src/libbsc/abis_rsl.c M openbsc/src/libbsc/bsc_init.c M openbsc/src/libbsc/bsc_vty.c M openbsc/src/libbsc/gsm_04_08_utils.c M openbsc/src/libbsc/handover_logic.c M openbsc/src/libbsc/net_init.c M openbsc/src/libbsc/paging.c M openbsc/src/libmsc/gsm_04_08.c M openbsc/src/libmsc/gsm_04_11.c M openbsc/src/libmsc/vty_interface_layer3.c 11 files changed, 152 insertions(+), 140 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/00/500/6 diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index bdcd0e0..f0098ce 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -7,7 +7,10 @@ #include #include +#include #include +#include + #include #include @@ -148,55 +151,79 @@ /* Some statistics of our network */ -struct gsmnet_stats { - struct { - struct osmo_counter *total; - struct osmo_counter *no_channel; - } chreq; - struct { - struct osmo_counter *attempted; - struct osmo_counter *no_channel; /* no channel available */ - struct osmo_counter *timeout; /* T3103 timeout */ - struct osmo_counter *completed; /* HO COMPL received */ - struct osmo_counter *failed; /* HO FAIL received */ - } handover; - struct { - struct osmo_counter *attach; - struct osmo_counter *normal; - struct osmo_counter *periodic; - struct osmo_counter *detach; - } loc_upd_type; - struct { - struct osmo_counter *reject; - struct osmo_counter *accept; - } loc_upd_resp; - struct { - struct osmo_counter *attempted; - struct osmo_counter *detached; - struct osmo_counter *completed; - struct osmo_counter *expired; - } paging; - struct { - struct osmo_counter *submitted; /* MO SMS submissions */ - struct osmo_counter *no_receiver; - struct osmo_counter *delivered; /* MT SMS deliveries */ - struct osmo_counter *rp_err_mem; - struct osmo_counter *rp_err_other; - } sms; - struct { - struct osmo_counter *mo_setup; - struct osmo_counter *mo_connect_ack; - struct osmo_counter *mt_setup; - struct osmo_counter *mt_connect; - } call; - struct { - struct osmo_counter *rf_fail; - struct osmo_counter *rll_err; - } chan; - struct { - struct osmo_counter *oml_fail; - struct osmo_counter *rsl_fail; - } bts; +enum { + MSC_CTR_CHREQ_TOTAL, + MSC_CTR_CHREQ_NO_CHANNEL, + MSC_CTR_HANDOVER_ATTEMPTED, + MSC_CTR_HANDOVER_NO_CHANNEL, + MSC_CTR_HANDOVER_TIMEOUT, + MSC_CTR_HANDOVER_COMPLETED, + MSC_CTR_HANDOVER_FAILED, + MSC_CTR_LOC_UPDATE_TYPE_ATTACH, + MSC_CTR_LOC_UPDATE_TYPE_NORMAL, + MSC_CTR_LOC_UPDATE_TYPE_PERIODIC, + MSC_CTR_LOC_UPDATE_TYPE_DETACH, + MSC_CTR_LOC_UPDATE_RESP_REJECT, + MSC_CTR_LOC_UPDATE_RESP_ACCEPT, + MSC_CTR_PAGING_ATTEMPTED, + MSC_CTR_PAGING_DETACHED, + MSC_CTR_PAGING_COMPLETED, + MSC_CTR_PAGING_EXPIRED, + MSC_CTR_SMS_SUBMITTED, + MSC_CTR_SMS_NO_RECEIVER, + MSC_CTR_SMS_DELIVERED, + MSC_CTR_SMS_RP_ERR_MEM, + MSC_CTR_SMS_RP_ERR_OTHER, + MSC_CTR_CALL_MO_SETUP, + MSC_CTR_CALL_MO_CONNECT_ACK, + MSC_CTR_CALL_MT_SETUP, + MSC_CTR_CALL_MT_CONNECT, + MSC_CTR_CHAN_RF_FAIL, + MSC_CTR_CHAN_RLL_ERR, + MSC_CTR_BTS_OML_FAIL, + MSC_CTR_BTS_RSL_FAIL, +}; + +static const struct rate_ctr_desc msc_ctr_description[] = { + [MSC_CTR_CHREQ_TOTAL] = {"chreq.total", "Received channel requests."}, + [MSC_CTR_CHREQ_NO_CHANNEL] = {"chreq.no_channel", "Sent to MS no channel available."}, + [MSC_CTR_HANDOVER_ATTEMPTED] = {"handover.attempted", "Received handover attempts."}, + [MSC_CTR_HANDOVER_NO_CHANNEL] = {"handover.no_channel", "Sent no channel available responses."}, + [MSC_CTR_HANDOVER_TIMEOUT] = {"handover.timeout", "Count the amount of timeouts of timer T3103."}, + [MSC_CTR_HANDOVER_COMPLETED] = {"handover.completed", "Received handover completed."}, + [MSC_CTR_HANDOVER_FAILED] = {"handover.failed", "Receive HO FAIL messages."}, + [MSC_CTR_LOC_UPDATE_TYPE_ATTACH] = {"loc_update_type.attach", "Received location update imsi attach requests."}, + [MSC_CTR_LOC_UPDATE_TYPE_NORMAL] = {"loc_update_type.normal", "Received location update normal requests."}, + [MSC_CTR_LOC_UPDATE_TYPE_PERIODIC] = {"loc_update_type.periodic", "Received location update periodic requests."}, + [MSC_CTR_LOC_UPDATE_TYPE_DETACH] = {"loc_update_type.detach", "Received location update detach indication."}, + [MSC_CTR_LOC_UPDATE_RESP_REJECT] = {"loc_update_resp.reject", "Sent location update reject responses."}, + [MSC_CTR_LOC_UPDATE_RESP_ACCEPT] = {"loc_update_resp.accept", "Sent location update accept responses."}, + [MSC_CTR_PAGING_ATTEMPTED] = {"paging.attempted", "Paging attempts for a MS."}, + [MSC_CTR_PAGING_DETACHED] = {"paging.detached", "Counts the amount of paging attempts which couldn't sent out any paging request because no responsible bts found."}, + [MSC_CTR_PAGING_COMPLETED] = {"paging.completed", "Paging successful completed."}, + [MSC_CTR_PAGING_EXPIRED] = {"paging.expired", "Paging Request expired because of timeout T3113."}, + [MSC_CTR_SMS_SUBMITTED] = {"sms.submitted", "Received a RPDU from a MS (MO)."}, + [MSC_CTR_SMS_NO_RECEIVER] = {"sms.no_receiver", "Counts SMS which couldn't routed because no receiver found."}, + [MSC_CTR_SMS_DELIVERED] = {"sms.delivered", "Global SMS Deliver attempts."}, + [MSC_CTR_SMS_RP_ERR_MEM] = {"sms.rp_err_mem", "CAUSE_MT_MEM_EXCEEDED errors of MS responses on a sms deliver attempt."}, + [MSC_CTR_SMS_RP_ERR_OTHER] = {"sms.rp_err_other", "Other error of MS responses on a sms delive attempt."}, + /* FIXME: count also sms delivered */ + [MSC_CTR_CALL_MO_SETUP] = {"call.mo_setup", "Received setup requests from a MS to init a MO call."}, + [MSC_CTR_CALL_MO_CONNECT_ACK] = {"call.mo_connect_ack", "Received a connect ack from MS of a MO call. Call is now succesful connected up."}, + [MSC_CTR_CALL_MT_SETUP] = {"call.mt_setup", "Sent setup requests to the MS (MT)."}, + [MSC_CTR_CALL_MT_CONNECT] = {"call.mt_connect", "Sent a connect to the MS (MT)."}, + [MSC_CTR_CHAN_RF_FAIL] = {"chan.rf_fail", "Received a RF failure indication from BTS."}, + [MSC_CTR_CHAN_RLL_ERR] = {"chan.rll_err", "Received a RLL failure with T200 cause from BTS."}, + [MSC_CTR_BTS_OML_FAIL] = {"bts.oml_fail", "Received a TEI down on a OML link."}, + [MSC_CTR_BTS_RSL_FAIL] = {"bts.rsl_fail", "Received a TEI down on a OML link."}, +}; + +static const struct rate_ctr_group_desc msc_ctrg_desc = { + "msc", + "mobile switch center", + OSMO_STATS_CLASS_GLOBAL, + ARRAY_SIZE(msc_ctr_description), + msc_ctr_description, }; enum gsm_auth_policy { @@ -241,7 +268,8 @@ unsigned int max_distance; /* TA values */ } handover; - struct gsmnet_stats stats; + struct rate_ctr_group *ratectrs; + /* layer 4 */ struct mncc_sock_state *mncc_state; diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index 013daec..21608b0 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -1071,7 +1071,7 @@ TLVP_LEN(&tp, RSL_IE_CAUSE)); LOGPC(DRSL, LOGL_NOTICE, "\n"); - osmo_counter_inc(msg->lchan->ts->trx->bts->network->stats.chan.rf_fail); + rate_ctr_inc(&msg->lchan->ts->trx->bts->network->ratectrs->ctr[MSC_CTR_CHAN_RF_FAIL]); return rsl_rf_chan_release_err(msg->lchan); } @@ -1505,7 +1505,7 @@ lctype = get_ctype_by_chreq(bts->network, rqd_ref->ra); chreq_reason = get_reason_by_chreq(rqd_ref->ra, bts->network->neci); - osmo_counter_inc(bts->network->stats.chreq.total); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_CHREQ_TOTAL]); /* * We want LOCATION UPDATES to succeed and will assign a TCH @@ -1518,7 +1518,7 @@ if (!lchan) { LOGP(DRSL, LOGL_NOTICE, "BTS %d CHAN RQD: no resources for %s 0x%x\n", msg->lchan->ts->trx->bts->nr, gsm_lchant_name(lctype), rqd_ref->ra); - osmo_counter_inc(bts->network->stats.chreq.no_channel); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_CHREQ_NO_CHANNEL]); /* FIXME gather multiple CHAN RQD and reject up to 4 at the same time */ if (bts->network->T3122) rsl_send_imm_ass_rej(bts, 1, rqd_ref, bts->network->T3122 & 0xff); @@ -1693,7 +1693,7 @@ rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_ERR_IND); if (rlm_cause == RLL_CAUSE_T200_EXPIRED) { - osmo_counter_inc(msg->lchan->ts->trx->bts->network->stats.chan.rll_err); + rate_ctr_inc(&msg->lchan->ts->trx->bts->network->ratectrs->ctr[MSC_CTR_CHAN_RLL_ERR]); return rsl_rf_chan_release_err(msg->lchan); } diff --git a/openbsc/src/libbsc/bsc_init.c b/openbsc/src/libbsc/bsc_init.c index 5c27862..5ea85d0 100644 --- a/openbsc/src/libbsc/bsc_init.c +++ b/openbsc/src/libbsc/bsc_init.c @@ -340,9 +340,9 @@ LOGP(DLMI, LOGL_ERROR, "Lost some E1 TEI link: %d %p\n", isd->link_type, trx); if (isd->link_type == E1INP_SIGN_OML) - osmo_counter_inc(trx->bts->network->stats.bts.oml_fail); + rate_ctr_inc(&trx->bts->network->ratectrs->ctr[MSC_CTR_BTS_OML_FAIL]); else if (isd->link_type == E1INP_SIGN_RSL) - osmo_counter_inc(trx->bts->network->stats.bts.rsl_fail); + rate_ctr_inc(&trx->bts->network->ratectrs->ctr[MSC_CTR_BTS_RSL_FAIL]); /* * free all allocated channels. change the nm_state so the diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c index b0e8764..abc7648 100644 --- a/openbsc/src/libbsc/bsc_vty.c +++ b/openbsc/src/libbsc/bsc_vty.c @@ -3755,18 +3755,22 @@ void openbsc_vty_print_statistics(struct vty *vty, struct gsm_network *net) { vty_out(vty, "Channel Requests : %lu total, %lu no channel%s", - osmo_counter_get(net->stats.chreq.total), - osmo_counter_get(net->stats.chreq.no_channel), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_CHREQ_TOTAL].current, + net->ratectrs->ctr[MSC_CTR_CHREQ_NO_CHANNEL].current, + VTY_NEWLINE); vty_out(vty, "Channel Failures : %lu rf_failures, %lu rll failures%s", - osmo_counter_get(net->stats.chan.rf_fail), - osmo_counter_get(net->stats.chan.rll_err), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_CHAN_RF_FAIL].current, + net->ratectrs->ctr[MSC_CTR_CHAN_RLL_ERR].current, + VTY_NEWLINE); vty_out(vty, "Paging : %lu attempted, %lu complete, %lu expired%s", - osmo_counter_get(net->stats.paging.attempted), - osmo_counter_get(net->stats.paging.completed), - osmo_counter_get(net->stats.paging.expired), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_PAGING_ATTEMPTED].current, + net->ratectrs->ctr[MSC_CTR_PAGING_COMPLETED].current, + net->ratectrs->ctr[MSC_CTR_PAGING_EXPIRED].current, + VTY_NEWLINE); vty_out(vty, "BTS failures : %lu OML, %lu RSL%s", - osmo_counter_get(net->stats.bts.oml_fail), - osmo_counter_get(net->stats.bts.rsl_fail), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_BTS_OML_FAIL].current, + net->ratectrs->ctr[MSC_CTR_BTS_RSL_FAIL].current, + VTY_NEWLINE); } DEFUN(drop_bts, diff --git a/openbsc/src/libbsc/gsm_04_08_utils.c b/openbsc/src/libbsc/gsm_04_08_utils.c index 635665a..d4eca4a 100644 --- a/openbsc/src/libbsc/gsm_04_08_utils.c +++ b/openbsc/src/libbsc/gsm_04_08_utils.c @@ -304,7 +304,7 @@ subscr = conn->subscr; } - osmo_counter_inc(bts->network->stats.paging.completed); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_PAGING_COMPLETED]); /* Stop paging on the bts we received the paging response */ paging_request_stop(conn->bts, subscr, conn, msg); diff --git a/openbsc/src/libbsc/handover_logic.c b/openbsc/src/libbsc/handover_logic.c index 52fa4af..5424e27 100644 --- a/openbsc/src/libbsc/handover_logic.c +++ b/openbsc/src/libbsc/handover_logic.c @@ -103,7 +103,7 @@ DEBUGP(DHO, "(old_lchan on BTS %u, new BTS %u)\n", old_lchan->ts->trx->bts->nr, bts->nr); - osmo_counter_inc(bts->network->stats.handover.attempted); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_HANDOVER_ATTEMPTED]); if (!old_lchan->conn) { LOGP(DHO, LOGL_ERROR, "Old lchan lacks connection data.\n"); @@ -113,7 +113,7 @@ new_lchan = lchan_alloc(bts, old_lchan->type, 0); if (!new_lchan) { LOGP(DHO, LOGL_NOTICE, "No free channel\n"); - osmo_counter_inc(bts->network->stats.handover.no_channel); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_HANDOVER_NO_CHANNEL]); return -ENOSPC; } @@ -188,7 +188,7 @@ struct gsm_network *net = ho->new_lchan->ts->trx->bts->network; DEBUGP(DHO, "HO T3103 expired\n"); - osmo_counter_inc(net->stats.handover.timeout); + rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_HANDOVER_TIMEOUT]); ho->new_lchan->conn->ho_lchan = NULL; ho->new_lchan->conn = NULL; @@ -265,7 +265,7 @@ ho->old_lchan->ts->trx->bts->nr, new_lchan->ts->trx->bts->nr, ho->old_lchan->ts->trx->arfcn, new_lchan->ts->trx->arfcn); - osmo_counter_inc(net->stats.handover.completed); + rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_HANDOVER_COMPLETED]); osmo_timer_del(&ho->T3103); @@ -303,7 +303,7 @@ return -ENODEV; } - osmo_counter_inc(net->stats.handover.failed); + rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_HANDOVER_FAILED]); new_lchan = ho->new_lchan; diff --git a/openbsc/src/libbsc/net_init.c b/openbsc/src/libbsc/net_init.c index 0e99097..9e4ccf6 100644 --- a/openbsc/src/libbsc/net_init.c +++ b/openbsc/src/libbsc/net_init.c @@ -80,36 +80,8 @@ INIT_LLIST_HEAD(&net->upqueue); INIT_LLIST_HEAD(&net->bts_list); - net->stats.chreq.total = osmo_counter_alloc("net.chreq.total"); - net->stats.chreq.no_channel = osmo_counter_alloc("net.chreq.no_channel"); - net->stats.handover.attempted = osmo_counter_alloc("net.handover.attempted"); - net->stats.handover.no_channel = osmo_counter_alloc("net.handover.no_channel"); - net->stats.handover.timeout = osmo_counter_alloc("net.handover.timeout"); - net->stats.handover.completed = osmo_counter_alloc("net.handover.completed"); - net->stats.handover.failed = osmo_counter_alloc("net.handover.failed"); - net->stats.loc_upd_type.attach = osmo_counter_alloc("net.loc_upd_type.attach"); - net->stats.loc_upd_type.normal = osmo_counter_alloc("net.loc_upd_type.normal"); - net->stats.loc_upd_type.periodic = osmo_counter_alloc("net.loc_upd_type.periodic"); - net->stats.loc_upd_type.detach = osmo_counter_alloc("net.imsi_detach.count"); - net->stats.loc_upd_resp.reject = osmo_counter_alloc("net.loc_upd_resp.reject"); - net->stats.loc_upd_resp.accept = osmo_counter_alloc("net.loc_upd_resp.accept"); - net->stats.paging.attempted = osmo_counter_alloc("net.paging.attempted"); - net->stats.paging.detached = osmo_counter_alloc("net.paging.detached"); - net->stats.paging.completed = osmo_counter_alloc("net.paging.completed"); - net->stats.paging.expired = osmo_counter_alloc("net.paging.expired"); - net->stats.sms.submitted = osmo_counter_alloc("net.sms.submitted"); - net->stats.sms.no_receiver = osmo_counter_alloc("net.sms.no_receiver"); - net->stats.sms.delivered = osmo_counter_alloc("net.sms.delivered"); - net->stats.sms.rp_err_mem = osmo_counter_alloc("net.sms.rp_err_mem"); - net->stats.sms.rp_err_other = osmo_counter_alloc("net.sms.rp_err_other"); - net->stats.call.mo_setup = osmo_counter_alloc("net.call.mo_setup"); - net->stats.call.mo_connect_ack = osmo_counter_alloc("net.call.mo_connect_ack"); - net->stats.call.mt_setup = osmo_counter_alloc("net.call.mt_setup"); - net->stats.call.mt_connect = osmo_counter_alloc("net.call.mt_connect"); - net->stats.chan.rf_fail = osmo_counter_alloc("net.chan.rf_fail"); - net->stats.chan.rll_err = osmo_counter_alloc("net.chan.rll_err"); - net->stats.bts.oml_fail = osmo_counter_alloc("net.bts.oml_fail"); - net->stats.bts.rsl_fail = osmo_counter_alloc("net.bts.rsl_fail"); + /* init statistics */ + net->ratectrs = rate_ctr_group_alloc(net, &msc_ctrg_desc, 0); net->mncc_recv = mncc_recv; net->ext_min = GSM_MIN_EXTEN; diff --git a/openbsc/src/libbsc/paging.c b/openbsc/src/libbsc/paging.c index 9ae28e0..03c91fd 100644 --- a/openbsc/src/libbsc/paging.c +++ b/openbsc/src/libbsc/paging.c @@ -260,7 +260,7 @@ req, req->subscr->imsi); /* must be destroyed before calling cbfn, to prevent double free */ - osmo_counter_inc(req->bts->network->stats.paging.expired); + rate_ctr_inc(&req->bts->network->ratectrs->ctr[MSC_CTR_PAGING_EXPIRED]); cbfn_param = req->cbfn_param; cbfn = req->cbfn; @@ -330,7 +330,7 @@ struct gsm_bts *bts = NULL; int num_pages = 0; - osmo_counter_inc(network->stats.paging.attempted); + rate_ctr_inc(&network->ratectrs->ctr[MSC_CTR_PAGING_ATTEMPTED]); /* start paging subscriber on all BTS within Location Area */ do { @@ -349,7 +349,7 @@ } while (1); if (num_pages == 0) - osmo_counter_inc(network->stats.paging.detached); + rate_ctr_inc(&network->ratectrs->ctr[MSC_CTR_PAGING_DETACHED]); return num_pages; } diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c index 1b02efe..c4ecf1c 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/src/libmsc/gsm_04_08.c @@ -457,7 +457,7 @@ struct gsm_bts *bts = conn->bts; struct msgb *msg; - osmo_counter_inc(bts->network->stats.loc_upd_resp.reject); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_REJECT]); msg = gsm48_create_loc_upd_rej(cause); if (!msg) { @@ -506,7 +506,7 @@ DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n"); - osmo_counter_inc(bts->network->stats.loc_upd_resp.accept); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_ACCEPT]); return gsm48_conn_sendmsg(msg, conn, NULL); } @@ -637,13 +637,13 @@ switch (lu->type) { case GSM48_LUPD_NORMAL: - osmo_counter_inc(bts->network->stats.loc_upd_type.normal); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_NORMAL]); break; case GSM48_LUPD_IMSI_ATT: - osmo_counter_inc(bts->network->stats.loc_upd_type.attach); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_ATTACH]); break; case GSM48_LUPD_PERIODIC: - osmo_counter_inc(bts->network->stats.loc_upd_type.periodic); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_PERIODIC]); break; } @@ -1063,7 +1063,7 @@ DEBUGP(DMM, "IMSI DETACH INDICATION: MI(%s)=%s", gsm48_mi_type_name(mi_type), mi_string); - osmo_counter_inc(bts->network->stats.loc_upd_type.detach); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_DETACH]); switch (mi_type) { case GSM_MI_TYPE_TMSI: @@ -2002,7 +2002,7 @@ subscr_name(trans->subscr), trans->subscr->extension, setup.called.number); - osmo_counter_inc(trans->net->stats.call.mo_setup); + rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MO_SETUP]); /* indicate setup to MNCC */ mncc_recvmsg(trans->net, trans, MNCC_SETUP_IND, &setup); @@ -2080,7 +2080,7 @@ new_cc_state(trans, GSM_CSTATE_CALL_PRESENT); - osmo_counter_inc(trans->net->stats.call.mt_setup); + rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MT_SETUP]); return gsm48_conn_sendmsg(msg, trans->conn, trans); } @@ -2306,7 +2306,7 @@ } new_cc_state(trans, GSM_CSTATE_CONNECT_REQUEST); - osmo_counter_inc(trans->net->stats.call.mt_connect); + rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MT_CONNECT]); return mncc_recvmsg(trans->net, trans, MNCC_SETUP_CNF, &connect); } @@ -2319,7 +2319,7 @@ gsm48_stop_cc_timer(trans); new_cc_state(trans, GSM_CSTATE_ACTIVE); - osmo_counter_inc(trans->net->stats.call.mo_connect_ack); + rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MO_CONNECT_ACK]); memset(&connect_ack, 0, sizeof(struct gsm_mncc)); connect_ack.callref = trans->callref; diff --git a/openbsc/src/libmsc/gsm_04_11.c b/openbsc/src/libmsc/gsm_04_11.c index 20d18a9..fba5208 100644 --- a/openbsc/src/libmsc/gsm_04_11.c +++ b/openbsc/src/libmsc/gsm_04_11.c @@ -315,14 +315,14 @@ rc = smpp_try_deliver(gsms, conn); if (rc == 1) { rc = 1; /* cause 1: unknown subscriber */ - osmo_counter_inc(conn->bts->network->stats.sms.no_receiver); + rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); } else if (rc < 0) { rc = 21; /* cause 21: short message transfer rejected */ /* FIXME: handle the error somehow? */ } #else rc = 1; /* cause 1: unknown subscriber */ - osmo_counter_inc(conn->bts->network->stats.sms.no_receiver); + rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); #endif return rc; } @@ -363,7 +363,7 @@ uint8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */ int rc = 0; - osmo_counter_inc(conn->bts->network->stats.sms.submitted); + rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_SUBMITTED]); gsms = sms_alloc(); if (!gsms) @@ -633,10 +633,10 @@ * to store this in our database and wait for a SMMA message */ /* FIXME */ send_signal(S_SMS_MEM_EXCEEDED, trans, sms, 0); - osmo_counter_inc(net->stats.sms.rp_err_mem); + rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_MEM]); } else { send_signal(S_SMS_UNKNOWN_ERROR, trans, sms, 0); - osmo_counter_inc(net->stats.sms.rp_err_other); + rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_OTHER]); } sms_free(sms); @@ -932,7 +932,7 @@ DEBUGP(DLSMS, "TX: SMS DELIVER\n"); - osmo_counter_inc(conn->bts->network->stats.sms.delivered); + rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_DELIVERED]); db_sms_inc_deliver_attempts(trans->sms.sms); return gsm411_rp_sendmsg(&trans->sms.smr_inst, msg, diff --git a/openbsc/src/libmsc/vty_interface_layer3.c b/openbsc/src/libmsc/vty_interface_layer3.c index 74da1d7..d1041b3 100644 --- a/openbsc/src/libmsc/vty_interface_layer3.c +++ b/openbsc/src/libmsc/vty_interface_layer3.c @@ -795,34 +795,42 @@ openbsc_vty_print_statistics(vty, net); vty_out(vty, "Location Update : %lu attach, %lu normal, %lu periodic%s", - osmo_counter_get(net->stats.loc_upd_type.attach), - osmo_counter_get(net->stats.loc_upd_type.normal), - osmo_counter_get(net->stats.loc_upd_type.periodic), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_ATTACH].current, + net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_NORMAL].current, + net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_PERIODIC].current, + VTY_NEWLINE); vty_out(vty, "IMSI Detach Indications : %lu%s", - osmo_counter_get(net->stats.loc_upd_type.detach), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_DETACH].current, + VTY_NEWLINE); vty_out(vty, "Location Update Response: %lu accept, %lu reject%s", - osmo_counter_get(net->stats.loc_upd_resp.accept), - osmo_counter_get(net->stats.loc_upd_resp.reject), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_ACCEPT].current, + net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_REJECT].current, + VTY_NEWLINE); vty_out(vty, "Handover : %lu attempted, %lu no_channel, %lu timeout, " "%lu completed, %lu failed%s", - osmo_counter_get(net->stats.handover.attempted), - osmo_counter_get(net->stats.handover.no_channel), - osmo_counter_get(net->stats.handover.timeout), - osmo_counter_get(net->stats.handover.completed), - osmo_counter_get(net->stats.handover.failed), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_HANDOVER_ATTEMPTED].current, + net->ratectrs->ctr[MSC_CTR_HANDOVER_NO_CHANNEL].current, + net->ratectrs->ctr[MSC_CTR_HANDOVER_TIMEOUT].current, + net->ratectrs->ctr[MSC_CTR_HANDOVER_COMPLETED].current, + net->ratectrs->ctr[MSC_CTR_HANDOVER_FAILED].current, + VTY_NEWLINE); vty_out(vty, "SMS MO : %lu submitted, %lu no receiver%s", - osmo_counter_get(net->stats.sms.submitted), - osmo_counter_get(net->stats.sms.no_receiver), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_SMS_SUBMITTED].current, + net->ratectrs->ctr[MSC_CTR_SMS_NO_RECEIVER].current, + VTY_NEWLINE); vty_out(vty, "SMS MT : %lu delivered, %lu no memory, %lu other error%s", - osmo_counter_get(net->stats.sms.delivered), - osmo_counter_get(net->stats.sms.rp_err_mem), - osmo_counter_get(net->stats.sms.rp_err_other), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_SMS_DELIVERED].current, + net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_MEM].current, + net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_OTHER].current, + VTY_NEWLINE); vty_out(vty, "MO Calls : %lu setup, %lu connect ack%s", - osmo_counter_get(net->stats.call.mo_setup), - osmo_counter_get(net->stats.call.mo_connect_ack), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_CALL_MO_SETUP].current, + net->ratectrs->ctr[MSC_CTR_CALL_MO_CONNECT_ACK].current, + VTY_NEWLINE); vty_out(vty, "MT Calls : %lu setup, %lu connect%s", - osmo_counter_get(net->stats.call.mt_setup), - osmo_counter_get(net->stats.call.mt_connect), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_CALL_MT_SETUP].current, + net->ratectrs->ctr[MSC_CTR_CALL_MT_CONNECT].current, + VTY_NEWLINE); return CMD_SUCCESS; } -- To view, visit https://gerrit.osmocom.org/500 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ie749cebd53a0bb618d0e23d375885712078bf8dd Gerrit-PatchSet: 6 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: lynxis lazus From gerrit-no-reply at lists.osmocom.org Tue Aug 2 09:48:41 2016 From: gerrit-no-reply at lists.osmocom.org (lynxis lazus) Date: Tue, 2 Aug 2016 09:48:41 +0000 Subject: [PATCH] openbsc[master]: libmsc/bsc: split rate counters into bsc and msc group Message-ID: Review at https://gerrit.osmocom.org/646 libmsc/bsc: split rate counters into bsc and msc group Change-Id: I7361033cd1eb919ec3c2ea2652f40ab8c75b2f99 --- M openbsc/include/openbsc/gsm_data.h M openbsc/include/openbsc/transaction.h M openbsc/src/libbsc/abis_rsl.c M openbsc/src/libbsc/bsc_init.c M openbsc/src/libbsc/bsc_vty.c M openbsc/src/libbsc/gsm_04_08_utils.c M openbsc/src/libbsc/handover_logic.c M openbsc/src/libbsc/net_init.c M openbsc/src/libbsc/paging.c M openbsc/src/libmsc/gsm_04_08.c M openbsc/src/libmsc/gsm_04_11.c M openbsc/src/libmsc/vty_interface_layer3.c 12 files changed, 111 insertions(+), 95 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/46/646/1 diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index f0098ce..670292c 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -150,25 +150,49 @@ #include "gsm_data_shared.h" -/* Some statistics of our network */ enum { - MSC_CTR_CHREQ_TOTAL, - MSC_CTR_CHREQ_NO_CHANNEL, - MSC_CTR_HANDOVER_ATTEMPTED, - MSC_CTR_HANDOVER_NO_CHANNEL, - MSC_CTR_HANDOVER_TIMEOUT, - MSC_CTR_HANDOVER_COMPLETED, - MSC_CTR_HANDOVER_FAILED, + BSC_CTR_CHREQ_TOTAL, + BSC_CTR_CHREQ_NO_CHANNEL, + BSC_CTR_HANDOVER_ATTEMPTED, + BSC_CTR_HANDOVER_NO_CHANNEL, + BSC_CTR_HANDOVER_TIMEOUT, + BSC_CTR_HANDOVER_COMPLETED, + BSC_CTR_HANDOVER_FAILED, + BSC_CTR_PAGING_ATTEMPTED, + BSC_CTR_PAGING_DETACHED, + BSC_CTR_PAGING_COMPLETED, + BSC_CTR_PAGING_EXPIRED, + BSC_CTR_CHAN_RF_FAIL, + BSC_CTR_CHAN_RLL_ERR, + BSC_CTR_BTS_OML_FAIL, + BSC_CTR_BTS_RSL_FAIL, +}; + +static const struct rate_ctr_desc bsc_ctr_description[] = { + [BSC_CTR_CHREQ_TOTAL] = {"chreq.total", "Received channel requests."}, + [BSC_CTR_CHREQ_NO_CHANNEL] = {"chreq.no_channel", "Sent to MS no channel available."}, + [BSC_CTR_HANDOVER_ATTEMPTED] = {"handover.attempted", "Received handover attempts."}, + [BSC_CTR_HANDOVER_NO_CHANNEL] = {"handover.no_channel", "Sent no channel available responses."}, + [BSC_CTR_HANDOVER_TIMEOUT] = {"handover.timeout", "Count the amount of timeouts of timer T3103."}, + [BSC_CTR_HANDOVER_COMPLETED] = {"handover.completed", "Received handover completed."}, + [BSC_CTR_HANDOVER_FAILED] = {"handover.failed", "Receive HO FAIL messages."}, + [BSC_CTR_PAGING_ATTEMPTED] = {"paging.attempted", "Paging attempts for a MS."}, + [BSC_CTR_PAGING_DETACHED] = {"paging.detached", "Counts the amount of paging attempts which couldn't sent out any paging request because no responsible bts found."}, + [BSC_CTR_PAGING_COMPLETED] = {"paging.completed", "Paging successful completed."}, + [BSC_CTR_PAGING_EXPIRED] = {"paging.expired", "Paging Request expired because of timeout T3113."}, + [BSC_CTR_CHAN_RF_FAIL] = {"chan.rf_fail", "Received a RF failure indication from BTS."}, + [BSC_CTR_CHAN_RLL_ERR] = {"chan.rll_err", "Received a RLL failure with T200 cause from BTS."}, + [BSC_CTR_BTS_OML_FAIL] = {"bts.oml_fail", "Received a TEI down on a OML link."}, + [BSC_CTR_BTS_RSL_FAIL] = {"bts.rsl_fail", "Received a TEI down on a OML link."}, +}; + +enum { MSC_CTR_LOC_UPDATE_TYPE_ATTACH, MSC_CTR_LOC_UPDATE_TYPE_NORMAL, MSC_CTR_LOC_UPDATE_TYPE_PERIODIC, MSC_CTR_LOC_UPDATE_TYPE_DETACH, MSC_CTR_LOC_UPDATE_RESP_REJECT, MSC_CTR_LOC_UPDATE_RESP_ACCEPT, - MSC_CTR_PAGING_ATTEMPTED, - MSC_CTR_PAGING_DETACHED, - MSC_CTR_PAGING_COMPLETED, - MSC_CTR_PAGING_EXPIRED, MSC_CTR_SMS_SUBMITTED, MSC_CTR_SMS_NO_RECEIVER, MSC_CTR_SMS_DELIVERED, @@ -178,30 +202,15 @@ MSC_CTR_CALL_MO_CONNECT_ACK, MSC_CTR_CALL_MT_SETUP, MSC_CTR_CALL_MT_CONNECT, - MSC_CTR_CHAN_RF_FAIL, - MSC_CTR_CHAN_RLL_ERR, - MSC_CTR_BTS_OML_FAIL, - MSC_CTR_BTS_RSL_FAIL, }; static const struct rate_ctr_desc msc_ctr_description[] = { - [MSC_CTR_CHREQ_TOTAL] = {"chreq.total", "Received channel requests."}, - [MSC_CTR_CHREQ_NO_CHANNEL] = {"chreq.no_channel", "Sent to MS no channel available."}, - [MSC_CTR_HANDOVER_ATTEMPTED] = {"handover.attempted", "Received handover attempts."}, - [MSC_CTR_HANDOVER_NO_CHANNEL] = {"handover.no_channel", "Sent no channel available responses."}, - [MSC_CTR_HANDOVER_TIMEOUT] = {"handover.timeout", "Count the amount of timeouts of timer T3103."}, - [MSC_CTR_HANDOVER_COMPLETED] = {"handover.completed", "Received handover completed."}, - [MSC_CTR_HANDOVER_FAILED] = {"handover.failed", "Receive HO FAIL messages."}, [MSC_CTR_LOC_UPDATE_TYPE_ATTACH] = {"loc_update_type.attach", "Received location update imsi attach requests."}, [MSC_CTR_LOC_UPDATE_TYPE_NORMAL] = {"loc_update_type.normal", "Received location update normal requests."}, [MSC_CTR_LOC_UPDATE_TYPE_PERIODIC] = {"loc_update_type.periodic", "Received location update periodic requests."}, [MSC_CTR_LOC_UPDATE_TYPE_DETACH] = {"loc_update_type.detach", "Received location update detach indication."}, [MSC_CTR_LOC_UPDATE_RESP_REJECT] = {"loc_update_resp.reject", "Sent location update reject responses."}, [MSC_CTR_LOC_UPDATE_RESP_ACCEPT] = {"loc_update_resp.accept", "Sent location update accept responses."}, - [MSC_CTR_PAGING_ATTEMPTED] = {"paging.attempted", "Paging attempts for a MS."}, - [MSC_CTR_PAGING_DETACHED] = {"paging.detached", "Counts the amount of paging attempts which couldn't sent out any paging request because no responsible bts found."}, - [MSC_CTR_PAGING_COMPLETED] = {"paging.completed", "Paging successful completed."}, - [MSC_CTR_PAGING_EXPIRED] = {"paging.expired", "Paging Request expired because of timeout T3113."}, [MSC_CTR_SMS_SUBMITTED] = {"sms.submitted", "Received a RPDU from a MS (MO)."}, [MSC_CTR_SMS_NO_RECEIVER] = {"sms.no_receiver", "Counts SMS which couldn't routed because no receiver found."}, [MSC_CTR_SMS_DELIVERED] = {"sms.delivered", "Global SMS Deliver attempts."}, @@ -212,15 +221,20 @@ [MSC_CTR_CALL_MO_CONNECT_ACK] = {"call.mo_connect_ack", "Received a connect ack from MS of a MO call. Call is now succesful connected up."}, [MSC_CTR_CALL_MT_SETUP] = {"call.mt_setup", "Sent setup requests to the MS (MT)."}, [MSC_CTR_CALL_MT_CONNECT] = {"call.mt_connect", "Sent a connect to the MS (MT)."}, - [MSC_CTR_CHAN_RF_FAIL] = {"chan.rf_fail", "Received a RF failure indication from BTS."}, - [MSC_CTR_CHAN_RLL_ERR] = {"chan.rll_err", "Received a RLL failure with T200 cause from BTS."}, - [MSC_CTR_BTS_OML_FAIL] = {"bts.oml_fail", "Received a TEI down on a OML link."}, - [MSC_CTR_BTS_RSL_FAIL] = {"bts.rsl_fail", "Received a TEI down on a OML link."}, +}; + + +static const struct rate_ctr_group_desc bsc_ctrg_desc = { + "bsc", + "base station controller", + OSMO_STATS_CLASS_GLOBAL, + ARRAY_SIZE(bsc_ctr_description), + bsc_ctr_description, }; static const struct rate_ctr_group_desc msc_ctrg_desc = { "msc", - "mobile switch center", + "mobile switching center", OSMO_STATS_CLASS_GLOBAL, ARRAY_SIZE(msc_ctr_description), msc_ctr_description, @@ -268,7 +282,8 @@ unsigned int max_distance; /* TA values */ } handover; - struct rate_ctr_group *ratectrs; + struct rate_ctr_group *bsc_ctrs; + struct rate_ctr_group *msc_ctrs; /* layer 4 */ diff --git a/openbsc/include/openbsc/transaction.h b/openbsc/include/openbsc/transaction.h index 6ef1612..bf7b22d 100644 --- a/openbsc/include/openbsc/transaction.h +++ b/openbsc/include/openbsc/transaction.h @@ -14,7 +14,7 @@ /* Entry in list of all transactions */ struct llist_head entry; - /* Back pointer to the netweork struct */ + /* Back pointer to the network struct */ struct gsm_network *net; /* The protocol within which we live */ diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index 21608b0..15b6688 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -1071,7 +1071,7 @@ TLVP_LEN(&tp, RSL_IE_CAUSE)); LOGPC(DRSL, LOGL_NOTICE, "\n"); - rate_ctr_inc(&msg->lchan->ts->trx->bts->network->ratectrs->ctr[MSC_CTR_CHAN_RF_FAIL]); + rate_ctr_inc(&msg->lchan->ts->trx->bts->network->bsc_ctrs->ctr[BSC_CTR_CHAN_RF_FAIL]); return rsl_rf_chan_release_err(msg->lchan); } @@ -1505,7 +1505,7 @@ lctype = get_ctype_by_chreq(bts->network, rqd_ref->ra); chreq_reason = get_reason_by_chreq(rqd_ref->ra, bts->network->neci); - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_CHREQ_TOTAL]); + rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_CHREQ_TOTAL]); /* * We want LOCATION UPDATES to succeed and will assign a TCH @@ -1518,7 +1518,7 @@ if (!lchan) { LOGP(DRSL, LOGL_NOTICE, "BTS %d CHAN RQD: no resources for %s 0x%x\n", msg->lchan->ts->trx->bts->nr, gsm_lchant_name(lctype), rqd_ref->ra); - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_CHREQ_NO_CHANNEL]); + rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_CHREQ_NO_CHANNEL]); /* FIXME gather multiple CHAN RQD and reject up to 4 at the same time */ if (bts->network->T3122) rsl_send_imm_ass_rej(bts, 1, rqd_ref, bts->network->T3122 & 0xff); @@ -1693,7 +1693,7 @@ rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_ERR_IND); if (rlm_cause == RLL_CAUSE_T200_EXPIRED) { - rate_ctr_inc(&msg->lchan->ts->trx->bts->network->ratectrs->ctr[MSC_CTR_CHAN_RLL_ERR]); + rate_ctr_inc(&msg->lchan->ts->trx->bts->network->bsc_ctrs->ctr[BSC_CTR_CHAN_RLL_ERR]); return rsl_rf_chan_release_err(msg->lchan); } diff --git a/openbsc/src/libbsc/bsc_init.c b/openbsc/src/libbsc/bsc_init.c index 5ea85d0..989fca8 100644 --- a/openbsc/src/libbsc/bsc_init.c +++ b/openbsc/src/libbsc/bsc_init.c @@ -340,9 +340,9 @@ LOGP(DLMI, LOGL_ERROR, "Lost some E1 TEI link: %d %p\n", isd->link_type, trx); if (isd->link_type == E1INP_SIGN_OML) - rate_ctr_inc(&trx->bts->network->ratectrs->ctr[MSC_CTR_BTS_OML_FAIL]); + rate_ctr_inc(&trx->bts->network->bsc_ctrs->ctr[BSC_CTR_BTS_OML_FAIL]); else if (isd->link_type == E1INP_SIGN_RSL) - rate_ctr_inc(&trx->bts->network->ratectrs->ctr[MSC_CTR_BTS_RSL_FAIL]); + rate_ctr_inc(&trx->bts->network->bsc_ctrs->ctr[BSC_CTR_BTS_RSL_FAIL]); /* * free all allocated channels. change the nm_state so the diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c index abc7648..1096cca 100644 --- a/openbsc/src/libbsc/bsc_vty.c +++ b/openbsc/src/libbsc/bsc_vty.c @@ -3755,21 +3755,21 @@ void openbsc_vty_print_statistics(struct vty *vty, struct gsm_network *net) { vty_out(vty, "Channel Requests : %lu total, %lu no channel%s", - net->ratectrs->ctr[MSC_CTR_CHREQ_TOTAL].current, - net->ratectrs->ctr[MSC_CTR_CHREQ_NO_CHANNEL].current, + net->bsc_ctrs->ctr[BSC_CTR_CHREQ_TOTAL].current, + net->bsc_ctrs->ctr[BSC_CTR_CHREQ_NO_CHANNEL].current, VTY_NEWLINE); vty_out(vty, "Channel Failures : %lu rf_failures, %lu rll failures%s", - net->ratectrs->ctr[MSC_CTR_CHAN_RF_FAIL].current, - net->ratectrs->ctr[MSC_CTR_CHAN_RLL_ERR].current, + net->bsc_ctrs->ctr[BSC_CTR_CHAN_RF_FAIL].current, + net->bsc_ctrs->ctr[BSC_CTR_CHAN_RLL_ERR].current, VTY_NEWLINE); vty_out(vty, "Paging : %lu attempted, %lu complete, %lu expired%s", - net->ratectrs->ctr[MSC_CTR_PAGING_ATTEMPTED].current, - net->ratectrs->ctr[MSC_CTR_PAGING_COMPLETED].current, - net->ratectrs->ctr[MSC_CTR_PAGING_EXPIRED].current, + net->bsc_ctrs->ctr[BSC_CTR_PAGING_ATTEMPTED].current, + net->bsc_ctrs->ctr[BSC_CTR_PAGING_COMPLETED].current, + net->bsc_ctrs->ctr[BSC_CTR_PAGING_EXPIRED].current, VTY_NEWLINE); vty_out(vty, "BTS failures : %lu OML, %lu RSL%s", - net->ratectrs->ctr[MSC_CTR_BTS_OML_FAIL].current, - net->ratectrs->ctr[MSC_CTR_BTS_RSL_FAIL].current, + net->bsc_ctrs->ctr[BSC_CTR_BTS_OML_FAIL].current, + net->bsc_ctrs->ctr[BSC_CTR_BTS_RSL_FAIL].current, VTY_NEWLINE); } diff --git a/openbsc/src/libbsc/gsm_04_08_utils.c b/openbsc/src/libbsc/gsm_04_08_utils.c index d4eca4a..46df108 100644 --- a/openbsc/src/libbsc/gsm_04_08_utils.c +++ b/openbsc/src/libbsc/gsm_04_08_utils.c @@ -304,7 +304,7 @@ subscr = conn->subscr; } - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_PAGING_COMPLETED]); + rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_PAGING_COMPLETED]); /* Stop paging on the bts we received the paging response */ paging_request_stop(conn->bts, subscr, conn, msg); diff --git a/openbsc/src/libbsc/handover_logic.c b/openbsc/src/libbsc/handover_logic.c index 5424e27..ffcca66 100644 --- a/openbsc/src/libbsc/handover_logic.c +++ b/openbsc/src/libbsc/handover_logic.c @@ -103,7 +103,7 @@ DEBUGP(DHO, "(old_lchan on BTS %u, new BTS %u)\n", old_lchan->ts->trx->bts->nr, bts->nr); - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_HANDOVER_ATTEMPTED]); + rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_HANDOVER_ATTEMPTED]); if (!old_lchan->conn) { LOGP(DHO, LOGL_ERROR, "Old lchan lacks connection data.\n"); @@ -113,7 +113,7 @@ new_lchan = lchan_alloc(bts, old_lchan->type, 0); if (!new_lchan) { LOGP(DHO, LOGL_NOTICE, "No free channel\n"); - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_HANDOVER_NO_CHANNEL]); + rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_HANDOVER_NO_CHANNEL]); return -ENOSPC; } @@ -188,7 +188,7 @@ struct gsm_network *net = ho->new_lchan->ts->trx->bts->network; DEBUGP(DHO, "HO T3103 expired\n"); - rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_HANDOVER_TIMEOUT]); + rate_ctr_inc(&net->bsc_ctrs->ctr[BSC_CTR_HANDOVER_TIMEOUT]); ho->new_lchan->conn->ho_lchan = NULL; ho->new_lchan->conn = NULL; @@ -265,7 +265,7 @@ ho->old_lchan->ts->trx->bts->nr, new_lchan->ts->trx->bts->nr, ho->old_lchan->ts->trx->arfcn, new_lchan->ts->trx->arfcn); - rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_HANDOVER_COMPLETED]); + rate_ctr_inc(&net->bsc_ctrs->ctr[BSC_CTR_HANDOVER_COMPLETED]); osmo_timer_del(&ho->T3103); @@ -303,7 +303,7 @@ return -ENODEV; } - rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_HANDOVER_FAILED]); + rate_ctr_inc(&net->bsc_ctrs->ctr[BSC_CTR_HANDOVER_FAILED]); new_lchan = ho->new_lchan; diff --git a/openbsc/src/libbsc/net_init.c b/openbsc/src/libbsc/net_init.c index 9e4ccf6..a9f5600 100644 --- a/openbsc/src/libbsc/net_init.c +++ b/openbsc/src/libbsc/net_init.c @@ -81,7 +81,8 @@ INIT_LLIST_HEAD(&net->bts_list); /* init statistics */ - net->ratectrs = rate_ctr_group_alloc(net, &msc_ctrg_desc, 0); + net->bsc_ctrs = rate_ctr_group_alloc(net, &bsc_ctrg_desc, 0); + net->bsc_ctrs = rate_ctr_group_alloc(net, &msc_ctrg_desc, 0); net->mncc_recv = mncc_recv; net->ext_min = GSM_MIN_EXTEN; diff --git a/openbsc/src/libbsc/paging.c b/openbsc/src/libbsc/paging.c index 03c91fd..fcb4deb 100644 --- a/openbsc/src/libbsc/paging.c +++ b/openbsc/src/libbsc/paging.c @@ -260,7 +260,7 @@ req, req->subscr->imsi); /* must be destroyed before calling cbfn, to prevent double free */ - rate_ctr_inc(&req->bts->network->ratectrs->ctr[MSC_CTR_PAGING_EXPIRED]); + rate_ctr_inc(&req->bts->network->bsc_ctrs->ctr[BSC_CTR_PAGING_EXPIRED]); cbfn_param = req->cbfn_param; cbfn = req->cbfn; @@ -330,7 +330,7 @@ struct gsm_bts *bts = NULL; int num_pages = 0; - rate_ctr_inc(&network->ratectrs->ctr[MSC_CTR_PAGING_ATTEMPTED]); + rate_ctr_inc(&network->bsc_ctrs->ctr[BSC_CTR_PAGING_ATTEMPTED]); /* start paging subscriber on all BTS within Location Area */ do { @@ -349,7 +349,7 @@ } while (1); if (num_pages == 0) - rate_ctr_inc(&network->ratectrs->ctr[MSC_CTR_PAGING_DETACHED]); + rate_ctr_inc(&network->bsc_ctrs->ctr[BSC_CTR_PAGING_DETACHED]); return num_pages; } diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c index c4ecf1c..c30fbb0 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/src/libmsc/gsm_04_08.c @@ -457,7 +457,7 @@ struct gsm_bts *bts = conn->bts; struct msgb *msg; - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_REJECT]); + rate_ctr_inc(&bts->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_RESP_REJECT]); msg = gsm48_create_loc_upd_rej(cause); if (!msg) { @@ -506,7 +506,7 @@ DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n"); - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_ACCEPT]); + rate_ctr_inc(&bts->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_RESP_ACCEPT]); return gsm48_conn_sendmsg(msg, conn, NULL); } @@ -637,13 +637,13 @@ switch (lu->type) { case GSM48_LUPD_NORMAL: - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_NORMAL]); + rate_ctr_inc(&bts->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_NORMAL]); break; case GSM48_LUPD_IMSI_ATT: - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_ATTACH]); + rate_ctr_inc(&bts->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_ATTACH]); break; case GSM48_LUPD_PERIODIC: - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_PERIODIC]); + rate_ctr_inc(&bts->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_PERIODIC]); break; } @@ -1063,7 +1063,7 @@ DEBUGP(DMM, "IMSI DETACH INDICATION: MI(%s)=%s", gsm48_mi_type_name(mi_type), mi_string); - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_DETACH]); + rate_ctr_inc(&bts->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_DETACH]); switch (mi_type) { case GSM_MI_TYPE_TMSI: @@ -2002,7 +2002,7 @@ subscr_name(trans->subscr), trans->subscr->extension, setup.called.number); - rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MO_SETUP]); + rate_ctr_inc(&trans->net->msc_ctrs->ctr[MSC_CTR_CALL_MO_SETUP]); /* indicate setup to MNCC */ mncc_recvmsg(trans->net, trans, MNCC_SETUP_IND, &setup); @@ -2080,7 +2080,7 @@ new_cc_state(trans, GSM_CSTATE_CALL_PRESENT); - rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MT_SETUP]); + rate_ctr_inc(&trans->net->msc_ctrs->ctr[MSC_CTR_CALL_MT_SETUP]); return gsm48_conn_sendmsg(msg, trans->conn, trans); } @@ -2306,7 +2306,7 @@ } new_cc_state(trans, GSM_CSTATE_CONNECT_REQUEST); - rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MT_CONNECT]); + rate_ctr_inc(&trans->net->msc_ctrs->ctr[MSC_CTR_CALL_MT_CONNECT]); return mncc_recvmsg(trans->net, trans, MNCC_SETUP_CNF, &connect); } @@ -2319,7 +2319,7 @@ gsm48_stop_cc_timer(trans); new_cc_state(trans, GSM_CSTATE_ACTIVE); - rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MO_CONNECT_ACK]); + rate_ctr_inc(&trans->net->msc_ctrs->ctr[MSC_CTR_CALL_MO_CONNECT_ACK]); memset(&connect_ack, 0, sizeof(struct gsm_mncc)); connect_ack.callref = trans->callref; diff --git a/openbsc/src/libmsc/gsm_04_11.c b/openbsc/src/libmsc/gsm_04_11.c index fba5208..0392d00 100644 --- a/openbsc/src/libmsc/gsm_04_11.c +++ b/openbsc/src/libmsc/gsm_04_11.c @@ -315,14 +315,14 @@ rc = smpp_try_deliver(gsms, conn); if (rc == 1) { rc = 1; /* cause 1: unknown subscriber */ - rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); + rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); } else if (rc < 0) { rc = 21; /* cause 21: short message transfer rejected */ /* FIXME: handle the error somehow? */ } #else rc = 1; /* cause 1: unknown subscriber */ - rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); + rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); #endif return rc; } @@ -363,7 +363,7 @@ uint8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */ int rc = 0; - rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_SUBMITTED]); + rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_SUBMITTED]); gsms = sms_alloc(); if (!gsms) @@ -633,10 +633,10 @@ * to store this in our database and wait for a SMMA message */ /* FIXME */ send_signal(S_SMS_MEM_EXCEEDED, trans, sms, 0); - rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_MEM]); + rate_ctr_inc(&net->msc_ctrs->ctr[MSC_CTR_SMS_RP_ERR_MEM]); } else { send_signal(S_SMS_UNKNOWN_ERROR, trans, sms, 0); - rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_OTHER]); + rate_ctr_inc(&net->msc_ctrs->ctr[MSC_CTR_SMS_RP_ERR_OTHER]); } sms_free(sms); @@ -932,7 +932,7 @@ DEBUGP(DLSMS, "TX: SMS DELIVER\n"); - rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_DELIVERED]); + rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_DELIVERED]); db_sms_inc_deliver_attempts(trans->sms.sms); return gsm411_rp_sendmsg(&trans->sms.smr_inst, msg, diff --git a/openbsc/src/libmsc/vty_interface_layer3.c b/openbsc/src/libmsc/vty_interface_layer3.c index d1041b3..e7ff0a9 100644 --- a/openbsc/src/libmsc/vty_interface_layer3.c +++ b/openbsc/src/libmsc/vty_interface_layer3.c @@ -795,41 +795,41 @@ openbsc_vty_print_statistics(vty, net); vty_out(vty, "Location Update : %lu attach, %lu normal, %lu periodic%s", - net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_ATTACH].current, - net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_NORMAL].current, - net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_PERIODIC].current, + net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_ATTACH].current, + net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_NORMAL].current, + net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_PERIODIC].current, VTY_NEWLINE); vty_out(vty, "IMSI Detach Indications : %lu%s", - net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_DETACH].current, + net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_DETACH].current, VTY_NEWLINE); vty_out(vty, "Location Update Response: %lu accept, %lu reject%s", - net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_ACCEPT].current, - net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_REJECT].current, + net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_RESP_ACCEPT].current, + net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_RESP_REJECT].current, VTY_NEWLINE); vty_out(vty, "Handover : %lu attempted, %lu no_channel, %lu timeout, " "%lu completed, %lu failed%s", - net->ratectrs->ctr[MSC_CTR_HANDOVER_ATTEMPTED].current, - net->ratectrs->ctr[MSC_CTR_HANDOVER_NO_CHANNEL].current, - net->ratectrs->ctr[MSC_CTR_HANDOVER_TIMEOUT].current, - net->ratectrs->ctr[MSC_CTR_HANDOVER_COMPLETED].current, - net->ratectrs->ctr[MSC_CTR_HANDOVER_FAILED].current, + net->msc_ctrs->ctr[BSC_CTR_HANDOVER_ATTEMPTED].current, + net->msc_ctrs->ctr[BSC_CTR_HANDOVER_NO_CHANNEL].current, + net->msc_ctrs->ctr[BSC_CTR_HANDOVER_TIMEOUT].current, + net->msc_ctrs->ctr[BSC_CTR_HANDOVER_COMPLETED].current, + net->msc_ctrs->ctr[BSC_CTR_HANDOVER_FAILED].current, VTY_NEWLINE); vty_out(vty, "SMS MO : %lu submitted, %lu no receiver%s", - net->ratectrs->ctr[MSC_CTR_SMS_SUBMITTED].current, - net->ratectrs->ctr[MSC_CTR_SMS_NO_RECEIVER].current, + net->msc_ctrs->ctr[MSC_CTR_SMS_SUBMITTED].current, + net->msc_ctrs->ctr[MSC_CTR_SMS_NO_RECEIVER].current, VTY_NEWLINE); vty_out(vty, "SMS MT : %lu delivered, %lu no memory, %lu other error%s", - net->ratectrs->ctr[MSC_CTR_SMS_DELIVERED].current, - net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_MEM].current, - net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_OTHER].current, + net->msc_ctrs->ctr[MSC_CTR_SMS_DELIVERED].current, + net->msc_ctrs->ctr[MSC_CTR_SMS_RP_ERR_MEM].current, + net->msc_ctrs->ctr[MSC_CTR_SMS_RP_ERR_OTHER].current, VTY_NEWLINE); vty_out(vty, "MO Calls : %lu setup, %lu connect ack%s", - net->ratectrs->ctr[MSC_CTR_CALL_MO_SETUP].current, - net->ratectrs->ctr[MSC_CTR_CALL_MO_CONNECT_ACK].current, + net->msc_ctrs->ctr[MSC_CTR_CALL_MO_SETUP].current, + net->msc_ctrs->ctr[MSC_CTR_CALL_MO_CONNECT_ACK].current, VTY_NEWLINE); vty_out(vty, "MT Calls : %lu setup, %lu connect%s", - net->ratectrs->ctr[MSC_CTR_CALL_MT_SETUP].current, - net->ratectrs->ctr[MSC_CTR_CALL_MT_CONNECT].current, + net->msc_ctrs->ctr[MSC_CTR_CALL_MT_SETUP].current, + net->msc_ctrs->ctr[MSC_CTR_CALL_MT_CONNECT].current, VTY_NEWLINE); return CMD_SUCCESS; } -- To view, visit https://gerrit.osmocom.org/646 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I7361033cd1eb919ec3c2ea2652f40ab8c75b2f99 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus From gerrit-no-reply at lists.osmocom.org Tue Aug 2 09:58:33 2016 From: gerrit-no-reply at lists.osmocom.org (lynxis lazus) Date: Tue, 2 Aug 2016 09:58:33 +0000 Subject: openbsc[master]: sms: change rp err cause of smpp_try_deliver errors In-Reply-To: References: Message-ID: Patch Set 1: (1 comment) > Let's assume you want to debug this at the 33C3. Do these two messages > have enough content for you to build a hypothesis and/or know for which > SMPP message to sarch in the trace? @Holger: I do not know. Only took a short look on this issue. I would suggest to log the error when it's happening in the smpp_try_deliver() function and not here. https://gerrit.osmocom.org/#/c/551/1/openbsc/src/libmsc/gsm_04_11.c File openbsc/src/libmsc/gsm_04_11.c: Line 298: LOGP(DLSMS, LOGL_ERROR, "While trying to deliver a SMS the error code %d received. Sending rp err cause 41 to ms\n", rc); > Let's assume you want to debug this at the 33C3. Do these two messages have u -- To view, visit https://gerrit.osmocom.org/551 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia03e50ce2bd9a7d1054cc5a6000fd73bd3497c03 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: lynxis lazus Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 2 13:19:43 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Tue, 2 Aug 2016 13:19:43 +0000 Subject: [PATCH] openbsc[master]: Add python functions to get/set ctrl variables In-Reply-To: References: Message-ID: Hello Harald Welte, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/645 to look at the new patch set (#2). Add python functions to get/set ctrl variables Add get_var and set_var functions which handle requested variable while checking for proper response and id. Change-Id: I2bc275b801a4b78642653f5b0a91e8cbea25422a Related: OS#1646 --- M openbsc/contrib/bsc_control.py 1 file changed, 22 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/45/645/2 diff --git a/openbsc/contrib/bsc_control.py b/openbsc/contrib/bsc_control.py index 4fc8b4d..dda319b 100755 --- a/openbsc/contrib/bsc_control.py +++ b/openbsc/contrib/bsc_control.py @@ -44,6 +44,28 @@ getmsg = "GET %s %s" %(op_id, var) send(sck, getmsg) +def do_set_get(sck, var, is_get = True, value = None): + r = random.randint(1, sys.maxint) + if (is_get): + s = 'GET_REPLY' + do_get(var, r, sck) + else: + s = 'SET_REPLY' + do_set(var, value, r, sck) + (answer, data) = remove_ipa_ctrl_header(sck.recv(4096)) + x = answer.split() + if (s == x[0] and str(r) == x[1] and var == x[2]): + if (not is_get and value != x[3]): + return None + return x[3] + return None + +def set_var(sck, var, val): + return do_set_get(sck, var, False, val) + +def get_var(sck, var): + return do_set_get(sck, var) + if __name__ == '__main__': random.seed() -- To view, visit https://gerrit.osmocom.org/645 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I2bc275b801a4b78642653f5b0a91e8cbea25422a Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte From gerrit-no-reply at lists.osmocom.org Tue Aug 2 13:47:19 2016 From: gerrit-no-reply at lists.osmocom.org (bhargava_abhyankar) Date: Tue, 2 Aug 2016 13:47:19 +0000 Subject: osmo-bts[master]: Update parameters in osmo-bts for 11 bit RACH In-Reply-To: References: Message-ID: Patch Set 4: (2 comments) https://gerrit.osmocom.org/#/c/434/3//COMMIT_MSG Commit Message: Line 7: Update parameters in osmo-bts for 11 bit RACH > you are only modifying osmo-bts-sysmo, so please make that clear in the com okay. I will change the commit message https://gerrit.osmocom.org/#/c/434/4/src/osmo-bts-sysmo/l1_if.h File src/osmo-bts-sysmo/l1_if.h: PS4, Line 45: : > you're not using the enum that I had asked in my previous commit, sorry. T Sorry. I misunderstood the comment. Will correct and submit. -- To view, visit https://gerrit.osmocom.org/434 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I93831ddfb3f31b637e6a576f23a9bb4557758582 Gerrit-PatchSet: 4 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: bhargava_abhyankar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 2 14:56:23 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Tue, 2 Aug 2016 14:56:23 +0000 Subject: [PATCH] openbsc[master]: Add web proxy for control interface Message-ID: Review at https://gerrit.osmocom.org/647 Add web proxy for control interface Add web application exposing Control Interface over web. Change-Id: Id3fc7e6dcf28fe543dc32930e737eae5bc188656 Related: OS#1646 --- A openbsc/contrib/ctrl2sse.py 1 file changed, 115 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/47/647/1 diff --git a/openbsc/contrib/ctrl2sse.py b/openbsc/contrib/ctrl2sse.py new file mode 100755 index 0000000..f8ef8bc --- /dev/null +++ b/openbsc/contrib/ctrl2sse.py @@ -0,0 +1,115 @@ +#!/usr/bin/python2 + +mod_license = """ +/* + * Copyright (C) 2016 sysmocom s.f.m.c. GmbH + * + * All Rights Reserved + * + * 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +""" + +import argparse, tornado.ioloop, tornado.web, random, bsc_control +from eventsource import listener + +""" +N. B: this is not an example of building proper REST API or building secure web application. +It's only purpose is to illustrate conversion of Osmocom's Control Interface to web-friendly API. +Exposing this to Internet while connected to production network might lead to all sorts of mischief and mayhem +from NSA' TAO breaking into your network to zombie apocalypse. Do NOT do that. +""" + +def d(s, v): + return { + 'interface' : tornado.escape.json_encode(s.getpeername()), + 'variable' : v, + 'value' : bsc_control.get_var(s, tornado.escape.native_str(v)) + } + +class CtrlHandler(tornado.web.RequestHandler): + """ + Return json according to following schema - see http://json-schema.org/documentation.html for details: + { + "title": "Ctrl Schema", + "type": "object", + "properties": { + "interface": { + "type": "string" + }, + "variable": { + "type": "string" + }, + "varlue": { + "type": "string" + } + }, + "required": ["interface", "variable", "value"] + } + Example validation from command-line: + json validate --schema-file=schema.json --document-file=data.json + The interface is represented as string because it might look different for IPv4 vs v6. + """ + def initialize(self): + self.skt = bsc_control.connect(self.settings['host'], self.settings['port']) + +class GetCtrl(CtrlHandler): + def get(self, var): + self.write(d(self.skt, var)) + + def post(self): + self.write(d(self.skt, self.get_argument("variable"))) + +class SetCtrl(CtrlHandler): + def get(self, var, val): + bsc_control.set_var(self.skt, tornado.escape.native_str(var), tornado.escape.native_str(val)) + self.write(d(self.skt, tornado.escape.native_str(var))) + + def post(self): + v = tornado.escape.native_str(self.get_argument("variable")) + bsc_control.set_var(self.skt, v, tornado.escape.native_str(self.get_argument("value"))) + self.write(d(self.skt, v)) + +class Slash(tornado.web.RequestHandler): + def get(self): + self.write('' + '
' + '' + '' + '
' + '
' + '' + '' + '' + '
' + '') + +if __name__ == '__main__': + p = argparse.ArgumentParser(description='Osmocom Control Interface proxy.') + p.add_argument('-c', '--control-port', type = int, default = 4249, help = 'Target Control Interface port') + p.add_argument('-a', '--control-host', default = 'localhost', help = 'Target Control Interface adress') + p.add_argument('-p', '--port', type = int, default = 6969, help = "Port to bind proxy's web interface") + args = p.parse_args() + application = tornado.web.Application([ + (r"/", Slash), + (r"/get", GetCtrl), + (r"/get/(.*)", GetCtrl), + (r"/set", SetCtrl), + (r"/set/(.*)/(.*)", SetCtrl), +# (r"/sse/(.*)/(.*)", listener.EventSourceHandler, dict(event_class = listener.StringIdEvent, keepalive = 10)), + ], debug = True, host = args.control_host, port = args.control_port) + random.seed() + application.listen(args.port) + tornado.ioloop.IOLoop.instance().start() -- To view, visit https://gerrit.osmocom.org/647 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Id3fc7e6dcf28fe543dc32930e737eae5bc188656 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max From gerrit-no-reply at lists.osmocom.org Tue Aug 2 15:19:29 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Tue, 2 Aug 2016 15:19:29 +0000 Subject: [PATCH] libosmocore[master]: Add control interface port for GGSN Message-ID: Review at https://gerrit.osmocom.org/648 Add control interface port for GGSN Change-Id: Ie7232189fe3265a8631fd3652b2c8c152cdee918 Related: OS#1646 --- M include/osmocom/ctrl/ports.h 1 file changed, 1 insertion(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/48/648/1 diff --git a/include/osmocom/ctrl/ports.h b/include/osmocom/ctrl/ports.h index 71c8e2d..c89bbe3 100644 --- a/include/osmocom/ctrl/ports.h +++ b/include/osmocom/ctrl/ports.h @@ -6,4 +6,5 @@ #define OSMO_CTRL_PORT_NITB_BSC 4249 #define OSMO_CTRL_PORT_BSC_NAT 4250 #define OSMO_CTRL_PORT_SGSN 4251 +#define OSMO_CTRL_PORT_GGSN 4252 #define OSMO_CTRL_PORT_CSCN 4255 -- To view, visit https://gerrit.osmocom.org/648 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ie7232189fe3265a8631fd3652b2c8c152cdee918 Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Max From gerrit-no-reply at lists.osmocom.org Wed Aug 3 06:45:16 2016 From: gerrit-no-reply at lists.osmocom.org (bhargava_abhyankar) Date: Wed, 3 Aug 2016 06:45:16 +0000 Subject: [PATCH] osmo-bts[master]: Update parameters in osmo-bts-sysmo for 11bit RACH In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/434 to look at the new patch set (#5). Update parameters in osmo-bts-sysmo for 11bit RACH Based on the indication from L1, number of bits in RACH and burst type is determined. Appropriate parameters are filled in osmo-bts-sysmo. These parameters are sent to osmo-pcu for processing of the RACH. Change-Id: I93831ddfb3f31b637e6a576f23a9bb4557758582 --- M src/osmo-bts-sysmo/l1_if.c 1 file changed, 36 insertions(+), 6 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/34/434/5 diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index a529e3a..708465e 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -925,7 +925,8 @@ struct gsm_lchan *lchan; struct osmo_phsap_prim *l1sap; uint32_t fn; - uint8_t ra, acc_delay = 0; + uint8_t acc_delay = 0; + uint16_t ra = 0, is_11bit = 0, burst_type = 0, temp = 0; int rc; /* increment number of busy RACH slots, if required */ @@ -947,16 +948,28 @@ btsb->load.rach.access++; dump_meas_res(LOGL_DEBUG, &ra_ind->measParam); + burst_type = ra_ind->burstType; - if (ra_ind->msgUnitParam.u8Size != 1) { + if ((ra_ind->msgUnitParam.u8Size != 1) && + (ra_ind->msgUnitParam.u8Size != 2)) { LOGP(DL1C, LOGL_ERROR, "PH-RACH-INDICATION has %d bits\n", ra_ind->sapi); msgb_free(l1p_msg); return 0; } + if (ra_ind->msgUnitParam.u8Size == 2) { + is_11bit = 1; + ra = ra_ind->msgUnitParam.u8Buffer[0]; + ra = ra << 3; + temp = (ra_ind->msgUnitParam.u8Buffer[1] & 0x7); + ra = ra | temp; + } else { + is_11bit = 0; + ra = ra_ind->msgUnitParam.u8Buffer[0]; + } + fn = ra_ind->u32Fn; - ra = ra_ind->msgUnitParam.u8Buffer[0]; rc = msgb_trim(l1p_msg, sizeof(*l1sap)); if (rc < 0) MSGB_ABORT(l1p_msg, "No room for primitive data\n"); @@ -966,11 +979,28 @@ l1sap->u.rach_ind.ra = ra; l1sap->u.rach_ind.acc_delay = acc_delay; l1sap->u.rach_ind.fn = fn; + l1sap->u.rach_ind.is_11bit = is_11bit; /* no of bits in 11 bit RACH */ - /* Initialising the parameters needs to be handled when 11 bit RACH */ + /*mapping of the burst type, the values are specific to osmo-bts-sysmo*/ - l1sap->u.rach_ind.is_11bit = 0; - l1sap->u.rach_ind.burst_type = GSM_L1_BURST_TYPE_ACCESS_0; + switch (burst_type) { + case GsmL1_BurstType_Access_0 : + l1sap->u.rach_ind.burst_type = + GSM_L1_BURST_TYPE_ACCESS_0; + break; + case GsmL1_BurstType_Access_1 : + l1sap->u.rach_ind.burst_type = + GSM_L1_BURST_TYPE_ACCESS_1; + break; + case GsmL1_BurstType_Access_2 : + l1sap->u.rach_ind.burst_type = + GSM_L1_BURST_TYPE_ACCESS_2; + break; + default : + l1sap->u.rach_ind.burst_type = + GSM_L1_BURST_TYPE_NONE; + break; + } if (!lchan || lchan->ts->pchan == GSM_PCHAN_CCCH || lchan->ts->pchan == GSM_PCHAN_CCCH_SDCCH4) -- To view, visit https://gerrit.osmocom.org/434 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I93831ddfb3f31b637e6a576f23a9bb4557758582 Gerrit-PatchSet: 5 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: bhargava_abhyankar From gerrit-no-reply at lists.osmocom.org Wed Aug 3 14:21:52 2016 From: gerrit-no-reply at lists.osmocom.org (bhargava_abhyankar) Date: Wed, 3 Aug 2016 14:21:52 +0000 Subject: osmo-bts[master]: Change interface in osmo-bts for 11 bit RACH In-Reply-To: References: Message-ID: Patch Set 4: (1 comment) https://gerrit.osmocom.org/#/c/433/4/src/osmo-bts-sysmo/l1_if.c File src/osmo-bts-sysmo/l1_if.c: Line 971: l1sap->u.rach_ind.is_11bit = 0; > the parameters are only initialized in the osmo-bts-sysmo code. What about Other bts models will not breaking since values of parameter are zero initialized. And this case is handled in pcu, and a log message is added. -- To view, visit https://gerrit.osmocom.org/433 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I4f4c501b2d86d77c78de32a84b1804172ffb6f4d Gerrit-PatchSet: 4 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: bhargava_abhyankar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Wed Aug 3 16:01:44 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Wed, 3 Aug 2016 16:01:44 +0000 Subject: [PATCH] openbsc[master]: Add web proxy for control interface In-Reply-To: References: Message-ID: Add web proxy for control interface Add web application exposing Control Interface over web. Only SET and GET but not TRAP operations are supported at the moment. Change-Id: Id3fc7e6dcf28fe543dc32930e737eae5bc188656 Related: OS#1646 --- A openbsc/contrib/ctrl2sse.py 1 file changed, 113 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/47/647/2 diff --git a/openbsc/contrib/ctrl2sse.py b/openbsc/contrib/ctrl2sse.py new file mode 100755 index 0000000..32440aa --- /dev/null +++ b/openbsc/contrib/ctrl2sse.py @@ -0,0 +1,113 @@ +#!/usr/bin/python2 + +mod_license = """ +/* + * Copyright (C) 2016 sysmocom s.f.m.c. GmbH + * + * All Rights Reserved + * + * 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +""" + +import argparse, tornado.ioloop, tornado.web, random, bsc_control +from eventsource import listener + +""" +N. B: this is not an example of building proper REST API or building secure web application. +It's only purpose is to illustrate conversion of Osmocom's Control Interface to web-friendly API. +Exposing this to Internet while connected to production network might lead to all sorts of mischief and mayhem +from NSA' TAO breaking into your network to zombie apocalypse. Do NOT do that. +""" + +def d(s, v): + return { + 'interface' : tornado.escape.json_encode(s.getpeername()), + 'variable' : v, + 'value' : bsc_control.get_var(s, tornado.escape.native_str(v)) + } + +class CtrlHandler(tornado.web.RequestHandler): + """ + Return json according to following schema - see http://json-schema.org/documentation.html for details: + { + "title": "Ctrl Schema", + "type": "object", + "properties": { + "interface": { + "type": "string" + }, + "variable": { + "type": "string" + }, + "varlue": { + "type": "string" + } + }, + "required": ["interface", "variable", "value"] + } + Example validation from command-line: + json validate --schema-file=schema.json --document-file=data.json + The interface is represented as string because it might look different for IPv4 vs v6. + """ + def initialize(self): + self.skt = bsc_control.connect(self.settings['host'], self.settings['port']) + + def get(self, v): + self.write(d(self.skt, v)) + + def post(self): + self.write(d(self.skt, self.get_argument("variable"))) + +class SetCtrl(CtrlHandler): + def get(self, var, val): + bsc_control.set_var(self.skt, tornado.escape.native_str(var), tornado.escape.native_str(val)) + super(SetCtrl, self).get(tornado.escape.native_str(var)) + + def post(self): + bsc_control.set_var(self.skt, tornado.escape.native_str(self.get_argument("variable")), tornado.escape.native_str(self.get_argument("value"))) + super(SetCtrl, self).post() + +class Slash(tornado.web.RequestHandler): + def get(self): + self.write('' + '
' + '' + '' + '
' + '
' + '' + '' + '' + '
' + '') + +if __name__ == '__main__': + p = argparse.ArgumentParser(description='Osmocom Control Interface proxy.') + p.add_argument('-c', '--control-port', type = int, default = 4249, help = 'Target Control Interface port') + p.add_argument('-a', '--control-host', default = 'localhost', help = 'Target Control Interface adress') + p.add_argument('-p', '--port', type = int, default = 6969, help = "Port to bind proxy's web interface") + args = p.parse_args() + application = tornado.web.Application([ + (r"/", Slash), + (r"/get", CtrlHandler), + (r"/get/(.*)", CtrlHandler), + (r"/set", SetCtrl), + (r"/set/(.*)/(.*)", SetCtrl), +# (r"/sse/(.*)/(.*)", listener.EventSourceHandler, dict(event_class = listener.StringIdEvent, keepalive = 10)), + ], debug = True, host = args.control_host, port = args.control_port) + random.seed() + application.listen(args.port) + tornado.ioloop.IOLoop.instance().start() -- To view, visit https://gerrit.osmocom.org/647 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Id3fc7e6dcf28fe543dc32930e737eae5bc188656 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max From gerrit-no-reply at lists.osmocom.org Wed Aug 3 16:43:12 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Wed, 3 Aug 2016 16:43:12 +0000 Subject: [PATCH] openbsc[master]: Added code to control GPRS TCP/IP header compression. In-Reply-To: References: Message-ID: Added code to control GPRS TCP/IP header compression. In this commit two modules were added: gprs_sndcp_comp_entity.h/c: This part handles the creation and destruction of conpression entites. It handles the allocation and freeing of the memory and offers functions to query compression parameters (i.e. which compression entity should be used if a packet from NSAPI x has to be compressed?) gprs_sndcp_hdrcomp.c/h: This is the code that performs the actual header compression. It takes care that the packets are compressed/decompressed with the right modes etc. It works, but is not yet ready for merging. Both files depend on each other so that they only can be merged both at the same time. Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 --- M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_sndcp_comp_entity.h A openbsc/include/openbsc/gprs_sndcp_hdrcomp.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/gprs_sndcp_comp_entity.c A openbsc/src/gprs/gprs_sndcp_hdrcomp.c 6 files changed, 690 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/42/642/2 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index b37103f..e159db5 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,8 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h gprs_sndcp_xid.h + gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h gprs_sndcp_xid.h \ + gprs_sndcp_comp_entity.h gprs_sndcp_hdrcomp.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_sndcp_comp_entity.h b/openbsc/include/openbsc/gprs_sndcp_comp_entity.h new file mode 100644 index 0000000..677b82d --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_comp_entity.h @@ -0,0 +1,91 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_SNDCP_COMP_ENTITY_H +#define _GPRS_SNDCP_COMP_ENTITY_H + +#include +#include +#include + +/* Header / Data compression entity */ +struct gprs_sndcp_comp_entity +{ + struct llist_head list; + + /* Serves as an ID in case we want to delete this entity later */ + int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + + /* Specifies to which NSAPIs the compression entity is assigned */ + int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + int nsapi[11]; /* Applicable NSAPIs (default 0) */ + + /* Assigned pcomp values */ + int comp_len; /* Number of contained PCOMP / DCOMP values */ + int comp[16]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */ + + /* Algorithm parameters */ + int algo; /* Algorithm type (see gprs_sndcp_xid.h) */ + int compclass; /* See gprs_sndcp_xid.h/c */ + void *status; /* Algorithm status and parameters */ +}; + +/* Free a list with compression entities */ +void gprs_sndcp_comp_entities_free (struct llist_head *comp_entities); + +/* Delete a compression entity */ +void gprs_sndcp_comp_entities_delete (struct llist_head *comp_entities, + int entity); + +/* Create and Add a new compression entity +(returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entities_add (struct llist_head *comp_entities, + struct gprs_sndcp_comp_field *comp_field); + +/* Find compression entity by its entity number */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_entity (struct llist_head*comp_entities, + int entity); + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_comp (struct llist_head *comp_entities, + int comp); + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_nsapi (struct llist_head *comp_entities, + int nsapi); + +/* Find a comp_index for a given pcomp/dcomp value */ +int +gprs_sndcp_comp_entity_find_comp_index_by_comp (struct gprs_sndcp_comp_entity + *comp_entity, int comp); + +/* Find a pcomp/dcomp value for a given comp_index */ +int +gprs_sndcp_comp_entity_find_comp_by_comp_index (struct gprs_sndcp_comp_entity + *comp_entity, + int comp_index); + +#endif diff --git a/openbsc/include/openbsc/gprs_sndcp_hdrcomp.h b/openbsc/include/openbsc/gprs_sndcp_hdrcomp.h new file mode 100644 index 0000000..e73bad1 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_hdrcomp.h @@ -0,0 +1,68 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_SNDCP_HDRCOMP_H +#define _GPRS_SNDCP_HDRCOMP_H + +#include +#include +#include + +/* 1=Bypass any header compression, 0=Normal */ +#define GPRS_SNDCP_HDRCOMP_BYPASS 0 + +/* Header compression entity */ +struct gprs_sndcp_hdrcomp_compression_entity { + + /* Specifies to which NSAPIs the compression entity is assigned */ + int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + int nsapi[11]; /* Applicable NSAPIs (default 0) */ + + /* Assigned pcomp values */ + int pcomp_len; /* Number of contained PCOMP / DCOMP values */ + int pcomp[16]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */ + + /* Algorithm parameters */ + int compclass; /* 1=Header compression, 2=Data compression */ + int algo; /* Algorithm type (see gprs_sndcp_xid.h) */ + void *status; /* Algorithm status and parameters */ +}; + + +/* Initalize header compression */ +int gprs_sndcp_hdrcomp_init(struct gprs_sndcp_comp_entity *comp_entity, + struct gprs_sndcp_comp_field *comp_field); + +/* Terminate header compression */ +void gprs_sndcp_hdrcomp_term(struct gprs_sndcp_comp_entity *comp_entity); + +/* Expand header compressed packet */ +int gprs_sndcp_hdrcomp_expand(uint8_t * packet, int packet_len, int pcomp, + struct llist_head *comp_entities); + +/* Expand header compressed packet */ +int gprs_sndcp_hdrcomp_compress(uint8_t * packet, int packet_len, + int *pcomp, + struct llist_head *comp_entities, + int nsapi); + +#endif diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 67e9943..3d6c82a 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -21,7 +21,8 @@ $(OSMO_LIBS) $(LIBCRYPTO_LIBS) -lrt osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \ - slhc.c gprs_sndcp_xid.c \ + slhc.c gprs_sndcp_xid.c gprs_sndcp_comp_entity.c \ + gprs_sndcp_hdrcomp.c \ sgsn_main.c sgsn_vty.c sgsn_libgtp.c \ gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c \ gprs_llc_xid.c crc24.c \ diff --git a/openbsc/src/gprs/gprs_sndcp_comp_entity.c b/openbsc/src/gprs/gprs_sndcp_comp_entity.c index 095a32a..c2e8b08 100644 --- a/openbsc/src/gprs/gprs_sndcp_comp_entity.c +++ b/openbsc/src/gprs/gprs_sndcp_comp_entity.c @@ -86,7 +86,11 @@ } comp_entity->algo = comp_field->algo; +<<<<<<< HEAD comp_entity->state = NULL; +======= + comp_entity->status = NULL; +>>>>>>> 4cf3ad6... Added code to control GPRS TCP/IP header compression. /* Determine of which class our compression entity will be (Protocol or Data compresson ?) */ diff --git a/openbsc/src/gprs/gprs_sndcp_hdrcomp.c b/openbsc/src/gprs/gprs_sndcp_hdrcomp.c new file mode 100644 index 0000000..8796684 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_hdrcomp.c @@ -0,0 +1,523 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* Enable private debug messages */ +#define GPRS_SNDCP_HDRCOMP_DEBUG 1 + +/* Test RFC1144 implementation + (Caution: GPRS_SNDCP_HDRCOMP_BYPASS in .h file has to be set to 1!) */ +#define GPRS_SNDCP_HDRCOMP_RFC1144_TEST 0 + +/* Exit immediately in case of RFC1144 test failure */ +#define GPRS_SNDCP_HDRCOMP_RFC1144_TEST_EXITONERR 1 + +/* For debug/test only! */ +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST == 1 +static struct slcompress *test_compression_state_tx = NULL; +static struct slcompress *test_compression_state_rx = NULL; +static int test_errors = 0; +static int gprs_sndcp_hdrcomp_test_ind(uint8_t * packet, int packet_len); +static int gprs_sndcp_hdrcomp_test_req(uint8_t * packet, int packet_len); +#endif + + +/* Initalize header compression */ +int gprs_sndcp_hdrcomp_init(struct gprs_sndcp_comp_entity *comp_entity, + struct gprs_sndcp_comp_field *comp_field) +{ + /* Note: This function is automatically called from + gprs_sndcp_comp_entity.c when a new header compression + entity is created by gprs_sndcp.c */ + + if ((comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + && (comp_entity->algo == RFC_1144)) { + comp_entity->status = + slhc_init(comp_field->rfc1144_params->s01 + 1, + comp_field->rfc1144_params->s01 + 1); + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression initalized.\n"); + return 0; + } + + /* Just in case someone tries to initalize an unknown or unsupported + header compresson. Since everything is checked during the SNDCP + negotiation process, this should never happen! */ + LOGP(DSNDCP, LOGL_ERROR, + "Unknown or unsupported header compression type requested for initalization, could not initalize...\n"); + return -EINVAL; + +} + + +/* Terminate header compression */ +void gprs_sndcp_hdrcomp_term(struct gprs_sndcp_comp_entity *comp_entity) +{ + /* Note: This function is automatically called from + gprs_sndcp_comp_entity.c when a header compression + entity is deleted by gprs_sndcp.c */ + + if ((comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + && (comp_entity->algo == RFC_1144)) { + if (comp_entity->status) { + slhc_free((struct slcompress *) comp_entity-> + status); + comp_entity->status = NULL; + } + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression terminated.\n"); + return; + } + + /* Just in case someone tries to initalize an unknown or unsupported + header compresson. Since everything is checked during the SNDCP + negotiation process, this should never happen! */ + LOGP(DSNDCP, LOGL_ERROR, + "Unknown or unsupported header compression type requested for termiation, could not initalize...\n"); +} + + +/* Display compressor status */ +static void gprs_sndcp_hdrcomp_rfc1144_stat(struct slcompress *comp) +{ + slhc_i_status(comp); + slhc_o_status(comp); +} + + +/* Compress a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_hdrcomp_rfc1144_compress(struct slcompress *comp, + uint8_t * packet, + int packet_len, + int *pcomp_index) +{ + uint8_t *packet_compressed; + uint8_t *packet_compressed_ptr; /* Not used */ + int packet_compressed_len; + + /* Reserve some space for to store the compression result */ + packet_compressed = talloc_zero_size(NULL, packet_len); + + /* Run compressor */ + memcpy(packet_compressed, packet, packet_len); + packet_compressed_len = + slhc_compress(comp, packet, packet_len, + (uint8_t *) packet_compressed, + &packet_compressed_ptr, 0); + + /* Copy back compression result */ + memcpy(packet, packet_compressed, packet_len); + talloc_free(packet_compressed); + + /* Generate pcomp_index */ + if ((packet[0] & SL_TYPE_COMPRESSED_TCP) == SL_TYPE_COMPRESSED_TCP) { + *pcomp_index = 2; + /* Remove tag for compressed TCP, because the packet + type is already define by pcomp */ + // packet[0] &= 0x7F; + } else if ((packet[0] & SL_TYPE_UNCOMPRESSED_TCP) == + SL_TYPE_UNCOMPRESSED_TCP) { + *pcomp_index = 1; + + /* Remove tag for uncompressed TCP, because the + packet type is already define by pcomp */ + packet[0] &= 0x4F; + } else + *pcomp_index = 0; + + return packet_compressed_len; +} + +/* Expand a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_hdrcomp_rfc1144_expand(struct slcompress *comp, + uint8_t * packet, + int packet_len, + int pcomp_index) +{ + int packet_decompressed_len; + int type = -1; + + /* Note: this function should never be called with pcomp_index=0, + since this condition is already filtered + out by gprs_sndcp_hdrcomp_expand() */ + + /* Determine the packet type by the PCOMP index */ + switch (pcomp_index) { + case 1: + type = SL_TYPE_UNCOMPRESSED_TCP; + break; + case 2: + type = SL_TYPE_COMPRESSED_TCP; + break; + } + + /* Restore the original version nibble on + marked uncompressed packets */ + if (type == SL_TYPE_UNCOMPRESSED_TCP) { + LOGP(DSNDCP, LOGL_INFO, + "Uncompressed rfc1144 packet received...\n"); + + + /* Just in case the phone tags uncompressed tcp-packets + (normally this is handled by pcomp so there is + no need for tagging the packets) */ + packet[0] &= 0x4F; + packet_decompressed_len = + slhc_remember(comp, packet, packet_len); + return packet_decompressed_len; + } + + /* Uncompress compressed packets */ + else if (type == SL_TYPE_COMPRESSED_TCP) { + LOGP(DSNDCP, LOGL_INFO, + "Compressed rfc1144 packet received...\n"); + packet_decompressed_len = + slhc_uncompress(comp, packet, packet_len); + return packet_decompressed_len; + } + + + /* Regular or unknown packets will not be touched */ + return packet_len; +} + + +/* Expand header compressed packet */ +int gprs_sndcp_hdrcomp_expand(uint8_t * packet, int packet_len, int pcomp, + struct llist_head *comp_entities) +{ + int rc; + int pcomp_index = 0; + struct gprs_sndcp_comp_entity *comp_entity; + + /* Skip on pcomp=0 */ + if (pcomp == 0) { + LOGP(DSNDCP, LOGL_INFO, + "Uncompressed packet received (pcomp=0), skipping compression...\n"); + return packet_len; + } + + /* Find out which compression entity handles the packet */ + comp_entity = + gprs_sndcp_comp_entity_find_by_comp(comp_entities, pcomp); + + /* Skip compression if no suitable compression entity can be found! */ + if (comp_entity == NULL) { + LOGP(DSNDCP, LOGL_ERROR, + "Compressed packet received (pcomp=%i) but no suitable compression entity found, skipping compression...\n", + pcomp); + return packet_len; + } + + /* Find pcomp_index */ + pcomp_index = + gprs_sndcp_comp_entity_find_comp_index_by_comp(comp_entity, + pcomp); + +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST == 1 + /* Test mode */ + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_expand(): testing compression...!\n"); + rc = gprs_sndcp_hdrcomp_test_ind(packet, packet_len); +#else + /* Normal operation: */ + rc = gprs_sndcp_hdrcomp_rfc1144_expand((struct slcompress *) + comp_entity->status, packet, + packet_len, pcomp_index); + gprs_sndcp_hdrcomp_rfc1144_stat((struct slcompress *) comp_entity-> + status); +#endif + + LOGP(DSNDCP, LOGL_DEBUG, + "Header expansion done, old length=%i, new length=%i, pcomp=%i, pcomp_index=%i\n", + packet_len, rc, pcomp, pcomp_index); + return rc; +} + + +/* Expand header compressed packet */ +int gprs_sndcp_hdrcomp_compress(uint8_t * packet, int packet_len, + int *pcomp, + struct llist_head *comp_entities, + int nsapi) +{ + int rc; + int pcomp_index = 0; + struct gprs_sndcp_comp_entity *comp_entity; + + /* Find out which compression entity handles the packet */ + comp_entity = + gprs_sndcp_comp_entity_find_by_nsapi(comp_entities, nsapi); + + /* Skip compression if no suitable compression entity can be found! */ + if (comp_entity == NULL) { + LOGP(DSNDCP, LOGL_INFO, + "No suitable compression entity found for nsapi %i, skipping compression...\n", + nsapi); + *pcomp = 0; + return packet_len; + } +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST == 1 + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_expand(): testing compression...!\n"); + rc = gprs_sndcp_hdrcomp_test_req(packet, packet_len); + *pcomp = 0; + return rc; +#else + /* Normal operation: */ + rc = gprs_sndcp_hdrcomp_rfc1144_compress((struct slcompress *) + comp_entity->status, + packet, packet_len, + &pcomp_index); + gprs_sndcp_hdrcomp_rfc1144_stat((struct slcompress *) comp_entity-> + status); +#endif + + /* Find pcomp value */ + *pcomp = + gprs_sndcp_comp_entity_find_comp_by_comp_index(comp_entity, + pcomp_index); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header compression done, old length=%i, new length=%i, pcomp=%i, pcomp_index=%i\n", + packet_len, rc, *pcomp, pcomp_index); + return rc; +} + + + + + + + +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST == 1 + +/* + * This is a test implementation to make sure the rfc1144 compression + * implementation works as expected. All data is first compressed and + * decompressed on both directions. + */ + +/* FIXME: FOR EXPERIMENTATION ONLY! REMOVE AS SOON AS POSSIBLE */ +static uint16_t header_checksum(uint8_t * iph, unsigned int ihl) +{ + int i; + uint16_t temp; + uint32_t accumulator = 0xFFFF; + + for (i = 0; i < ihl * 2; i++) { + temp = ((*iph) << 8) & 0xFF00; + iph++; + temp |= (*iph) & 0xFF; + iph++; + + accumulator += temp; + if (accumulator > 0xFFFF) { + accumulator++; + accumulator &= 0xFFFF; + } + } + + return (uint16_t) (htons(~accumulator) & 0xFFFF); +} + +/* Check packet integrity */ +static int gprs_sndcp_hdrcomp_test_check_packet(uint8_t * packet, + uint8_t * packet_backup, + int packet_len, + int + packet_len_uncompressed) +{ + uint16_t checksum; + + if (packet_len != packet_len_uncompressed) { + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): Error: Packet length mismatch!\n"); +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST_EXITONERR == 1 + exit(1); +#endif + return -1; + } + + /* Check packet integrety */ + if (memcmp(packet, packet_backup, packet_len)) { + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): Warning: Packet content!\n"); + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): %s\n", + osmo_hexdump_nospc(packet_backup, 80)); + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): %s\n", + osmo_hexdump_nospc(packet, 80)); + + checksum = header_checksum(packet, 5); + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): %04x\n", + checksum); + + if (checksum == 0x0000) { + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): Checksum looks good!\n"); + + if (memcmp + (packet + 20, packet_backup + 20, + packet_len - 20)) + test_errors++; + else + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): Packet looks also good!\n"); + } else { + test_errors++; +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST_EXITONERR == 1 + exit(1); +#endif + return -1; + } + } + + return 0; +} + +/* FIXME: FOR EXPERIMENTATION ONLY! REMOVE AS SOON AS POSSIBLE */ +static int gprs_sndcp_hdrcomp_test_ind(uint8_t * packet, int packet_len) +{ + int packet_len_compressed; + int packet_len_uncompressed; + int pcomp; + uint8_t *packet_backup; + + if (test_compression_state_tx == NULL) + test_compression_state_tx = slhc_init(8, 8); + if (test_compression_state_rx == NULL) + test_compression_state_rx = slhc_init(8, 8); + + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): packet_len=%i\n", packet_len); + packet_backup = talloc_zero_size(NULL, packet_len); + memcpy(packet_backup, packet, packet_len); + + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): IND: %s\n", + osmo_hexdump_nospc(packet, packet_len)); + packet_len_compressed = + gprs_sndcp_hdrcomp_rfc1144_compress(test_compression_state_rx, + packet, packet_len, + &pcomp); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): IND (COMP): %s\n", + osmo_hexdump_nospc(packet, packet_len_compressed)); + packet_len_uncompressed = + gprs_sndcp_hdrcomp_rfc1144_expand(test_compression_state_tx, + packet, + packet_len_compressed, + pcomp); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): IND (DECOMP): %s\n", + osmo_hexdump_nospc(packet, packet_len_uncompressed)); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): packet_len=%i packet_len_compressed=%i packet_len_uncompressed=%i\n", + packet_len, packet_len_compressed, packet_len_uncompressed); + + gprs_sndcp_hdrcomp_test_check_packet(packet, packet_backup, + packet_len, + packet_len_uncompressed); + talloc_free(packet_backup); + gprs_sndcp_hdrcomp_rfc1144_stat(test_compression_state_rx); + gprs_sndcp_hdrcomp_rfc1144_stat(test_compression_state_tx); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): Test errors: %i\n", + test_errors); + return packet_len; +} + +/* FIXME: FOR EXPERIMENTATION ONLY! REMOVE AS SOON AS POSSIBLE */ +static int gprs_sndcp_hdrcomp_test_req(uint8_t * packet, int packet_len) +{ + int packet_len_compressed; + int packet_len_uncompressed; + int pcomp; + uint8_t *packet_backup; + + if (test_compression_state_tx == NULL) + test_compression_state_tx = slhc_init(8, 8); + if (test_compression_state_rx == NULL) + test_compression_state_rx = slhc_init(8, 8); + + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_req(): packet_len=%i\n", packet_len); + packet_backup = talloc_zero_size(NULL, packet_len); + memcpy(packet_backup, packet, packet_len); + + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_req(): REQ: %s\n", + osmo_hexdump_nospc(packet, packet_len)); + packet_len_compressed = + gprs_sndcp_hdrcomp_rfc1144_compress(test_compression_state_tx, + packet, packet_len, + &pcomp); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_req(): REQ (COMP): %s\n", + osmo_hexdump_nospc(packet, packet_len_compressed)); + packet_len_uncompressed = + gprs_sndcp_hdrcomp_rfc1144_expand(test_compression_state_rx, + packet, + packet_len_compressed, + pcomp); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_req(): REQ (DECOMP): %s\n", + osmo_hexdump_nospc(packet, packet_len_uncompressed)); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_req(): packet_len=%i packet_len_compressed=%i packet_len_uncompressed=%i\n", + packet_len, packet_len_compressed, packet_len_uncompressed); + + gprs_sndcp_hdrcomp_test_check_packet(packet, packet_backup, + packet_len, + packet_len_uncompressed); + talloc_free(packet_backup); + gprs_sndcp_hdrcomp_rfc1144_stat(test_compression_state_rx); + gprs_sndcp_hdrcomp_rfc1144_stat(test_compression_state_tx); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): Test errors: %i\n", + test_errors); + return packet_len; +} + +#endif -- To view, visit https://gerrit.osmocom.org/642 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter From gerrit-no-reply at lists.osmocom.org Wed Aug 3 16:43:12 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Wed, 3 Aug 2016 16:43:12 +0000 Subject: [PATCH] openbsc[master]: Added llc-xid encoder / decoder In-Reply-To: References: Message-ID: Hello Harald Welte, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/638 to look at the new patch set (#3). Added llc-xid encoder / decoder The lle-xid encoder/decoder is needed to encode and decode llc xid parameter messages. We need this to exchange sndcp-parameters (SNDCP-XID) and also simple parameters such as encryption IOVs Change-Id: Ia06e4cb08bf9b48c2a4682606d1b1a91d19a9d37 --- M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_llc_xid.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_llc_xid.c A openbsc/src/gprs/gprs_sndcp_comp_entity.c 5 files changed, 678 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/38/638/3 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 9ef8a15..9e8c554 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,7 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_sndcp.h slhc.h + gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_llc_xid.h b/openbsc/include/openbsc/gprs_llc_xid.h new file mode 100644 index 0000000..a4104ec --- /dev/null +++ b/openbsc/include/openbsc/gprs_llc_xid.h @@ -0,0 +1,63 @@ +/* GPRS LLC XID field encoding/decoding as per 3GPP TS 04.64 */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_LLC_XID_H +#define _GPRS_LLC_XID_H + +#include +#include + +/* TS 101 351 6.4.1.6 Exchange Identification (XID) + command/response parameter field */ +struct gprs_llc_xid_field { + struct llist_head list; + uint8_t type; /* See also Table 6: LLC layer parameter + negotiation */ + uint8_t *data; /* Payload data (octets) */ + unsigned int data_len; /* Payload length */ +}; + +/* Transform a list with XID fields into a XID message (dst) */ +int gprs_llc_compile_xid(const struct llist_head *xid_fields, uint8_t *dst, + int bytes_maxlen); + +/* Transform a XID message (dst) into a list of XID fields */ +int gprs_llc_parse_xid(struct llist_head *xid_fields, const uint8_t *src, + int bytes_len); + +/* Free llist with xid fields */ +void gprs_llc_free_xid(struct llist_head *xid_fields); + +/* Create a duplicate of an XID-Field */ +struct gprs_llc_xid_field *gprs_llc_duplicate_xid_field(const struct + gprs_llc_xid_field + *xid_field); + +/* Copy an llist with xid fields */ +void gprs_llc_copy_xid(struct llist_head *xid_fields_copy, + const struct llist_head *xid_fields_orig); + +/* Dump a list with XID fields (Debug) */ +void gprs_llc_dump_xid_fields(const struct llist_head *xid_fields, + unsigned int logl); + +#endif diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index a118a19..b3a5137 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -23,7 +23,8 @@ osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \ slhc.c \ sgsn_main.c sgsn_vty.c sgsn_libgtp.c \ - gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c crc24.c \ + gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c \ + gprs_llc_xid.c crc24.c \ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ diff --git a/openbsc/src/gprs/gprs_llc_xid.c b/openbsc/src/gprs/gprs_llc_xid.c new file mode 100644 index 0000000..e2ec163 --- /dev/null +++ b/openbsc/src/gprs/gprs_llc_xid.c @@ -0,0 +1,281 @@ +/* GPRS LLC XID field encoding/decoding as per 3GPP TS 04.64 */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +/* Parse XID parameter field */ +static int +decode_xid_field(const uint8_t *src, uint8_t src_len, + struct gprs_llc_xid_field *xid_field) +{ + uint8_t xl; + uint8_t type; + uint8_t len; + int src_counter = 0; + + /* Exit immediately if it is clear that no + parseable data is present */ + if ((src_len < 1) || !src) + return -EINVAL; + + /* Exit immediately if no result can be stored */ + if (!xid_field) + return -EINVAL; + + /* Extract header info */ + xl = (*src >> 7) & 1; + type = (*src >> 2) & 0x1F; + + /* Extract length field */ + len = (*src) & 0x3; + src++; + src_counter++; + if (xl) { + if (src_len < 2) + return -EINVAL; + len = (len << 6) & 0xC0; + len |= ((*src) >> 2) & 0x3F; + src++; + src_counter++; + } + + /* Fill out struct */ + xid_field->type = type; + xid_field->data_len = len; + if (len > 0) { + if (src_len < src_counter + len) + return -EINVAL; + xid_field->data = + talloc_zero_size(NULL, xid_field->data_len); + memcpy(xid_field->data, src, xid_field->data_len); + } else + xid_field->data = NULL; + + /* Return consumed length */ + return src_counter + len; +} + + +/* Encode XID parameter field */ +static int +encode_xid_field(uint8_t *dst, int dst_maxlen, + const struct gprs_llc_xid_field *xid_field) +{ + int xl = 0; + + /* Exit immediately if no source struct is available */ + if (!xid_field) + return -EINVAL; + + /* When the length does not fit into 2 bits, + we need extended length fields */ + if (xid_field->data_len > 3) + xl = 1; + + /* Exit immediately if it is clear that no + encoding result can be stored */ + if (dst_maxlen < xid_field->data_len + 1 + xl) + return -EINVAL; + + /* There are only 5 bits reserved for the type, exit on exceed */ + if (xid_field->type > 31) + return -EINVAL; + + /* Encode header */ + memset(dst, 0, dst_maxlen); + if (xl) + dst[0] |= 0x80; + dst[0] |= (((xid_field->type) & 0x1F) << 2); + + if (xl) { + dst[0] |= (((xid_field->data_len) >> 6) & 0x03); + dst[1] = ((xid_field->data_len) << 2) & 0xFC; + } else + dst[0] |= ((xid_field->data_len) & 0x03); + + /* Append payload data */ + if ((xid_field->data) && (xid_field->data_len)) + memcpy(dst + 1 + xl, xid_field->data, + xid_field->data_len); + + /* Return generated length */ + return xid_field->data_len + 1 + xl; +} + + +/* Transform a list with XID fields into a XID message (dst) */ +int +gprs_llc_compile_xid(const struct llist_head *xid_fields, uint8_t *dst, + int dst_maxlen) +{ + struct gprs_llc_xid_field *xid_field; + int rc; + int byte_counter = 0; + + llist_for_each_entry(xid_field, xid_fields, list) { + /* Encode XID-Field */ + rc = encode_xid_field(dst, dst_maxlen, xid_field); + if (rc < 0) + return -EINVAL; + + /* Advance pointer and lower maxlen for the + next encoding round */ + dst += rc; + byte_counter += rc; + dst_maxlen -= rc; + } + + /* Return generated length */ + return byte_counter; +} + + +/* Transform a XID message (dst) into a list of XID fields */ +int +gprs_llc_parse_xid(struct llist_head *xid_fields, const uint8_t *src, + int src_len) +{ + struct gprs_llc_xid_field *xid_field; + int rc; + int max_loops = src_len; + + while (1) { + /* Bail in case decode_xid_field() constantly returns zero */ + if (max_loops <= 0) { + gprs_llc_free_xid(xid_fields); + return -EINVAL; + } + + /* Decode XID field */ + xid_field = talloc_zero(NULL, struct gprs_llc_xid_field); + rc = decode_xid_field(src, src_len, xid_field); + + /* Immediately stop on error */ + if (rc < 0) { + gprs_llc_free_xid(xid_fields); + return -EINVAL; + } + + /* Add parsed XID field to list */ + llist_add(&xid_field->list, xid_fields); + + /* Advance pointer and lower dst_len for the next + decoding round */ + src += rc; + src_len -= rc; + + /* We are (scuccessfully) done when no further byes are left */ + if (src_len == 0) + return 0; + + max_loops--; + } +} + + +/* Free llist with xid fields */ +void gprs_llc_free_xid(struct llist_head *xid_fields) +{ + struct gprs_llc_xid_field *xid_field; + struct llist_head *lh, *lh2; + + if (xid_fields) { + llist_for_each_entry(xid_field, xid_fields, list) { + if ((xid_field->data) && (xid_field->data_len)) + talloc_free(xid_field->data); + } + + llist_for_each_safe(lh, lh2, xid_fields) { + llist_del(lh); + talloc_free(lh); + } + } +} + + +/* Create a duplicate of an XID-Field */ +struct gprs_llc_xid_field *gprs_llc_duplicate_xid_field(const struct + gprs_llc_xid_field + *xid_field) +{ + struct gprs_llc_xid_field *duplicate_of_xid_field; + + /* Create a copy of the XID field in memory */ + duplicate_of_xid_field = + talloc_zero(NULL, struct gprs_llc_xid_field); + memcpy(duplicate_of_xid_field, xid_field, + sizeof(struct gprs_llc_xid_field)); + duplicate_of_xid_field->data = + talloc_zero_size(NULL, xid_field->data_len); + memcpy(duplicate_of_xid_field->data, xid_field->data, + xid_field->data_len); + + /* Wipeout all llist information in the duplicate (just to be sure) */ + memset(&duplicate_of_xid_field->list, 0, + sizeof(struct llist_head)); + + return duplicate_of_xid_field; +} + +/* Copy an llist with xid fields */ +void gprs_llc_copy_xid(struct llist_head *xid_fields_copy, + const struct llist_head *xid_fields_orig) +{ + struct gprs_llc_xid_field *xid_field; + + /* Make sure that the target list is empty */ + gprs_llc_free_xid(xid_fields_copy); + + /* Create duplicates and add them to the target list */ + llist_for_each_entry(xid_field, xid_fields_orig, list) { + llist_add(&gprs_llc_duplicate_xid_field(xid_field)->list, xid_fields_copy); + } +} + +/* Dump a list with XID fields (Debug) */ +void gprs_llc_dump_xid_fields(const struct llist_head *xid_fields, unsigned int logl) +{ + struct gprs_llc_xid_field *xid_field; + + llist_for_each_entry(xid_field, xid_fields, list) { + LOGP(DSNDCP, logl, + "XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + osmo_hexdump_nospc(xid_field->data, + xid_field->data_len)); + } +} diff --git a/openbsc/src/gprs/gprs_sndcp_comp_entity.c b/openbsc/src/gprs/gprs_sndcp_comp_entity.c new file mode 100644 index 0000000..095a32a --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_comp_entity.c @@ -0,0 +1,331 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +/* Create a new compression entity from a XID-Field */ +static struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_create (struct gprs_sndcp_comp_field *comp_field) +{ + struct gprs_sndcp_comp_entity *comp_entity; + comp_entity = talloc_zero (NULL, struct gprs_sndcp_comp_entity); + + /* Copy relevant information from the SNDCP-XID field */ + comp_entity->entity = comp_field->entity; + comp_entity->comp_len = comp_field->comp_len; + memcpy (comp_entity->comp, comp_field->comp, + comp_field->comp_len * sizeof (int)); + + if (comp_field->rfc1144_params) { + comp_entity->nsapi_len = + comp_field->rfc1144_params->nsapi_len; + memcpy (comp_entity->nsapi, + comp_field->rfc1144_params->nsapi, + comp_entity->nsapi_len * sizeof (int)); + } + else if (comp_field->rfc2507_params) { + comp_entity->nsapi_len = + comp_field->rfc2507_params->nsapi_len; + memcpy (comp_entity->nsapi, + comp_field->rfc2507_params->nsapi, + comp_entity->nsapi_len * sizeof (int)); + } + else if (comp_field->rohc_params) { + comp_entity->nsapi_len = comp_field->rohc_params->nsapi_len; + memcpy (comp_entity->nsapi, comp_field->rohc_params->nsapi, + comp_entity->nsapi_len * sizeof (int)); + } + else if (comp_field->v42bis_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy (comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + comp_entity->nsapi_len * sizeof (int)); + } + else if (comp_field->v44_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy (comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + comp_entity->nsapi_len * sizeof (int)); + } + else { + talloc_free (comp_entity); + LOGP (DSNDCP, LOGL_ERROR, + "Comp field contained invalid parameters, compression entity not created!\n"); + return NULL; + } + + comp_entity->algo = comp_field->algo; + comp_entity->state = NULL; + + /* Determine of which class our compression entity will be + (Protocol or Data compresson ?) */ + comp_entity->compclass = + gprs_sndcp_get_compression_class (comp_field); + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + if (gprs_sndcp_hdrcomp_init (comp_entity, comp_field) == 0) + LOGP (DSNDCP, LOGL_INFO, + "New header compression entity (%i) created.\n", + comp_entity->entity); + else { + talloc_free (comp_entity); + LOGP (DSNDCP, LOGL_ERROR, + "Header compression entity (%i) creation failed!\n", + comp_entity->entity); + return NULL; + } + } + else + LOGP (DSNDCP, LOGL_INFO, + "New data compression entity (%i) created.\n", + comp_entity->entity); + + return comp_entity; +} + +/* Free a list with compression entities */ +void +gprs_sndcp_comp_entities_free (struct llist_head *comp_entities) +{ + if (comp_entities) { + struct gprs_sndcp_comp_entity *comp_entity; + + llist_for_each_entry (comp_entity, comp_entities, list) { + /* Free compression entity */ + if (comp_entity->compclass == + SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP (DSNDCP, LOGL_INFO, + "Deleting (free) header compression entity %i ...\n", + comp_entity->entity); + gprs_sndcp_hdrcomp_term (comp_entity); + } + else + LOGP (DSNDCP, LOGL_INFO, + "Deleting (free) data compression entity %i ...\n", + comp_entity->entity); + + talloc_free (comp_entity); + } + + } +} + +/* Delete a compression entity */ +void +gprs_sndcp_comp_entities_delete (struct llist_head *comp_entities, int entity) +{ + struct gprs_sndcp_comp_entity *comp_entity; + struct gprs_sndcp_comp_entity *comp_entity_to_delete = NULL; + + if (comp_entities) { + + llist_for_each_entry (comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) + comp_entity_to_delete = comp_entity; + } + + if (comp_entity_to_delete) { + if (comp_entity_to_delete->compclass == + SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP (DSNDCP, LOGL_INFO, + "Deleting header compression entity %i ...\n", + comp_entity_to_delete->entity); + gprs_sndcp_hdrcomp_term + (comp_entity_to_delete); + } + else + LOGP (DSNDCP, LOGL_INFO, + "Deleting data compression entity %i ...\n", + comp_entity_to_delete->entity); + + /* Delete compression entity */ + llist_del (&comp_entity_to_delete->list); + talloc_free (comp_entity_to_delete); + } + } +} + +/* Create and Add a new compression entity +(returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entities_add (struct + llist_head + *comp_entities, struct + gprs_sndcp_comp_field *comp_field) +{ + struct gprs_sndcp_comp_entity *comp_entity; + + /* Just to be sure, if the entity is already in + the list it will be deleted now */ + gprs_sndcp_comp_entities_delete (comp_entities, comp_field->entity); + + /* Create and add a new entity to the list */ + comp_entity = gprs_sndcp_comp_entity_create (comp_field); + + if (comp_entity) { + llist_add (&comp_entity->list, comp_entities); + return comp_entity; + } + + return NULL; +} + +/* Find compression entity by its entity number */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_entity (struct + llist_head *comp_entities, int entity) +{ + struct gprs_sndcp_comp_entity *comp_entity; + + if (comp_entities) { + llist_for_each_entry (comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) + return comp_entity; + } + } + + LOGP (DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given entity number %i.\n", + entity); + return NULL; +} + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_comp (struct + llist_head *comp_entities, int comp) +{ + struct gprs_sndcp_comp_entity *comp_entity; + int i; + + if (comp_entities) { + llist_for_each_entry (comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return comp_entity; + } + } + } + + LOGP (DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given pcomp/dcomp value %i.\n", + comp); + return NULL; +} + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_nsapi (struct + llist_head *comp_entities, int nsapi) +{ + struct gprs_sndcp_comp_entity *comp_entity; + int i; + + if (comp_entities) { + llist_for_each_entry (comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->nsapi_len; i++) { + if (comp_entity->nsapi[i] == nsapi) + return comp_entity; + } + } + + LOGP (DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given nsapi value %i\n", + nsapi); + return NULL; + } + + LOGP (DSNDCP, LOGL_ERROR, + "Compression entity list contained null-pointer!\n"); + return NULL; +} + +/* Find a comp_index for a given pcomp/dcomp value */ +int +gprs_sndcp_comp_entity_find_comp_index_by_comp (struct + gprs_sndcp_comp_entity + *comp_entity, int comp) +{ + int i; + + if (comp_entity) { + /* A pcomp/dcomp field set to zero always disables + all sort of compression and is assigned fix. So we + just return zero in this case */ + if (comp == 0) + return 0; + + /* Look in the pcomp/dcomp list for the index */ + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return i + 1; + } + + LOGP (DSNDCP, LOGL_ERROR, + "Could not find a matching comp_index for given pcomp/dcomp value %i\n", + comp); + return 0; + } + + LOGP (DSNDCP, LOGL_ERROR, + "Compression entity contained null-pointer!\n"); + return 0; +} + +/* Find a pcomp/dcomp value for a given comp_index */ +int +gprs_sndcp_comp_entity_find_comp_by_comp_index (struct + gprs_sndcp_comp_entity + *comp_entity, int comp_index) +{ + if (comp_entity) { + /* A comp_index of zero translates to zero right away. */ + if (comp_index == 0) + return 0; + + if (comp_index > comp_entity->comp_len) { + LOGP (DSNDCP, LOGL_ERROR, + "Could not find a matching pcomp/dcomp value for given comp_index value %i.\n", + comp_index); + return 0; + } + + /* Look in the pcomp/dcomp list for the comp_index */ + return comp_entity->comp[comp_index - 1]; + } + + LOGP (DSNDCP, LOGL_ERROR, + "Compression entity contained null-pointer!\n"); + return 0; +} -- To view, visit https://gerrit.osmocom.org/638 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia06e4cb08bf9b48c2a4682606d1b1a91d19a9d37 Gerrit-PatchSet: 3 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Thu Aug 4 08:25:19 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Thu, 4 Aug 2016 08:25:19 +0000 Subject: [PATCH] openbsc[master]: Added SNDCP-XID encoder / decoder In-Reply-To: References: Message-ID: Hello Harald Welte, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/641 to look at the new patch set (#3). Added SNDCP-XID encoder / decoder The SNDCP-XID (or layer-3 xid) is used to exchange layer-3 parameters such as compression. The encoder encodes a bytestream that is then sent as regular XID field from LLC. We will need the SNDCP-XID to negotiate the parameters for our upcomming GPRS data and header compression features Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e --- M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_sndcp_xid.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_sndcp_xid.c 4 files changed, 1,971 insertions(+), 3 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/41/641/3 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 9e8c554..b37103f 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,7 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h + gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h gprs_sndcp_xid.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_sndcp_xid.h b/openbsc/include/openbsc/gprs_sndcp_xid.h new file mode 100644 index 0000000..ec14a55 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_xid.h @@ -0,0 +1,220 @@ +#ifndef _GPRS_SNDCP_XID_H +#define _GPRS_SNDCP_XID_H + +#include +#include + +#define CURRENT_SNDCP_VERSION 0 /* See TS 144 065, clause 8 */ +#define MAX_ENTITIES 32 /* TS 144 065 reserves 5 bit for compr. entity num. */ + +/* According to: TS 144 065 6.5.1.1 Format of the protocol control information + compression field (Figure 7) + + TS 144 065 6.6.1.1 Format of the data compression + field (Figure 9) */ + +struct gprs_sndcp_comp_field { + struct llist_head list; + + /* Propose bit (P), see also: 6.5.1.1.2 and 6.6.1.1.2 */ + unsigned int p; + + /* Entity number, see also: 6.5.1.1.3 and 6.6.1.1.3 */ + unsigned int entity; + + /* Algorithm identifier, see also: 6.5.1.1.4 and 6.6.1.1.4 */ + unsigned int algo; + + /* Number of contained PCOMP / DCOMP values */ + unsigned int comp_len; + + /* PCOMP / DCOMP values, see also: 6.5.1.1.5 and 6.6.1.1.5 */ + unsigned int comp[16]; + + /* Note: Only one of the following struct pointers may, + be used unused pointers must be set to NULL! */ + struct gprs_sndcp_hdrcomp_rfc1144_params *rfc1144_params; + struct gprs_sndcp_hdrcomp_rfc2507_params *rfc2507_params; + struct gprs_sndcp_hdrcomp_rohc_params *rohc_params; + struct gprs_sndcp_datacomp_v42bis_params *v42bis_params; + struct gprs_sndcp_datacomp_v44_params *v44_params; +}; + +/* According to: TS 144 065 6.5.1.1.4 Algorithm identifier */ +enum gprs_sndcp_hdr_comp_algo { + RFC_1144 = 0, /* TCP/IP header compression, see also 6.5.2 */ + RFC_2507 = 1, /* TCP/UDP/IP header compression, see also: 6.5.3 */ + ROHC = 2, /* Robust Header Compression, see also 6.5.4 */ +}; + +/* According to: TS 144 065 6.5.1.1.4 Algorithm identifier */ +enum gprs_sndcp_data_comp_algo { + V42BIS = 0, /* V42bis data compression, see also 6.6.2 */ + V44 = 1, /* V44 data compression, see also: 6.6.3 */ +}; + +/* According to: TS 144 065 8 SNDCP XID parameters */ +enum gprs_sndcp_xid_param_types { + SNDCP_XID_VERSION_NUMBER = 0, + SNDCP_XID_DATA_COMPRESSION = 1, /* See also: subclause 6.6.1 */ + SNDCP_XID_PROTOCOL_COMPRESSION = 2, /* See also: subclause 6.5.1 */ +}; + +/* When the propose bit in an SNDCP-XID compression field is set to zero, + the algorithm identifier is stripped. The algoritm parameters are specific + for each algorithms. The following struct is used to pass the information + about the referenced algorithm to the parser. */ +struct gprs_sndcp_hdrcomp_entity_algo_table { + unsigned int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + unsigned int algo; /* see also: 6.5.1.1.4 and 6.6.1.1.4 */ + unsigned int compclass; /* Can be either SNDCP_XID_DATA_COMPRESSION or + SNDCP_XID_PROTOCOL_COMPRESSION */ +}; + + + +/* According to: TS 144 065 6.5.2.1 Parameters (Table 5) */ +struct gprs_sndcp_hdrcomp_rfc1144_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int s01; /* (default 15) */ +}; + +/* According to: TS 144 065 6.5.2.2 Assignment of PCOMP values */ +enum gprs_sndcp_hdrcomp_rfc1144_pcomp { + RFC1144_PCOMP1 = 0, /* Uncompressed TCP */ + RFC1144_PCOMP2 = 1, /* Compressed TCP */ + RFC1144_PCOMP_NUM = 2 /* Number of pcomp values */ +}; + + + +/* According to: TS 144 065 6.5.3.1 Parameters (Table 6) */ +struct gprs_sndcp_hdrcomp_rfc2507_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int f_max_period; /* (default 256) */ + int f_max_time; /* (default 5) */ + int max_header; /* (default 168) */ + int tcp_space; /* (default 15) */ + int non_tcp_space; /* (default 15) */ +}; + +/* According to: TS 144 065 6.5.3.2 Assignment of PCOMP values for RFC2507 */ +enum gprs_sndcp_hdrcomp_rfc2507_pcomp { + RFC2507_PCOMP1 = 0, /* Full Header */ + RFC2507_PCOMP2 = 1, /* Compressed TCP */ + RFC2507_PCOMP3 = 2, /* Compressed TCP non delta */ + RFC2507_PCOMP4 = 3, /* Compressed non TCP */ + RFC2507_PCOMP5 = 4, /* Context state */ + RFC2507_PCOMP_NUM = 5 /* Number of pcomp values */ +}; + + + +/* According to: TS 144 065 6.5.4.1 Parameter (Table 10) */ +struct gprs_sndcp_hdrcomp_rohc_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int max_cid; /* (default 15) */ + int max_header; /* (default 168) */ + unsigned int profile_len; /* (default 1) */ + uint16_t profile[16]; /* (default 0, ROHC uncompressed) */ +}; + +/* According to: TS 144 065 6.5.4.2 Assignment of PCOMP values for ROHC */ +enum gprs_sndcp_hdrcomp_rohc_pcomp { + ROHC_PCOMP1 = 0, /* ROHC small CIDs */ + ROHC_PCOMP2 = 1, /* ROHC large CIDs */ + ROHC_PCOMP_NUM = 2 /* Number of pcomp values */ +}; + +/* ROHC compression profiles, see also: + http://www.iana.org/assignments/rohc-pro-ids/rohc-pro-ids.xhtml */ +enum gprs_sndcp_xid_rohc_profiles { + ROHC_UNCOMPRESSED = 0x0000, /* ROHC uncompressed [RFC5795] */ + ROHC_RTP = 0x0001, /* ROHC RTP [RFC3095] */ + ROHCV2_RTP = 0x0101, /* ROHCv2 RTP [RFC5225] */ + ROHC_UDP = 0x0002, /* ROHC UDP [RFC3095] */ + ROHCv2_UDP = 0x0102, /* ROHCv2 UDP [RFC5225] */ + ROHC_ESP = 0x0003, /* ROHC ESP [RFC3095] */ + ROHCV2_ESP = 0x0103, /* ROHCv2 ESP [RFC5225] */ + ROHC_IP = 0x0004, /* ROHC IP [RFC3843] */ + ROHCV2_IP = 0x0104, /* ROHCv2 IP [RFC5225] */ + ROHC_LLA = 0x0005, /* ROHC LLA [RFC4362] */ + ROHC_LLA_WITH_R_MODE = 0x0105, /* ROHC LLA with R-mode [RFC3408] */ + ROHC_TCP = 0x0006, /* ROHC TCP [RFC6846] */ + ROHC_RTP_UDP_LITE = 0x0007, /* ROHC RTP/UDP-Lite [RFC4019] */ + ROHCV2_RTP_UDP_LITE = 0x0107, /* ROHCv2 RTP/UDP-Lite [RFC5225] */ + ROHC_UDP_LITE = 0x0008, /* ROHC UDP-Lite [RFC4019] */ + ROHCV2_UDP_LITE = 0x0108, /* ROHCv2 UDP-Lite [RFC5225] */ +}; + + + +/* According to: TS 144 065 6.6.2.1 Parameters (Table 7a) */ +struct gprs_sndcp_datacomp_v42bis_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int p0; /* (default 3) */ + int p1; /* (default 2048) */ + int p2; /* (default 20) */ + +}; + +/* According to: ETSI TS 144 065 6.6.2.2 Assignment of DCOMP values */ +enum gprs_sndcp_datacomp_v42bis_dcomp { + V42BIS_DCOMP1 = 0, /* V42bis enabled */ + V42BIS_DCOMP_NUM = 1 /* Number of dcomp values */ +}; + + + +/* According to: TS 144 065 6.6.3.1 Parameters (Table 7c) */ +struct gprs_sndcp_datacomp_v44_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int c0; /* (default 10000000) */ + int p0; /* (default 3) */ + int p1t; /* Refer to subclause 6.6.3.1.4 */ + int p1r; /* Refer to subclause 6.6.3.1.5 */ + int p3t; /* (default 3 x p1t) */ + int p3r; /* (default 3 x p1r) */ +}; + +/* According to: ETSI TS 144 065 6.6.3.2 Assignment of DCOMP values */ +enum gprs_sndcp_datacomp_v44_dcomp { + V44_DCOMP1 = 0, /* Packet method compressed */ + V44_DCOMP2 = 1, /* Multi packet method compressed */ + V44_DCOMP_NUM = 2 /* Number of dcomp values */ +}; + +/* Transform a list with compression fields into an SNDCP-XID message (dst) */ +int gprs_sndcp_compile_xid(const struct llist_head *comp_fields, uint8_t *dst, + unsigned int dst_maxlen); + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +int gprs_sndcp_parse_xid(struct llist_head *comp_fields, const uint8_t *src, + unsigned int dst_len, + struct gprs_sndcp_hdrcomp_entity_algo_table *lt, + unsigned int lt_len); + +/* Free a list with SNDCP-XID fields */ +void gprs_sndcp_free_comp_fields(struct llist_head *comp_fields); + +/* Find out to which compression class the specified comp-field belongs + (header compression or data compression?) */ +int gprs_sndcp_get_compression_class(const struct gprs_sndcp_comp_field + *comp_field); + +/* Fill up lookutable from a list with comression entitiy fields */ +int gprs_sndcp_fill_table(struct gprs_sndcp_hdrcomp_entity_algo_table *lt, + unsigned int lt_len, + const struct llist_head *comp_fields); + +/* Dump a list with SNDCP-XID fields (Debug) */ +void gprs_sndcp_dump_comp_fields(const struct llist_head *comp_fields, + unsigned int logl); + + +#endif diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index b3a5137..67e9943 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -21,7 +21,7 @@ $(OSMO_LIBS) $(LIBCRYPTO_LIBS) -lrt osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \ - slhc.c \ + slhc.c gprs_sndcp_xid.c \ sgsn_main.c sgsn_vty.c sgsn_libgtp.c \ gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c \ gprs_llc_xid.c crc24.c \ @@ -32,7 +32,7 @@ osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ - $(LIBCRYPTO_LIBS) -lrt + $(LIBCRYPTO_LIBS) -lrt -lm osmo_gtphub_SOURCES = gtphub_main.c gtphub.c gtphub_sock.c gtphub_ares.c \ gtphub_vty.c sgsn_ares.c gprs_utils.c diff --git a/openbsc/src/gprs/gprs_sndcp_xid.c b/openbsc/src/gprs/gprs_sndcp_xid.c new file mode 100644 index 0000000..070058c --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_xid.c @@ -0,0 +1,1748 @@ +/* GPRS SNDCP XID field encoding/decoding as per 3GPP TS 144 065 */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +/* + * FUNCTIONS RELATED TO SNDCP-XID ENCODING + */ + +/* Encode applicable sapis (works the same in all three compression schemes) */ +static int encode_hdrcomp_applicable_sapis(uint8_t * dst, + const unsigned int *nsapis, + unsigned int nsapis_len) +{ + /* + * NOTE: Buffer *dst needs offer at 2 bytes + * of space to store the generation results + */ + + uint16_t blob; + unsigned int nsapi; + int i; + + /* Encode applicable SAPIs */ + blob = 0; + for (i = 0; i < nsapis_len; i++) { + nsapi = nsapis[i]; + /* + * Only NSAPI 5 to 15 are applicable for user traffic (PDP- + * contexts). Only for these NSAPIs SNDCP-XID parameters + * can apply. See also ETSI TS 144 065 5.1 Service primitives + */ + if ((nsapi < 5) || (nsapi > 15)) + return -EINVAL; + blob |= (1 << nsapi); + } + + /* Store result */ + *dst = (blob >> 8) & 0xFF; + dst++; + *dst = blob & 0xFF; + + return 2; +} + + +/* + * Encode rfc1144 parameter field + * (see also: ETSI TS 144 065 6.5.2.1, Table 5) + */ +static int encode_hdrcomp_rfc1144_params(uint8_t * dst, + unsigned int dst_maxlen, const struct + gprs_sndcp_hdrcomp_rfc1144_params + *params) +{ + /* + * NOTE: Buffer *dst should offer at least 3 bytes + * of space to store the generation results + */ + + int dst_counter = 0; + int rc; + + /* Exit immediately if no source struct is available */ + if (!params) + return -EINVAL; + + /* Exit immediately if no sufficient memory space is supplied */ + if ((dst_maxlen < 3) || !dst) + return -EINVAL; + + /* + * Exit if number of possible nsapis exceeds valid range + * (Only 11 nsapis possible for PDP-Contexts) + */ + if ((params->nsapi_len < 0) || (params->nsapi_len > 11)) + return -EINVAL; + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_hdrcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode s01 (see also: ETSI TS 144 065 6.5.2.1, Table 5) */ + *dst = params->s01; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + + +/* + * Encode rfc2507 parameter field + * (see also: ETSI TS 144 065 6.5.3.1, Table 6) + */ +static int encode_hdrcomp_rfc2507_params(uint8_t * dst, + unsigned int dst_maxlen, const struct + gprs_sndcp_hdrcomp_rfc2507_params + *params) +{ + /* + * NOTE: Buffer *dst should offer at least 3 bytes + * of space to store the generation results + */ + + int dst_counter = 0; + int rc; + + /* Exit immediately if no source struct is available */ + if (!params) + return -EINVAL; + + /* Exit immediately if no sufficient memory space is supplied */ + if ((dst_maxlen < 9) || !dst) + return -EINVAL; + + /* + * Exit if number of possible nsapis exceeds valid range + * (Only 11 nsapis possible for PDP-Contexts) + */ + if ((params->nsapi_len < 0) || (params->nsapi_len > 11)) + return -EINVAL; + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_hdrcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode F_MAX_PERIOD (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + if ((params->f_max_period < 1) || (params->f_max_period > 65535)) + return -EINVAL; + *dst = (params->f_max_period >> 8) & 0xFF; + dst++; + dst_counter++; + *dst = (params->f_max_period) & 0xFF; + dst++; + dst_counter++; + + /* Encode F_MAX_TIME (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + if ((params->f_max_time < 1) || (params->f_max_time > 255)) + return -EINVAL; + *dst = params->f_max_time; + dst++; + dst_counter++; + + /* Encode MAX_HEADER (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + if ((params->max_header < 60) || (params->max_header > 255)) + return -EINVAL; + *dst = params->max_header; + dst++; + dst_counter++; + + /* Encode TCP_SPACE (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + if ((params->tcp_space < 3) || (params->tcp_space > 255)) + return -EINVAL; + *dst = params->tcp_space; + dst++; + dst_counter++; + + /* Encode NON_TCP_SPACE (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + if ((params->non_tcp_space < 3) || (params->tcp_space > 65535)) + return -EINVAL; + *dst = (params->non_tcp_space >> 8) & 0xFF; + dst++; + dst_counter++; + *dst = (params->non_tcp_space) & 0xFF; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + + +/* + * Encode ROHC parameter field + * (see also: ETSI TS 144 065 6.5.4.1, Table 10) + */ +static int encode_hdrcomp_rohc_params(uint8_t * dst, + unsigned int dst_maxlen, + const struct gprs_sndcp_hdrcomp_rohc_params + *params) +{ + /* + * NOTE: Buffer *dst should offer at least 36 + * (2 * 16 Profiles + 2 * 3 Parameter) bytes + * of memory space to store generation results + */ + + int i; + int dst_counter = 0; + int rc; + + /* Exit immediately if no source struct is available */ + if (!params) + return -EINVAL; + + /* Exit immediately if no sufficient memory space is supplied */ + if ((dst_maxlen < 38) || !dst) + return -EINVAL; + + /* + * Exit if number of possible nsapis exceeds valid range + * (Only 11 nsapis possible for PDP-Contexts) + */ + if ((params->nsapi_len < 0) || (params->nsapi_len > 11)) + return -EINVAL; + + /* + * Exit if number of ROHC profiles exceeds limit + * (ROHC supports only a maximum of 16 different profiles) + */ + if ((params->profile_len < 0) || (params->profile_len > 16)) + return -EINVAL; + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_hdrcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode MAX_CID (see also: ETSI TS 144 065 6.5.4.1, Table 10) */ + if ((params->max_cid < 0) || (params->max_cid > 16383)) + return -EINVAL; + *dst = (params->max_cid >> 8) & 0xFF; + dst++; + *dst = params->max_cid & 0xFF; + dst++; + dst_counter += 2; + + /* Encode MAX_HEADER (see also: ETSI TS 144 065 6.5.4.1, Table 10) */ + if ((params->max_header < 60) || (params->max_header > 255)) + return -EINVAL; + *dst = (params->max_header >> 8) & 0xFF; + dst++; + *dst = params->max_header & 0xFF; + dst++; + dst_counter += 2; + + /* Encode ROHC Profiles (see also: ETSI TS 144 065 6.5.4.1, Table 10) */ + for (i = 0; i < params->profile_len; i++) { + *dst = (params->profile[i] >> 8) & 0xFF; + dst++; + *dst = params->profile[i] & 0xFF; + dst++; + dst_counter += 2; + } + + /* Return generated length */ + return dst_counter; +} + + +/* + * Encode V42bis parameter field + * (see also: ETSI TS 144 065 6.6.2.1, Table 7a) + */ +static int encode_datacomp_v42bis_params(uint8_t * dst, + unsigned int dst_maxlen, const struct + gprs_sndcp_datacomp_v42bis_params + *params) +{ + /* + * NOTE: Buffer *dst should offer at least 6 bytes + * of space to store the generation results + */ + + int dst_counter = 0; + int rc; + + /* Exit immediately if no source struct is available */ + if (!params) + return -EINVAL; + + /* Exit immediately if no sufficient memory space is supplied */ + if ((dst_maxlen < 6) || !dst) + return -EINVAL; + + /* + * Exit if number of possible nsapis exceeds valid range + * (Only 11 nsapis possible for PDP-Contexts) + */ + if ((params->nsapi_len < 0) || (params->nsapi_len > 11)) + return -EINVAL; + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_hdrcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode P0 (see also: ETSI TS 144 065 6.6.2.1, Table 7a) */ + if ((params->p0 < 0) || (params->p0 > 3)) + return -EINVAL; + *dst = params->p0 & 0x03; + dst++; + dst_counter++; + + /* Encode P1 (see also: ETSI TS 144 065 6.6.2.1, Table 7a) */ + if ((params->p1 < 512) || (params->p1 > 65535)) + return -EINVAL; + *dst = (params->p1 >> 8) & 0xFF; + dst++; + *dst = params->p1 & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P2 (see also: ETSI TS 144 065 6.6.2.1, Table 7a) */ + if ((params->p2 < 6) || (params->p2 > 250)) + return -EINVAL; + *dst = params->p2; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + + +/* + * Encode V44 parameter field + * (see also: ETSI TS 144 065 6.6.3.1, Table 7c) + */ +static int encode_datacomp_v44_params(uint8_t * dst, + unsigned int dst_maxlen, + const struct gprs_sndcp_datacomp_v44_params + *params) +{ + /* + * NOTE: Buffer *dst should offer at least 12 bytes + * of space to store the generation results + */ + + int dst_counter = 0; + int rc; + + /* Exit immediately if no source struct is available */ + if (!params) + return -EINVAL; + + /* Exit immediately if no sufficient memory space is supplied */ + if ((dst_maxlen < 12) || !dst) + return -EINVAL; + + /* + * Exit if number of possible nsapis exceeds valid range + * (Only 11 nsapis possible for PDP-Contexts) + */ + if ((params->nsapi_len < 0) || (params->nsapi_len > 11)) + return -EINVAL; + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_hdrcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode C0 (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + if ((params->c0 == 0x80) || (params->c0 == 0xC0)) { + *dst = params->c0 & 0xC0; + dst++; + dst_counter++; + } else + return -EINVAL; + + /* Encode P0 (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + if ((params->p0 < 0) || (params->p0 > 3)) + return -EINVAL; + *dst = params->p0 & 0x03; + dst++; + dst_counter++; + + /* Encode P1T (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + if ((params->p1t < 256) || (params->p1t > 65535)) + return -EINVAL; + *dst = (params->p1t >> 8) & 0xFF; + dst++; + *dst = params->p1t & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P1R (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + if ((params->p1r < 256) || (params->p1r > 65535)) + return -EINVAL; + *dst = (params->p1r >> 8) & 0xFF; + dst++; + *dst = params->p1r & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P3T (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + if ((params->p3t < 0) || (params->p3t > 65535)) + return -EINVAL; + if (params->p3t < 2 * params->p1t) + return -EINVAL; + *dst = (params->p3t >> 8) & 0xFF; + dst++; + *dst = params->p3t & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P3R (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + if ((params->p3r < 0) || (params->p3r > 65535)) + return -EINVAL; + if (params->p3r < 2 * params->p1r) + return -EINVAL; + *dst = (params->p3r >> 8) & 0xFF; + dst++; + *dst = params->p3r & 0xFF; + dst++; + dst_counter += 2; + + /* Return generated length */ + return dst_counter; +} + + +/* + * Encode data or protocol control information compression field + * (see also: ETSI TS 144 065 6.6.1.1, Figure 9 and + * ETSI TS 144 065 6.5.1.1, Figure 7) + */ +static int encode_comp_field(uint8_t * dst, unsigned int dst_maxlen, + const struct gprs_sndcp_comp_field *comp_field) +{ + int dst_counter = 0; + int len; + int expected_length; + int i; + + uint8_t payload_bytes[256]; + int payload_bytes_len = -1; + + /* If possible, try do encode payload bytes first */ + if (comp_field->rfc1144_params) + payload_bytes_len = + encode_hdrcomp_rfc1144_params(payload_bytes, + sizeof(payload_bytes), + comp_field-> + rfc1144_params); + else if (comp_field->rfc2507_params) + payload_bytes_len = + encode_hdrcomp_rfc2507_params(payload_bytes, + sizeof(payload_bytes), + comp_field-> + rfc2507_params); + else if (comp_field->rohc_params) + payload_bytes_len = + encode_hdrcomp_rohc_params(payload_bytes, + sizeof(payload_bytes), + comp_field->rohc_params); + else if (comp_field->v42bis_params) + payload_bytes_len = + encode_datacomp_v42bis_params(payload_bytes, + sizeof(payload_bytes), + comp_field-> + v42bis_params); + else if (comp_field->v44_params) + payload_bytes_len = + encode_datacomp_v44_params(payload_bytes, + sizeof(payload_bytes), + comp_field->v44_params); + else + return -EINVAL; + + /* Exit immediately if payload byte generation failed */ + if (payload_bytes_len < 0) + return -EINVAL; + + /* Exit immediately if no source struct is available */ + if (!comp_field) + return -EINVAL; + + /* Check if comp_len is within bounds */ + if ((comp_field->comp_len < 0) || (comp_field->comp_len > 16)) + return -EINVAL; + + /* Calculate length field of the data block */ + if (comp_field->p) { + len = + payload_bytes_len + + ceil((double) (comp_field->comp_len) / 2.0); + expected_length = len + 3; + } else { + len = payload_bytes_len; + expected_length = len + 2; + } + + /* Exit immediately if no sufficient memory space is supplied */ + if ((dst_maxlen < expected_length) || !dst) + return -EINVAL; + + /* Check if the entity number is within bounds */ + if ((comp_field->entity < 0) || (comp_field->entity > 0x1f)) + return -EINVAL; + + /* Check if the algorithm number is within bounds */ + if ((comp_field->algo < 0) || (comp_field->algo > 0x1f)) + return -EINVAL; + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode Propose bit */ + if (comp_field->p) + *dst |= (1 << 7); + + /* Encode entity number */ + *dst |= comp_field->entity & 0x1F; + dst++; + dst_counter++; + + /* Encode algorithm number */ + if (comp_field->p) { + *dst |= comp_field->algo & 0x1F; + dst++; + dst_counter++; + } + + /* Encode length field */ + *dst |= len & 0xFF; + dst++; + dst_counter++; + + /* Encode PCOMP/DCOMP values */ + if (comp_field->p) { + for (i = 0; i < comp_field->comp_len; i++) { + /* Check if submitted PCOMP/DCOMP + values are within bounds */ + if ((comp_field->comp[i] < 0) + || (comp_field->comp[i] > 0x0F)) + return -EINVAL; + + if (i & 1) { + *dst |= comp_field->comp[i] & 0x0F; + dst++; + dst_counter++; + } else + *dst |= (comp_field->comp[i] << 4) & 0xF0; + } + + if (i & 1) { + dst++; + dst_counter++; + } + } + + /* Append payload bytes */ + memcpy(dst, payload_bytes, payload_bytes_len); + dst_counter += payload_bytes_len; + + /* Return generated length */ + return dst_counter; +} + + +/* Find out to which compression class the specified comp-field belongs + (header compression or data compression?) */ +int gprs_sndcp_get_compression_class(const struct gprs_sndcp_comp_field + *comp_field) +{ + if (comp_field->rfc1144_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->rfc2507_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->rohc_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->v42bis_params) + return SNDCP_XID_DATA_COMPRESSION; + else if (comp_field->v44_params) + return SNDCP_XID_DATA_COMPRESSION; + else + return -EINVAL; +} + + +/* Convert all compression fields to bytstreams */ +static int gprs_sndcp_pack_fields(const struct llist_head *comp_fields, + uint8_t * dst, + unsigned int dst_maxlen, int class) +{ + struct gprs_sndcp_comp_field *comp_field; + int byte_counter = 0; + int rc; + + llist_for_each_entry(comp_field, comp_fields, list) { + if (class == gprs_sndcp_get_compression_class(comp_field)) { + rc = encode_comp_field(dst + byte_counter, + dst_maxlen - byte_counter, + comp_field); + + /* Immediately stop on error */ + if (rc < 0) + return rc; + + byte_counter += rc; + } + } + + /* Return generated length */ + return byte_counter; +} + + +/* Transform a list with compression fields into an SNDCP-XID message (dst) */ +int gprs_sndcp_compile_xid(const struct llist_head *comp_fields, uint8_t * dst, + unsigned int dst_maxlen) +{ + int rc; + int byte_counter = 0; + uint8_t comp_bytes[512]; + uint8_t xid_version_number[1] = { CURRENT_SNDCP_VERSION }; + + /* Exit immediately if no sufficient memory space is supplied */ + if ((dst_maxlen < 2 + sizeof(xid_version_number)) || !dst) + return -EINVAL; + + /* Prepend header */ + dst = + tlv_put(dst, SNDCP_XID_VERSION_NUMBER, + sizeof(xid_version_number), xid_version_number); + byte_counter += (sizeof(xid_version_number) + 2); + + /* Add data compression fields */ + rc = gprs_sndcp_pack_fields(comp_fields, comp_bytes, + sizeof(comp_bytes), + SNDCP_XID_DATA_COMPRESSION); + if (rc < 0) + return rc; + else if (rc > 0) { + dst = + tlv_put(dst, SNDCP_XID_DATA_COMPRESSION, rc, + comp_bytes); + byte_counter += rc + 2; + } + + /* Add header compression fields */ + rc = gprs_sndcp_pack_fields(comp_fields, comp_bytes, + sizeof(comp_bytes), + SNDCP_XID_PROTOCOL_COMPRESSION); + if (rc < 0) + return rc; + else if (rc > 0) { + dst = + tlv_put(dst, SNDCP_XID_PROTOCOL_COMPRESSION, rc, + comp_bytes); + byte_counter += rc + 2; + } + + /* Return generated length */ + return byte_counter; +} + + + + + + + + + + +/* + * FUNCTIONS RELATED TO SNDCP-XID DECODING + */ + +/* Decode applicable sapis (works the same in all three compression schemes) */ +static int decode_hdrcomp_applicable_sapis(const uint8_t * src, + unsigned int src_len, + unsigned int *nsapis, + unsigned int *nsapis_len) +{ + uint16_t blob; + int i; + int nsapi_len = 0; + + /* Exit immediately if no result can be stored */ + if (!nsapis) + return -EINVAL; + + /* Exit immediately if not enough input data is available */ + if (src_len < 2) + return -EINVAL; + + /* Read bitmask */ + blob = *src; + blob = (blob << 8) & 0xFF00; + src++; + blob |= (*src) & 0xFF; + blob = (blob >> 5); + + /* Decode applicable SAPIs */ + for (i = 0; i < 15; i++) { + if ((blob >> i) & 1) { + nsapis[nsapi_len] = i + 5; + nsapi_len++; + } + } + + /* Return consumed length */ + *nsapis_len = nsapi_len; + return 2; +} + +/* Decode 16 bit field */ +static int decode_hdrcomp_16_bit_field(const uint8_t * src, + unsigned int src_len, + int value_min, int value_max, + int *value_int, + uint16_t * value_uint16) +{ + uint16_t blob; + + /* Reset values to zero (just to be sure) */ + if (value_int) + *value_int = -1; + if (value_uint16) + *value_uint16 = 0; + + /* Exit if not enough src are available */ + if (src_len < 2) + return -EINVAL; + + /* Decode bit value */ + blob = *src; + blob = (blob << 8) & 0xFF00; + src++; + blob |= *src; + + /* Check if parsed value is within bounds */ + if (blob < value_min) + return -EINVAL; + if (blob > value_max) + return -EINVAL; + + /* Hand back results to the caller */ + if (value_int) + *value_int = blob; + if (value_uint16) + *value_uint16 = blob; + + /* Return consumed length */ + return 2; +} + +/* Decode 8 bit field */ +static int decode_hdrcomp_8_bit_field(const uint8_t * src, + unsigned int src_len, + int value_min, int value_max, + int *value_int, + uint8_t * value_uint8) +{ + uint8_t blob; + + /* Reset values to invalid (just to be sure) */ + if (value_int) + *value_int = -1; + if (value_uint8) + *value_uint8 = 0; + + /* Exit if not enough src are available */ + if (src_len < 1) + return -EINVAL; + + /* Decode bit value */ + blob = *src; + + /* Check if parsed value is within bounds */ + if (blob < value_min) + return -EINVAL; + if (blob > value_max) + return -EINVAL; + + /* Hand back results to the caller */ + if (value_int) + *value_int = blob; + if (value_uint8) + *value_uint8 = blob; + + /* Return consumed length */ + return 1; +} + + + + +/* Decode rfc1144 parameter field see also: ETSI TS 144 065 6.5.2.1, Table 5) */ +static int decode_hdrcomp_rfc1144_params(const uint8_t * src, + unsigned int src_len, struct + gprs_sndcp_hdrcomp_rfc1144_params + *params) +{ + int rc; + int byte_counter = 0; + + /* Exit immediately if no result can be stored */ + if (!params) + return -EINVAL; + + /* Mark all optional parameters invalid by default */ + params->s01=-1; + + /* Decode applicable SAPIs */ + rc = decode_hdrcomp_applicable_sapis(src, src_len, + params->nsapi, + ¶ms->nsapi_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* + * Decode parameter S0 -1 + * (see also: ETSI TS 144 065 6.5.2.1, Table 5) + */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, 0, + 255, ¶ms->s01, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* + * Decode rfc2507 parameter field + * (see also: ETSI TS 144 065 6.5.3.1, Table 6) + */ +static int decode_hdrcomp_rfc2507_params(const uint8_t * src, + unsigned int src_len, struct + gprs_sndcp_hdrcomp_rfc2507_params + *params) +{ + int rc; + int byte_counter = 0; + + /* Exit immediately if no result can be stored */ + if (!params) + return -EINVAL; + + /* Mark all optional parameters invalid by default */ + params->f_max_period=-1; + params->f_max_time=-1; + params->max_header=-1; + params->tcp_space=-1; + params->non_tcp_space=-1; + + /* Decode applicable SAPIs */ + rc = decode_hdrcomp_applicable_sapis(src, src_len, + params->nsapi, + ¶ms->nsapi_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode F_MAX_PERIOD (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 1, 65535, ¶ms->f_max_period, + NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode F_MAX_TIME (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, 1, + 255, ¶ms->f_max_time, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_HEADER (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, + 60, 255, ¶ms->max_header, + NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode TCP_SPACE (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, 3, + 255, ¶ms->tcp_space, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode NON_TCP_SPACE (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 3, 65535, ¶ms->non_tcp_space, + NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Decode ROHC parameter field (see also: ETSI TS 144 065 6.5.4.1, Table 10) */ +static int decode_hdrcomp_rohc_params(const uint8_t * src, + unsigned int src_len, + struct gprs_sndcp_hdrcomp_rohc_params + *params) +{ + int rc; + int byte_counter = 0; + int i; + + /* Exit immediately if no result can be stored */ + if (!params) + return -EINVAL; + + /* Mark all optional parameters invalid by default */ + params->max_cid=-1; + params->max_header=-1; + + /* Decode applicable SAPIs */ + rc = decode_hdrcomp_applicable_sapis(src, src_len, + params->nsapi, + ¶ms->nsapi_len); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_CID (see also: ETSI TS 144 065 6.5.4.1, Table 10) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 0, 16383, ¶ms->max_cid, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_HEADER (see also: ETSI TS 144 065 6.5.4.1, Table 10) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 60, 255, ¶ms->max_header, + NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode Profiles (see also: ETSI TS 144 065 6.5.4.1, Table 10) */ + for (i = 0; i < 16; i++) { + params->profile_len = 0; + rc = decode_hdrcomp_16_bit_field(src, + src_len - byte_counter, + 0, 65535, NULL, + ¶ms->profile[i]); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + params->profile_len = i + 1; + } + + /* Return consumed length */ + return byte_counter; +} + + +/* + * Decode V42bis parameter field + * (see also: ETSI TS 144 065 6.6.2.1, Table 7a) + */ +static int decode_datacomp_v42bis_params(const uint8_t * src, + unsigned int src_len, struct + gprs_sndcp_datacomp_v42bis_params + *params) +{ + int rc; + int byte_counter = 0; + + /* Exit immediately if no result can be stored */ + if (!params) + return -EINVAL; + + /* Mark all optional parameters invalid by default */ + params->p0=-1; + params->p1=-1; + params->p2=-1; + + /* Decode applicable SAPIs */ + rc = decode_hdrcomp_applicable_sapis(src, src_len, + params->nsapi, + ¶ms->nsapi_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode P0 (see also: ETSI TS 144 065 6.6.2.1, Table 7a) */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, 0, + 3, ¶ms->p0, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1 (see also: ETSI TS 144 065 6.6.2.1, Table 7a) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 512, 65535, ¶ms->p1, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P2 (see also: ETSI TS 144 065 6.6.2.1, Table 7a) */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, 6, + 250, ¶ms->p2, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + + +/* Decode V44 parameter field (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ +static int decode_datacomp_v44_params(const uint8_t * src, + unsigned int src_len, + struct gprs_sndcp_datacomp_v44_params + *params) +{ + int rc; + int byte_counter = 0; + + /* Exit immediately if no result can be stored */ + if (!params) + return -EINVAL; + + /* Mark all optional parameters invalid by default */ + params->c0=-1; + params->p0=-1; + params->p1t=-1; + params->p1r=-1; + params->p3t=-1; + params->p3r=-1; + + /* Decode applicable SAPIs */ + rc = decode_hdrcomp_applicable_sapis(src, src_len, + params->nsapi, + ¶ms->nsapi_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode C0 (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, 0, + 255, ¶ms->c0, NULL); + if (rc <= 0) + return byte_counter; + if ((params->c0 != 0x80) && (params->c0 != 0xC0)) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Decode P0 (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, 0, + 3, ¶ms->p0, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1T (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 265, 65535, ¶ms->p1t, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1R (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 265, 65535, ¶ms->p1r, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P3T (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 265, 65535, ¶ms->p3t, NULL); + if (rc <= 0) + return byte_counter; + if (params->p3t < 2 * params->p1t) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Decode P3R (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 265, 65535, ¶ms->p3r, NULL); + if (rc <= 0) + return byte_counter; + if (params->p3r < 2 * params->p1r) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + + +/* Lookup algorithm identfier by entity ID */ +static int lookup_algorithm_identifier(int entity, struct + gprs_sndcp_hdrcomp_entity_algo_table + *lt, unsigned int lt_len, + int compclass) +{ + int i; + if ((lt) && (lt_len > 0)) { + for (i = 0; i < lt_len; i++) { + if ((lt[i].entity == entity) + && (lt[i].compclass == compclass)) + return lt[i].algo; + } + } + + return -1; +} + +/* + * Helper function for decode_comp_field(), decodes + * numeric pcomp/dcomp values + */ +static int decode_comp_values(struct gprs_sndcp_comp_field *comp_field, + const uint8_t * src, int compclass) +{ + int src_counter = 0; + int i; + + if (comp_field->p) { + /* Determine the number of expected PCOMP/DCOMP values */ + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + /* For protocol compression */ + switch (comp_field->algo) { + case RFC_1144: + comp_field->comp_len = RFC1144_PCOMP_NUM; + break; + case RFC_2507: + comp_field->comp_len = RFC2507_PCOMP_NUM; + break; + case ROHC: + comp_field->comp_len = ROHC_PCOMP_NUM; + break; + + /* Exit if the algorithem type encodes + something unknown / unspecified */ + default: + return -EINVAL; + } + } else { + /* For data compression */ + switch (comp_field->algo) { + case V42BIS: + comp_field->comp_len = V42BIS_DCOMP_NUM; + break; + case V44: + comp_field->comp_len = V44_DCOMP_NUM; + break; + + /* Exit if the algorithem type encodes + something unknown / unspecified */ + default: + return -EINVAL; + } + } + + for (i = 0; i < comp_field->comp_len; i++) { + if (i & 1) { + comp_field->comp[i] = (*src) & 0x0F; + src++; + src_counter++; + } else + comp_field->comp[i] = ((*src) >> 4) & 0x0F; + } + + if (i & 1) { + src++; + src_counter++; + } + } + + return src_counter; +} + +/* + * Helper function for decode_comp_field(), decodes the parameters + * which are algorithm specific + */ +static int decode_comp_params(struct gprs_sndcp_comp_field *comp_field, + const uint8_t * src, int src_len, + int compclass) +{ + int rc; + + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + /* For protocol compression */ + switch (comp_field->algo) { + case RFC_1144: + comp_field->rfc1144_params = talloc_zero(NULL, struct + gprs_sndcp_hdrcomp_rfc1144_params); + rc = decode_hdrcomp_rfc1144_params(src, src_len, + comp_field-> + rfc1144_params); + if (rc < 0) + talloc_free(comp_field->rfc1144_params); + break; + case RFC_2507: + comp_field->rfc2507_params = talloc_zero(NULL, struct + gprs_sndcp_hdrcomp_rfc2507_params); + rc = decode_hdrcomp_rfc2507_params(src, src_len, + comp_field-> + rfc2507_params); + if (rc < 0) + talloc_free(comp_field->rfc1144_params); + break; + case ROHC: + comp_field->rohc_params = talloc_zero(NULL, struct + gprs_sndcp_hdrcomp_rohc_params); + rc = decode_hdrcomp_rohc_params(src, src_len, + comp_field-> + rohc_params); + if (rc < 0) + talloc_free(comp_field->rohc_params); + break; + + /* If no suitable decoder is detected, + leave the remaining bytes undecoded */ + default: + rc = src_len; + } + } else { + /* For data compression */ + switch (comp_field->algo) { + case V42BIS: + comp_field->v42bis_params = talloc_zero(NULL, struct + gprs_sndcp_datacomp_v42bis_params); + rc = decode_datacomp_v42bis_params(src, src_len, + comp_field-> + v42bis_params); + if (rc < 0) + talloc_free(comp_field->v42bis_params); + break; + case V44: + comp_field->v44_params = talloc_zero(NULL, struct + gprs_sndcp_datacomp_v44_params); + rc = decode_datacomp_v44_params(src, src_len, + comp_field-> + v44_params); + if (rc < 0) + talloc_free(comp_field->v44_params); + break; + + /* If no suitable decoder is detected, + leave the remaining bytes undecoded */ + default: + rc = src_len; + } + } + + if (rc < 0) { + comp_field->rfc1144_params = NULL; + comp_field->rfc2507_params = NULL; + comp_field->rohc_params = NULL; + comp_field->v42bis_params = NULL; + comp_field->v44_params = NULL; + } + + return rc; +} + + +/* + * Decode data or protocol control information compression field + * (see also: ETSI TS 144 065 6.6.1.1, Figure 9 and + * ETSI TS 144 065 6.5.1.1, Figure 7) + */ +static int decode_comp_field(const uint8_t * src, unsigned int src_len, + struct gprs_sndcp_comp_field *comp_field, + struct + gprs_sndcp_hdrcomp_entity_algo_table + *lt, unsigned int lt_len, int compclass) +{ + int src_counter = 0; + unsigned int len; + int rc; + + /* Exit immediately if it is clear that no + parseable data is present */ + if ((src_len < 1) || !src) + return -EINVAL; + + /* Exit immediately if no result can be stored */ + if (!comp_field) + return -EINVAL; + + /* Zero out target struct */ + memset(comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + + /* Decode Propose bit and Entity number */ + if ((*src) & 0x80) + comp_field->p = 1; + comp_field->entity = (*src) & 0x1F; + src_counter++; + src++; + + /* Decode algorithm number (if present) */ + if (comp_field->p) { + comp_field->algo = (*src) & 0x1F; + src_counter++; + src++; + } + /* Alternatively take the information from the lookup table */ + else + comp_field->algo = + lookup_algorithm_identifier(comp_field->entity, lt, + lt_len, compclass); + + /* Decode length field */ + len = *src; + src_counter++; + src++; + + + /* Decode PCOMP/DCOMP values */ + rc = decode_comp_values(comp_field, src, compclass); + if (rc < 0) + return -EINVAL; + src_counter += rc; + src += rc; + len -= rc; + + /* Decode algorithm specific payload data */ + rc = decode_comp_params(comp_field, src, len, compclass); + if (rc >= 0) + src_counter += rc; + else + return -EINVAL; + + + /* Return consumed length */ + return src_counter; +} + + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +int gprs_sndcp_parse_xid(struct llist_head *comp_fields, const uint8_t * src, + unsigned int src_len, + struct gprs_sndcp_hdrcomp_entity_algo_table + *lt, unsigned int lt_len) +{ + int src_pos = 0; + uint8_t tag; + uint16_t tag_len; + const uint8_t *val; + struct gprs_sndcp_comp_field *comp_field; + int rc; + int byte_counter = 0; + int comp_field_count = 0; + + /* Valid TLV-Tag and types */ + static const struct tlv_definition sndcp_xid_def = { + .def = { + [SNDCP_XID_VERSION_NUMBER] = {TLV_TYPE_TLV,}, + [SNDCP_XID_DATA_COMPRESSION] = {TLV_TYPE_TLV,}, + [SNDCP_XID_PROTOCOL_COMPRESSION] = {TLV_TYPE_TLV,}, + }, + }; + + /* Parse TLV-Encoded SNDCP-XID message and defer payload + to the apporpiate sub-parser functions */ + while (1) { + src_pos += + tlv_parse_one(&tag, &tag_len, &val, &sndcp_xid_def, + src + src_pos, src_len - src_pos); + + /* Decode compression parameters */ + if ((tag == SNDCP_XID_PROTOCOL_COMPRESSION) + || (tag == SNDCP_XID_DATA_COMPRESSION)) { + byte_counter = 0; + do { + /* Bail if more than the maximum number of + comp_fields is generated */ + if (comp_field_count > MAX_ENTITIES * 2) { + gprs_sndcp_free_comp_fields + (comp_fields); + return -EINVAL; + } + + /* Parse and add comp_field */ + comp_field = + talloc_zero(NULL, + struct + gprs_sndcp_comp_field); + + rc = decode_comp_field(val + byte_counter, + tag_len - + byte_counter, + comp_field, lt, + lt_len, tag); + + if (rc < 0) { + talloc_free(comp_field); + gprs_sndcp_free_comp_fields + (comp_fields); + return -EINVAL; + } else { + byte_counter += rc; + llist_add(&comp_field->list, + comp_fields); + } + + comp_field_count++; + } + while (tag_len - byte_counter > 0); + } + + /* Stop when no further TLV elements can be expected */ + if (src_len - src_pos <= 2) + break; + } + + return 0; +} + + +/* Free a list with SNDCP-XID fields */ +void gprs_sndcp_free_comp_fields(struct llist_head *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field; + struct llist_head *lh, *lh2; + + /* Exit immediately if no list is present */ + if (!comp_fields) + return; + + llist_for_each_entry(comp_field, comp_fields, list) { + if (comp_field->rfc1144_params) + talloc_free(comp_field->rfc1144_params); + if (comp_field->rfc2507_params) + talloc_free(comp_field->rfc2507_params); + if (comp_field->rohc_params) + talloc_free(comp_field->rohc_params); + if (comp_field->v42bis_params) + talloc_free(comp_field->v42bis_params); + if (comp_field->v44_params) + talloc_free(comp_field->v44_params); + } + + llist_for_each_safe(lh, lh2, comp_fields) { + llist_del(lh); + talloc_free(lh); + } +} + + +/* Fill up lookutable from a list with comression entitiy fields */ +int gprs_sndcp_fill_table(struct gprs_sndcp_hdrcomp_entity_algo_table *lt, + unsigned int lt_len, + const struct llist_head *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field; + int i = 0; + + if (!(comp_fields)) + return -EINVAL; + if (!(lt)) + return -EINVAL; + + memset(lt, 0, + lt_len * + sizeof(struct gprs_sndcp_hdrcomp_entity_algo_table)); + + llist_for_each_entry(comp_field, comp_fields, list) { + + lt[i].entity = comp_field->entity; + lt[i].algo = comp_field->algo; + lt[i].compclass = + gprs_sndcp_get_compression_class(comp_field); + + if (lt[i].compclass < 0) { + memset(lt, 0, lt_len * + sizeof(struct + gprs_sndcp_hdrcomp_entity_algo_table)); + return -EINVAL; + } + + i++; + } + + return i; +} + + +/* + * Helper for gprs_sndcp_dump_comp_fields(), + * dumps protocol compression parameters + */ +static void dump_pcomp_params(const struct gprs_sndcp_comp_field *comp_field, unsigned int logl) +{ + int i; + switch (comp_field->algo) { + case RFC_1144: + LOGP(DSNDCP, LOGL_DEBUG, + " gprs_sndcp_hdrcomp_rfc1144_params {\n"); + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi_len=%i;\n", + comp_field->rfc1144_params->nsapi_len); + if (comp_field->rfc1144_params->nsapi_len == 0) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rfc1144_params->nsapi_len; i++) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[%i]=%i;\n", i, + comp_field->rfc1144_params->nsapi[i]); + LOGP(DSNDCP, logl, " s01=%i;\n", + comp_field->rfc1144_params->s01); + LOGP(DSNDCP, logl, " }\n"); + break; + case RFC_2507: + LOGP(DSNDCP, LOGL_DEBUG, + " gprs_sndcp_hdrcomp_rfc2507_params {\n"); + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi_len=%i;\n", + comp_field->rfc2507_params->nsapi_len); + if (comp_field->rfc2507_params->nsapi_len == 0) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rfc2507_params->nsapi_len; i++) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[%i]=%i;\n", i, + comp_field->rfc2507_params->nsapi[i]); + LOGP(DSNDCP, LOGL_DEBUG, + " f_max_period=%i;\n", + comp_field->rfc2507_params->f_max_period); + LOGP(DSNDCP, LOGL_DEBUG, + " f_max_time=%i;\n", + comp_field->rfc2507_params->f_max_time); + LOGP(DSNDCP, LOGL_DEBUG, + " max_header=%i;\n", + comp_field->rfc2507_params->max_header); + LOGP(DSNDCP, LOGL_DEBUG, + " tcp_space=%i;\n", + comp_field->rfc2507_params->tcp_space); + LOGP(DSNDCP, LOGL_DEBUG, + " non_tcp_space=%i;\n", + comp_field->rfc2507_params->non_tcp_space); + LOGP(DSNDCP, logl, " }\n"); + break; + case ROHC: + LOGP(DSNDCP, LOGL_DEBUG, + " gprs_sndcp_hdrcomp_rohc_params {\n"); + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi_len=%i;\n", + comp_field->rohc_params->nsapi_len); + if (comp_field->rohc_params->nsapi_len == 0) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rohc_params->nsapi_len; i++) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[%i]=%i;\n", i, + comp_field->rohc_params->nsapi[i]); + LOGP(DSNDCP, LOGL_DEBUG, + " max_cid=%i;\n", + comp_field->rohc_params->max_cid); + LOGP(DSNDCP, LOGL_DEBUG, + " max_header=%i;\n", + comp_field->rohc_params->max_header); + if (comp_field->rohc_params->profile_len == 0) + LOGP(DSNDCP, LOGL_DEBUG, + " profile[] = NULL;\n"); + for (i = 0; i < comp_field->rohc_params->profile_len; i++) + LOGP(DSNDCP, LOGL_DEBUG, + " profile[%i]=%04x;\n", + i, comp_field->rohc_params->profile[i]); + LOGP(DSNDCP, logl, " }\n"); + break; + } + + +} + + +/* + * Helper for gprs_sndcp_dump_comp_fields(), + * data protocol compression parameters + */ +static void dump_dcomp_params(const struct gprs_sndcp_comp_field *comp_field, unsigned int logl) +{ + int i; + switch (comp_field->algo) { + case V42BIS: + LOGP(DSNDCP, LOGL_DEBUG, + " gprs_sndcp_datacomp_v42bis_params {\n"); + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi_len=%i;\n", + comp_field->v42bis_params->nsapi_len); + if (comp_field->v42bis_params->nsapi_len == 0) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->v42bis_params->nsapi_len; i++) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[%i]=%i;\n", i, + comp_field->v42bis_params->nsapi[i]); + LOGP(DSNDCP, logl, " p0=%i;\n", + comp_field->v42bis_params->p0); + LOGP(DSNDCP, logl, " p1=%i;\n", + comp_field->v42bis_params->p1); + LOGP(DSNDCP, logl, " p2=%i;\n", + comp_field->v42bis_params->p2); + LOGP(DSNDCP, logl, " }\n"); + break; + case V44: + LOGP(DSNDCP, LOGL_DEBUG, + " gprs_sndcp_datacomp_v44_params {\n"); + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi_len=%i;\n", + comp_field->v44_params->nsapi_len); + if (comp_field->v44_params->nsapi_len == 0) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->v44_params->nsapi_len; i++) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[%i]=%i;\n", i, + comp_field->v44_params->nsapi[i]); + LOGP(DSNDCP, logl, " c0=%i;\n", + comp_field->v44_params->c0); + LOGP(DSNDCP, logl, " p0=%i;\n", + comp_field->v44_params->p0); + LOGP(DSNDCP, logl, " p1t=%i;\n", + comp_field->v44_params->p1t); + LOGP(DSNDCP, logl, " p1r=%i;\n", + comp_field->v44_params->p1r); + LOGP(DSNDCP, logl, " p3t=%i;\n", + comp_field->v44_params->p3t); + LOGP(DSNDCP, logl, " p3r=%i;\n", + comp_field->v44_params->p3r); + LOGP(DSNDCP, logl, " }\n"); + break; + } +} + + +/* Dump a list with SNDCP-XID fields (Debug) */ +void gprs_sndcp_dump_comp_fields(const struct llist_head *comp_fields, unsigned int logl) +{ + struct gprs_sndcp_comp_field *comp_field; + int i; + int compclass; + + llist_for_each_entry(comp_field, comp_fields, list) { + LOGP(DSNDCP, logl, "SNDCP-XID:\n"); + LOGP(DSNDCP, LOGL_DEBUG, + "struct gprs_sndcp_comp_field {\n"); + LOGP(DSNDCP, logl, " entity=%i;\n", comp_field->entity); + LOGP(DSNDCP, logl, " algo=%i;\n", comp_field->algo); + LOGP(DSNDCP, logl, " comp_len=%i;\n", comp_field->comp_len); + if (comp_field->comp_len == 0) + LOGP(DSNDCP, logl, " comp[] = NULL;\n"); + for (i = 0; i < comp_field->comp_len; i++) + LOGP(DSNDCP, logl, " comp[%i]=%i;\n", i, + comp_field->comp[i]); + + compclass = gprs_sndcp_get_compression_class(comp_field); + + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + dump_pcomp_params(comp_field,logl); + } else if (compclass == SNDCP_XID_DATA_COMPRESSION) { + dump_dcomp_params(comp_field,logl); + } + + LOGP(DSNDCP, logl, "}\n"); + LOGP(DSNDCP, logl, "\n"); + } + +} -- To view, visit https://gerrit.osmocom.org/641 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e Gerrit-PatchSet: 3 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte From gerrit-no-reply at lists.osmocom.org Thu Aug 4 08:40:42 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Thu, 4 Aug 2016 08:40:42 +0000 Subject: [PATCH] openbsc[master]: Added SNDCP-XID encoder / decoder In-Reply-To: References: Message-ID: Hello Harald Welte, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/641 to look at the new patch set (#4). Added SNDCP-XID encoder / decoder The SNDCP-XID (or layer-3 xid) is used to exchange layer-3 parameters such as compression. The encoder encodes a bytestream that is then sent as regular XID field from LLC. We will need the SNDCP-XID to negotiate the parameters for our upcomming GPRS data and header compression features Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e --- M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_sndcp_xid.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_sndcp_xid.c 4 files changed, 1,971 insertions(+), 3 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/41/641/4 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 9e8c554..b37103f 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,7 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h + gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h gprs_sndcp_xid.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_sndcp_xid.h b/openbsc/include/openbsc/gprs_sndcp_xid.h new file mode 100644 index 0000000..ec14a55 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_xid.h @@ -0,0 +1,220 @@ +#ifndef _GPRS_SNDCP_XID_H +#define _GPRS_SNDCP_XID_H + +#include +#include + +#define CURRENT_SNDCP_VERSION 0 /* See TS 144 065, clause 8 */ +#define MAX_ENTITIES 32 /* TS 144 065 reserves 5 bit for compr. entity num. */ + +/* According to: TS 144 065 6.5.1.1 Format of the protocol control information + compression field (Figure 7) + + TS 144 065 6.6.1.1 Format of the data compression + field (Figure 9) */ + +struct gprs_sndcp_comp_field { + struct llist_head list; + + /* Propose bit (P), see also: 6.5.1.1.2 and 6.6.1.1.2 */ + unsigned int p; + + /* Entity number, see also: 6.5.1.1.3 and 6.6.1.1.3 */ + unsigned int entity; + + /* Algorithm identifier, see also: 6.5.1.1.4 and 6.6.1.1.4 */ + unsigned int algo; + + /* Number of contained PCOMP / DCOMP values */ + unsigned int comp_len; + + /* PCOMP / DCOMP values, see also: 6.5.1.1.5 and 6.6.1.1.5 */ + unsigned int comp[16]; + + /* Note: Only one of the following struct pointers may, + be used unused pointers must be set to NULL! */ + struct gprs_sndcp_hdrcomp_rfc1144_params *rfc1144_params; + struct gprs_sndcp_hdrcomp_rfc2507_params *rfc2507_params; + struct gprs_sndcp_hdrcomp_rohc_params *rohc_params; + struct gprs_sndcp_datacomp_v42bis_params *v42bis_params; + struct gprs_sndcp_datacomp_v44_params *v44_params; +}; + +/* According to: TS 144 065 6.5.1.1.4 Algorithm identifier */ +enum gprs_sndcp_hdr_comp_algo { + RFC_1144 = 0, /* TCP/IP header compression, see also 6.5.2 */ + RFC_2507 = 1, /* TCP/UDP/IP header compression, see also: 6.5.3 */ + ROHC = 2, /* Robust Header Compression, see also 6.5.4 */ +}; + +/* According to: TS 144 065 6.5.1.1.4 Algorithm identifier */ +enum gprs_sndcp_data_comp_algo { + V42BIS = 0, /* V42bis data compression, see also 6.6.2 */ + V44 = 1, /* V44 data compression, see also: 6.6.3 */ +}; + +/* According to: TS 144 065 8 SNDCP XID parameters */ +enum gprs_sndcp_xid_param_types { + SNDCP_XID_VERSION_NUMBER = 0, + SNDCP_XID_DATA_COMPRESSION = 1, /* See also: subclause 6.6.1 */ + SNDCP_XID_PROTOCOL_COMPRESSION = 2, /* See also: subclause 6.5.1 */ +}; + +/* When the propose bit in an SNDCP-XID compression field is set to zero, + the algorithm identifier is stripped. The algoritm parameters are specific + for each algorithms. The following struct is used to pass the information + about the referenced algorithm to the parser. */ +struct gprs_sndcp_hdrcomp_entity_algo_table { + unsigned int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + unsigned int algo; /* see also: 6.5.1.1.4 and 6.6.1.1.4 */ + unsigned int compclass; /* Can be either SNDCP_XID_DATA_COMPRESSION or + SNDCP_XID_PROTOCOL_COMPRESSION */ +}; + + + +/* According to: TS 144 065 6.5.2.1 Parameters (Table 5) */ +struct gprs_sndcp_hdrcomp_rfc1144_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int s01; /* (default 15) */ +}; + +/* According to: TS 144 065 6.5.2.2 Assignment of PCOMP values */ +enum gprs_sndcp_hdrcomp_rfc1144_pcomp { + RFC1144_PCOMP1 = 0, /* Uncompressed TCP */ + RFC1144_PCOMP2 = 1, /* Compressed TCP */ + RFC1144_PCOMP_NUM = 2 /* Number of pcomp values */ +}; + + + +/* According to: TS 144 065 6.5.3.1 Parameters (Table 6) */ +struct gprs_sndcp_hdrcomp_rfc2507_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int f_max_period; /* (default 256) */ + int f_max_time; /* (default 5) */ + int max_header; /* (default 168) */ + int tcp_space; /* (default 15) */ + int non_tcp_space; /* (default 15) */ +}; + +/* According to: TS 144 065 6.5.3.2 Assignment of PCOMP values for RFC2507 */ +enum gprs_sndcp_hdrcomp_rfc2507_pcomp { + RFC2507_PCOMP1 = 0, /* Full Header */ + RFC2507_PCOMP2 = 1, /* Compressed TCP */ + RFC2507_PCOMP3 = 2, /* Compressed TCP non delta */ + RFC2507_PCOMP4 = 3, /* Compressed non TCP */ + RFC2507_PCOMP5 = 4, /* Context state */ + RFC2507_PCOMP_NUM = 5 /* Number of pcomp values */ +}; + + + +/* According to: TS 144 065 6.5.4.1 Parameter (Table 10) */ +struct gprs_sndcp_hdrcomp_rohc_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int max_cid; /* (default 15) */ + int max_header; /* (default 168) */ + unsigned int profile_len; /* (default 1) */ + uint16_t profile[16]; /* (default 0, ROHC uncompressed) */ +}; + +/* According to: TS 144 065 6.5.4.2 Assignment of PCOMP values for ROHC */ +enum gprs_sndcp_hdrcomp_rohc_pcomp { + ROHC_PCOMP1 = 0, /* ROHC small CIDs */ + ROHC_PCOMP2 = 1, /* ROHC large CIDs */ + ROHC_PCOMP_NUM = 2 /* Number of pcomp values */ +}; + +/* ROHC compression profiles, see also: + http://www.iana.org/assignments/rohc-pro-ids/rohc-pro-ids.xhtml */ +enum gprs_sndcp_xid_rohc_profiles { + ROHC_UNCOMPRESSED = 0x0000, /* ROHC uncompressed [RFC5795] */ + ROHC_RTP = 0x0001, /* ROHC RTP [RFC3095] */ + ROHCV2_RTP = 0x0101, /* ROHCv2 RTP [RFC5225] */ + ROHC_UDP = 0x0002, /* ROHC UDP [RFC3095] */ + ROHCv2_UDP = 0x0102, /* ROHCv2 UDP [RFC5225] */ + ROHC_ESP = 0x0003, /* ROHC ESP [RFC3095] */ + ROHCV2_ESP = 0x0103, /* ROHCv2 ESP [RFC5225] */ + ROHC_IP = 0x0004, /* ROHC IP [RFC3843] */ + ROHCV2_IP = 0x0104, /* ROHCv2 IP [RFC5225] */ + ROHC_LLA = 0x0005, /* ROHC LLA [RFC4362] */ + ROHC_LLA_WITH_R_MODE = 0x0105, /* ROHC LLA with R-mode [RFC3408] */ + ROHC_TCP = 0x0006, /* ROHC TCP [RFC6846] */ + ROHC_RTP_UDP_LITE = 0x0007, /* ROHC RTP/UDP-Lite [RFC4019] */ + ROHCV2_RTP_UDP_LITE = 0x0107, /* ROHCv2 RTP/UDP-Lite [RFC5225] */ + ROHC_UDP_LITE = 0x0008, /* ROHC UDP-Lite [RFC4019] */ + ROHCV2_UDP_LITE = 0x0108, /* ROHCv2 UDP-Lite [RFC5225] */ +}; + + + +/* According to: TS 144 065 6.6.2.1 Parameters (Table 7a) */ +struct gprs_sndcp_datacomp_v42bis_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int p0; /* (default 3) */ + int p1; /* (default 2048) */ + int p2; /* (default 20) */ + +}; + +/* According to: ETSI TS 144 065 6.6.2.2 Assignment of DCOMP values */ +enum gprs_sndcp_datacomp_v42bis_dcomp { + V42BIS_DCOMP1 = 0, /* V42bis enabled */ + V42BIS_DCOMP_NUM = 1 /* Number of dcomp values */ +}; + + + +/* According to: TS 144 065 6.6.3.1 Parameters (Table 7c) */ +struct gprs_sndcp_datacomp_v44_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int c0; /* (default 10000000) */ + int p0; /* (default 3) */ + int p1t; /* Refer to subclause 6.6.3.1.4 */ + int p1r; /* Refer to subclause 6.6.3.1.5 */ + int p3t; /* (default 3 x p1t) */ + int p3r; /* (default 3 x p1r) */ +}; + +/* According to: ETSI TS 144 065 6.6.3.2 Assignment of DCOMP values */ +enum gprs_sndcp_datacomp_v44_dcomp { + V44_DCOMP1 = 0, /* Packet method compressed */ + V44_DCOMP2 = 1, /* Multi packet method compressed */ + V44_DCOMP_NUM = 2 /* Number of dcomp values */ +}; + +/* Transform a list with compression fields into an SNDCP-XID message (dst) */ +int gprs_sndcp_compile_xid(const struct llist_head *comp_fields, uint8_t *dst, + unsigned int dst_maxlen); + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +int gprs_sndcp_parse_xid(struct llist_head *comp_fields, const uint8_t *src, + unsigned int dst_len, + struct gprs_sndcp_hdrcomp_entity_algo_table *lt, + unsigned int lt_len); + +/* Free a list with SNDCP-XID fields */ +void gprs_sndcp_free_comp_fields(struct llist_head *comp_fields); + +/* Find out to which compression class the specified comp-field belongs + (header compression or data compression?) */ +int gprs_sndcp_get_compression_class(const struct gprs_sndcp_comp_field + *comp_field); + +/* Fill up lookutable from a list with comression entitiy fields */ +int gprs_sndcp_fill_table(struct gprs_sndcp_hdrcomp_entity_algo_table *lt, + unsigned int lt_len, + const struct llist_head *comp_fields); + +/* Dump a list with SNDCP-XID fields (Debug) */ +void gprs_sndcp_dump_comp_fields(const struct llist_head *comp_fields, + unsigned int logl); + + +#endif diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index b3a5137..67e9943 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -21,7 +21,7 @@ $(OSMO_LIBS) $(LIBCRYPTO_LIBS) -lrt osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \ - slhc.c \ + slhc.c gprs_sndcp_xid.c \ sgsn_main.c sgsn_vty.c sgsn_libgtp.c \ gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c \ gprs_llc_xid.c crc24.c \ @@ -32,7 +32,7 @@ osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ - $(LIBCRYPTO_LIBS) -lrt + $(LIBCRYPTO_LIBS) -lrt -lm osmo_gtphub_SOURCES = gtphub_main.c gtphub.c gtphub_sock.c gtphub_ares.c \ gtphub_vty.c sgsn_ares.c gprs_utils.c diff --git a/openbsc/src/gprs/gprs_sndcp_xid.c b/openbsc/src/gprs/gprs_sndcp_xid.c new file mode 100644 index 0000000..070058c --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_xid.c @@ -0,0 +1,1748 @@ +/* GPRS SNDCP XID field encoding/decoding as per 3GPP TS 144 065 */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +/* + * FUNCTIONS RELATED TO SNDCP-XID ENCODING + */ + +/* Encode applicable sapis (works the same in all three compression schemes) */ +static int encode_hdrcomp_applicable_sapis(uint8_t * dst, + const unsigned int *nsapis, + unsigned int nsapis_len) +{ + /* + * NOTE: Buffer *dst needs offer at 2 bytes + * of space to store the generation results + */ + + uint16_t blob; + unsigned int nsapi; + int i; + + /* Encode applicable SAPIs */ + blob = 0; + for (i = 0; i < nsapis_len; i++) { + nsapi = nsapis[i]; + /* + * Only NSAPI 5 to 15 are applicable for user traffic (PDP- + * contexts). Only for these NSAPIs SNDCP-XID parameters + * can apply. See also ETSI TS 144 065 5.1 Service primitives + */ + if ((nsapi < 5) || (nsapi > 15)) + return -EINVAL; + blob |= (1 << nsapi); + } + + /* Store result */ + *dst = (blob >> 8) & 0xFF; + dst++; + *dst = blob & 0xFF; + + return 2; +} + + +/* + * Encode rfc1144 parameter field + * (see also: ETSI TS 144 065 6.5.2.1, Table 5) + */ +static int encode_hdrcomp_rfc1144_params(uint8_t * dst, + unsigned int dst_maxlen, const struct + gprs_sndcp_hdrcomp_rfc1144_params + *params) +{ + /* + * NOTE: Buffer *dst should offer at least 3 bytes + * of space to store the generation results + */ + + int dst_counter = 0; + int rc; + + /* Exit immediately if no source struct is available */ + if (!params) + return -EINVAL; + + /* Exit immediately if no sufficient memory space is supplied */ + if ((dst_maxlen < 3) || !dst) + return -EINVAL; + + /* + * Exit if number of possible nsapis exceeds valid range + * (Only 11 nsapis possible for PDP-Contexts) + */ + if ((params->nsapi_len < 0) || (params->nsapi_len > 11)) + return -EINVAL; + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_hdrcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode s01 (see also: ETSI TS 144 065 6.5.2.1, Table 5) */ + *dst = params->s01; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + + +/* + * Encode rfc2507 parameter field + * (see also: ETSI TS 144 065 6.5.3.1, Table 6) + */ +static int encode_hdrcomp_rfc2507_params(uint8_t * dst, + unsigned int dst_maxlen, const struct + gprs_sndcp_hdrcomp_rfc2507_params + *params) +{ + /* + * NOTE: Buffer *dst should offer at least 3 bytes + * of space to store the generation results + */ + + int dst_counter = 0; + int rc; + + /* Exit immediately if no source struct is available */ + if (!params) + return -EINVAL; + + /* Exit immediately if no sufficient memory space is supplied */ + if ((dst_maxlen < 9) || !dst) + return -EINVAL; + + /* + * Exit if number of possible nsapis exceeds valid range + * (Only 11 nsapis possible for PDP-Contexts) + */ + if ((params->nsapi_len < 0) || (params->nsapi_len > 11)) + return -EINVAL; + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_hdrcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode F_MAX_PERIOD (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + if ((params->f_max_period < 1) || (params->f_max_period > 65535)) + return -EINVAL; + *dst = (params->f_max_period >> 8) & 0xFF; + dst++; + dst_counter++; + *dst = (params->f_max_period) & 0xFF; + dst++; + dst_counter++; + + /* Encode F_MAX_TIME (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + if ((params->f_max_time < 1) || (params->f_max_time > 255)) + return -EINVAL; + *dst = params->f_max_time; + dst++; + dst_counter++; + + /* Encode MAX_HEADER (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + if ((params->max_header < 60) || (params->max_header > 255)) + return -EINVAL; + *dst = params->max_header; + dst++; + dst_counter++; + + /* Encode TCP_SPACE (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + if ((params->tcp_space < 3) || (params->tcp_space > 255)) + return -EINVAL; + *dst = params->tcp_space; + dst++; + dst_counter++; + + /* Encode NON_TCP_SPACE (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + if ((params->non_tcp_space < 3) || (params->tcp_space > 65535)) + return -EINVAL; + *dst = (params->non_tcp_space >> 8) & 0xFF; + dst++; + dst_counter++; + *dst = (params->non_tcp_space) & 0xFF; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + + +/* + * Encode ROHC parameter field + * (see also: ETSI TS 144 065 6.5.4.1, Table 10) + */ +static int encode_hdrcomp_rohc_params(uint8_t * dst, + unsigned int dst_maxlen, + const struct gprs_sndcp_hdrcomp_rohc_params + *params) +{ + /* + * NOTE: Buffer *dst should offer at least 36 + * (2 * 16 Profiles + 2 * 3 Parameter) bytes + * of memory space to store generation results + */ + + int i; + int dst_counter = 0; + int rc; + + /* Exit immediately if no source struct is available */ + if (!params) + return -EINVAL; + + /* Exit immediately if no sufficient memory space is supplied */ + if ((dst_maxlen < 38) || !dst) + return -EINVAL; + + /* + * Exit if number of possible nsapis exceeds valid range + * (Only 11 nsapis possible for PDP-Contexts) + */ + if ((params->nsapi_len < 0) || (params->nsapi_len > 11)) + return -EINVAL; + + /* + * Exit if number of ROHC profiles exceeds limit + * (ROHC supports only a maximum of 16 different profiles) + */ + if ((params->profile_len < 0) || (params->profile_len > 16)) + return -EINVAL; + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_hdrcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode MAX_CID (see also: ETSI TS 144 065 6.5.4.1, Table 10) */ + if ((params->max_cid < 0) || (params->max_cid > 16383)) + return -EINVAL; + *dst = (params->max_cid >> 8) & 0xFF; + dst++; + *dst = params->max_cid & 0xFF; + dst++; + dst_counter += 2; + + /* Encode MAX_HEADER (see also: ETSI TS 144 065 6.5.4.1, Table 10) */ + if ((params->max_header < 60) || (params->max_header > 255)) + return -EINVAL; + *dst = (params->max_header >> 8) & 0xFF; + dst++; + *dst = params->max_header & 0xFF; + dst++; + dst_counter += 2; + + /* Encode ROHC Profiles (see also: ETSI TS 144 065 6.5.4.1, Table 10) */ + for (i = 0; i < params->profile_len; i++) { + *dst = (params->profile[i] >> 8) & 0xFF; + dst++; + *dst = params->profile[i] & 0xFF; + dst++; + dst_counter += 2; + } + + /* Return generated length */ + return dst_counter; +} + + +/* + * Encode V42bis parameter field + * (see also: ETSI TS 144 065 6.6.2.1, Table 7a) + */ +static int encode_datacomp_v42bis_params(uint8_t * dst, + unsigned int dst_maxlen, const struct + gprs_sndcp_datacomp_v42bis_params + *params) +{ + /* + * NOTE: Buffer *dst should offer at least 6 bytes + * of space to store the generation results + */ + + int dst_counter = 0; + int rc; + + /* Exit immediately if no source struct is available */ + if (!params) + return -EINVAL; + + /* Exit immediately if no sufficient memory space is supplied */ + if ((dst_maxlen < 6) || !dst) + return -EINVAL; + + /* + * Exit if number of possible nsapis exceeds valid range + * (Only 11 nsapis possible for PDP-Contexts) + */ + if ((params->nsapi_len < 0) || (params->nsapi_len > 11)) + return -EINVAL; + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_hdrcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode P0 (see also: ETSI TS 144 065 6.6.2.1, Table 7a) */ + if ((params->p0 < 0) || (params->p0 > 3)) + return -EINVAL; + *dst = params->p0 & 0x03; + dst++; + dst_counter++; + + /* Encode P1 (see also: ETSI TS 144 065 6.6.2.1, Table 7a) */ + if ((params->p1 < 512) || (params->p1 > 65535)) + return -EINVAL; + *dst = (params->p1 >> 8) & 0xFF; + dst++; + *dst = params->p1 & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P2 (see also: ETSI TS 144 065 6.6.2.1, Table 7a) */ + if ((params->p2 < 6) || (params->p2 > 250)) + return -EINVAL; + *dst = params->p2; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + + +/* + * Encode V44 parameter field + * (see also: ETSI TS 144 065 6.6.3.1, Table 7c) + */ +static int encode_datacomp_v44_params(uint8_t * dst, + unsigned int dst_maxlen, + const struct gprs_sndcp_datacomp_v44_params + *params) +{ + /* + * NOTE: Buffer *dst should offer at least 12 bytes + * of space to store the generation results + */ + + int dst_counter = 0; + int rc; + + /* Exit immediately if no source struct is available */ + if (!params) + return -EINVAL; + + /* Exit immediately if no sufficient memory space is supplied */ + if ((dst_maxlen < 12) || !dst) + return -EINVAL; + + /* + * Exit if number of possible nsapis exceeds valid range + * (Only 11 nsapis possible for PDP-Contexts) + */ + if ((params->nsapi_len < 0) || (params->nsapi_len > 11)) + return -EINVAL; + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_hdrcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode C0 (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + if ((params->c0 == 0x80) || (params->c0 == 0xC0)) { + *dst = params->c0 & 0xC0; + dst++; + dst_counter++; + } else + return -EINVAL; + + /* Encode P0 (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + if ((params->p0 < 0) || (params->p0 > 3)) + return -EINVAL; + *dst = params->p0 & 0x03; + dst++; + dst_counter++; + + /* Encode P1T (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + if ((params->p1t < 256) || (params->p1t > 65535)) + return -EINVAL; + *dst = (params->p1t >> 8) & 0xFF; + dst++; + *dst = params->p1t & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P1R (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + if ((params->p1r < 256) || (params->p1r > 65535)) + return -EINVAL; + *dst = (params->p1r >> 8) & 0xFF; + dst++; + *dst = params->p1r & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P3T (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + if ((params->p3t < 0) || (params->p3t > 65535)) + return -EINVAL; + if (params->p3t < 2 * params->p1t) + return -EINVAL; + *dst = (params->p3t >> 8) & 0xFF; + dst++; + *dst = params->p3t & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P3R (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + if ((params->p3r < 0) || (params->p3r > 65535)) + return -EINVAL; + if (params->p3r < 2 * params->p1r) + return -EINVAL; + *dst = (params->p3r >> 8) & 0xFF; + dst++; + *dst = params->p3r & 0xFF; + dst++; + dst_counter += 2; + + /* Return generated length */ + return dst_counter; +} + + +/* + * Encode data or protocol control information compression field + * (see also: ETSI TS 144 065 6.6.1.1, Figure 9 and + * ETSI TS 144 065 6.5.1.1, Figure 7) + */ +static int encode_comp_field(uint8_t * dst, unsigned int dst_maxlen, + const struct gprs_sndcp_comp_field *comp_field) +{ + int dst_counter = 0; + int len; + int expected_length; + int i; + + uint8_t payload_bytes[256]; + int payload_bytes_len = -1; + + /* If possible, try do encode payload bytes first */ + if (comp_field->rfc1144_params) + payload_bytes_len = + encode_hdrcomp_rfc1144_params(payload_bytes, + sizeof(payload_bytes), + comp_field-> + rfc1144_params); + else if (comp_field->rfc2507_params) + payload_bytes_len = + encode_hdrcomp_rfc2507_params(payload_bytes, + sizeof(payload_bytes), + comp_field-> + rfc2507_params); + else if (comp_field->rohc_params) + payload_bytes_len = + encode_hdrcomp_rohc_params(payload_bytes, + sizeof(payload_bytes), + comp_field->rohc_params); + else if (comp_field->v42bis_params) + payload_bytes_len = + encode_datacomp_v42bis_params(payload_bytes, + sizeof(payload_bytes), + comp_field-> + v42bis_params); + else if (comp_field->v44_params) + payload_bytes_len = + encode_datacomp_v44_params(payload_bytes, + sizeof(payload_bytes), + comp_field->v44_params); + else + return -EINVAL; + + /* Exit immediately if payload byte generation failed */ + if (payload_bytes_len < 0) + return -EINVAL; + + /* Exit immediately if no source struct is available */ + if (!comp_field) + return -EINVAL; + + /* Check if comp_len is within bounds */ + if ((comp_field->comp_len < 0) || (comp_field->comp_len > 16)) + return -EINVAL; + + /* Calculate length field of the data block */ + if (comp_field->p) { + len = + payload_bytes_len + + ceil((double) (comp_field->comp_len) / 2.0); + expected_length = len + 3; + } else { + len = payload_bytes_len; + expected_length = len + 2; + } + + /* Exit immediately if no sufficient memory space is supplied */ + if ((dst_maxlen < expected_length) || !dst) + return -EINVAL; + + /* Check if the entity number is within bounds */ + if ((comp_field->entity < 0) || (comp_field->entity > 0x1f)) + return -EINVAL; + + /* Check if the algorithm number is within bounds */ + if ((comp_field->algo < 0) || (comp_field->algo > 0x1f)) + return -EINVAL; + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode Propose bit */ + if (comp_field->p) + *dst |= (1 << 7); + + /* Encode entity number */ + *dst |= comp_field->entity & 0x1F; + dst++; + dst_counter++; + + /* Encode algorithm number */ + if (comp_field->p) { + *dst |= comp_field->algo & 0x1F; + dst++; + dst_counter++; + } + + /* Encode length field */ + *dst |= len & 0xFF; + dst++; + dst_counter++; + + /* Encode PCOMP/DCOMP values */ + if (comp_field->p) { + for (i = 0; i < comp_field->comp_len; i++) { + /* Check if submitted PCOMP/DCOMP + values are within bounds */ + if ((comp_field->comp[i] < 0) + || (comp_field->comp[i] > 0x0F)) + return -EINVAL; + + if (i & 1) { + *dst |= comp_field->comp[i] & 0x0F; + dst++; + dst_counter++; + } else + *dst |= (comp_field->comp[i] << 4) & 0xF0; + } + + if (i & 1) { + dst++; + dst_counter++; + } + } + + /* Append payload bytes */ + memcpy(dst, payload_bytes, payload_bytes_len); + dst_counter += payload_bytes_len; + + /* Return generated length */ + return dst_counter; +} + + +/* Find out to which compression class the specified comp-field belongs + (header compression or data compression?) */ +int gprs_sndcp_get_compression_class(const struct gprs_sndcp_comp_field + *comp_field) +{ + if (comp_field->rfc1144_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->rfc2507_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->rohc_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->v42bis_params) + return SNDCP_XID_DATA_COMPRESSION; + else if (comp_field->v44_params) + return SNDCP_XID_DATA_COMPRESSION; + else + return -EINVAL; +} + + +/* Convert all compression fields to bytstreams */ +static int gprs_sndcp_pack_fields(const struct llist_head *comp_fields, + uint8_t * dst, + unsigned int dst_maxlen, int class) +{ + struct gprs_sndcp_comp_field *comp_field; + int byte_counter = 0; + int rc; + + llist_for_each_entry(comp_field, comp_fields, list) { + if (class == gprs_sndcp_get_compression_class(comp_field)) { + rc = encode_comp_field(dst + byte_counter, + dst_maxlen - byte_counter, + comp_field); + + /* Immediately stop on error */ + if (rc < 0) + return rc; + + byte_counter += rc; + } + } + + /* Return generated length */ + return byte_counter; +} + + +/* Transform a list with compression fields into an SNDCP-XID message (dst) */ +int gprs_sndcp_compile_xid(const struct llist_head *comp_fields, uint8_t * dst, + unsigned int dst_maxlen) +{ + int rc; + int byte_counter = 0; + uint8_t comp_bytes[512]; + uint8_t xid_version_number[1] = { CURRENT_SNDCP_VERSION }; + + /* Exit immediately if no sufficient memory space is supplied */ + if ((dst_maxlen < 2 + sizeof(xid_version_number)) || !dst) + return -EINVAL; + + /* Prepend header */ + dst = + tlv_put(dst, SNDCP_XID_VERSION_NUMBER, + sizeof(xid_version_number), xid_version_number); + byte_counter += (sizeof(xid_version_number) + 2); + + /* Add data compression fields */ + rc = gprs_sndcp_pack_fields(comp_fields, comp_bytes, + sizeof(comp_bytes), + SNDCP_XID_DATA_COMPRESSION); + if (rc < 0) + return rc; + else if (rc > 0) { + dst = + tlv_put(dst, SNDCP_XID_DATA_COMPRESSION, rc, + comp_bytes); + byte_counter += rc + 2; + } + + /* Add header compression fields */ + rc = gprs_sndcp_pack_fields(comp_fields, comp_bytes, + sizeof(comp_bytes), + SNDCP_XID_PROTOCOL_COMPRESSION); + if (rc < 0) + return rc; + else if (rc > 0) { + dst = + tlv_put(dst, SNDCP_XID_PROTOCOL_COMPRESSION, rc, + comp_bytes); + byte_counter += rc + 2; + } + + /* Return generated length */ + return byte_counter; +} + + + + + + + + + + +/* + * FUNCTIONS RELATED TO SNDCP-XID DECODING + */ + +/* Decode applicable sapis (works the same in all three compression schemes) */ +static int decode_hdrcomp_applicable_sapis(const uint8_t * src, + unsigned int src_len, + unsigned int *nsapis, + unsigned int *nsapis_len) +{ + uint16_t blob; + int i; + int nsapi_len = 0; + + /* Exit immediately if no result can be stored */ + if (!nsapis) + return -EINVAL; + + /* Exit immediately if not enough input data is available */ + if (src_len < 2) + return -EINVAL; + + /* Read bitmask */ + blob = *src; + blob = (blob << 8) & 0xFF00; + src++; + blob |= (*src) & 0xFF; + blob = (blob >> 5); + + /* Decode applicable SAPIs */ + for (i = 0; i < 15; i++) { + if ((blob >> i) & 1) { + nsapis[nsapi_len] = i + 5; + nsapi_len++; + } + } + + /* Return consumed length */ + *nsapis_len = nsapi_len; + return 2; +} + +/* Decode 16 bit field */ +static int decode_hdrcomp_16_bit_field(const uint8_t * src, + unsigned int src_len, + int value_min, int value_max, + int *value_int, + uint16_t * value_uint16) +{ + uint16_t blob; + + /* Reset values to zero (just to be sure) */ + if (value_int) + *value_int = -1; + if (value_uint16) + *value_uint16 = 0; + + /* Exit if not enough src are available */ + if (src_len < 2) + return -EINVAL; + + /* Decode bit value */ + blob = *src; + blob = (blob << 8) & 0xFF00; + src++; + blob |= *src; + + /* Check if parsed value is within bounds */ + if (blob < value_min) + return -EINVAL; + if (blob > value_max) + return -EINVAL; + + /* Hand back results to the caller */ + if (value_int) + *value_int = blob; + if (value_uint16) + *value_uint16 = blob; + + /* Return consumed length */ + return 2; +} + +/* Decode 8 bit field */ +static int decode_hdrcomp_8_bit_field(const uint8_t * src, + unsigned int src_len, + int value_min, int value_max, + int *value_int, + uint8_t * value_uint8) +{ + uint8_t blob; + + /* Reset values to invalid (just to be sure) */ + if (value_int) + *value_int = -1; + if (value_uint8) + *value_uint8 = 0; + + /* Exit if not enough src are available */ + if (src_len < 1) + return -EINVAL; + + /* Decode bit value */ + blob = *src; + + /* Check if parsed value is within bounds */ + if (blob < value_min) + return -EINVAL; + if (blob > value_max) + return -EINVAL; + + /* Hand back results to the caller */ + if (value_int) + *value_int = blob; + if (value_uint8) + *value_uint8 = blob; + + /* Return consumed length */ + return 1; +} + + + + +/* Decode rfc1144 parameter field see also: ETSI TS 144 065 6.5.2.1, Table 5) */ +static int decode_hdrcomp_rfc1144_params(const uint8_t * src, + unsigned int src_len, struct + gprs_sndcp_hdrcomp_rfc1144_params + *params) +{ + int rc; + int byte_counter = 0; + + /* Exit immediately if no result can be stored */ + if (!params) + return -EINVAL; + + /* Mark all optional parameters invalid by default */ + params->s01=-1; + + /* Decode applicable SAPIs */ + rc = decode_hdrcomp_applicable_sapis(src, src_len, + params->nsapi, + ¶ms->nsapi_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* + * Decode parameter S0 -1 + * (see also: ETSI TS 144 065 6.5.2.1, Table 5) + */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, 0, + 255, ¶ms->s01, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* + * Decode rfc2507 parameter field + * (see also: ETSI TS 144 065 6.5.3.1, Table 6) + */ +static int decode_hdrcomp_rfc2507_params(const uint8_t * src, + unsigned int src_len, struct + gprs_sndcp_hdrcomp_rfc2507_params + *params) +{ + int rc; + int byte_counter = 0; + + /* Exit immediately if no result can be stored */ + if (!params) + return -EINVAL; + + /* Mark all optional parameters invalid by default */ + params->f_max_period=-1; + params->f_max_time=-1; + params->max_header=-1; + params->tcp_space=-1; + params->non_tcp_space=-1; + + /* Decode applicable SAPIs */ + rc = decode_hdrcomp_applicable_sapis(src, src_len, + params->nsapi, + ¶ms->nsapi_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode F_MAX_PERIOD (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 1, 65535, ¶ms->f_max_period, + NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode F_MAX_TIME (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, 1, + 255, ¶ms->f_max_time, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_HEADER (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, + 60, 255, ¶ms->max_header, + NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode TCP_SPACE (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, 3, + 255, ¶ms->tcp_space, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode NON_TCP_SPACE (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 3, 65535, ¶ms->non_tcp_space, + NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Decode ROHC parameter field (see also: ETSI TS 144 065 6.5.4.1, Table 10) */ +static int decode_hdrcomp_rohc_params(const uint8_t * src, + unsigned int src_len, + struct gprs_sndcp_hdrcomp_rohc_params + *params) +{ + int rc; + int byte_counter = 0; + int i; + + /* Exit immediately if no result can be stored */ + if (!params) + return -EINVAL; + + /* Mark all optional parameters invalid by default */ + params->max_cid=-1; + params->max_header=-1; + + /* Decode applicable SAPIs */ + rc = decode_hdrcomp_applicable_sapis(src, src_len, + params->nsapi, + ¶ms->nsapi_len); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_CID (see also: ETSI TS 144 065 6.5.4.1, Table 10) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 0, 16383, ¶ms->max_cid, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_HEADER (see also: ETSI TS 144 065 6.5.4.1, Table 10) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 60, 255, ¶ms->max_header, + NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode Profiles (see also: ETSI TS 144 065 6.5.4.1, Table 10) */ + for (i = 0; i < 16; i++) { + params->profile_len = 0; + rc = decode_hdrcomp_16_bit_field(src, + src_len - byte_counter, + 0, 65535, NULL, + ¶ms->profile[i]); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + params->profile_len = i + 1; + } + + /* Return consumed length */ + return byte_counter; +} + + +/* + * Decode V42bis parameter field + * (see also: ETSI TS 144 065 6.6.2.1, Table 7a) + */ +static int decode_datacomp_v42bis_params(const uint8_t * src, + unsigned int src_len, struct + gprs_sndcp_datacomp_v42bis_params + *params) +{ + int rc; + int byte_counter = 0; + + /* Exit immediately if no result can be stored */ + if (!params) + return -EINVAL; + + /* Mark all optional parameters invalid by default */ + params->p0=-1; + params->p1=-1; + params->p2=-1; + + /* Decode applicable SAPIs */ + rc = decode_hdrcomp_applicable_sapis(src, src_len, + params->nsapi, + ¶ms->nsapi_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode P0 (see also: ETSI TS 144 065 6.6.2.1, Table 7a) */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, 0, + 3, ¶ms->p0, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1 (see also: ETSI TS 144 065 6.6.2.1, Table 7a) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 512, 65535, ¶ms->p1, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P2 (see also: ETSI TS 144 065 6.6.2.1, Table 7a) */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, 6, + 250, ¶ms->p2, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + + +/* Decode V44 parameter field (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ +static int decode_datacomp_v44_params(const uint8_t * src, + unsigned int src_len, + struct gprs_sndcp_datacomp_v44_params + *params) +{ + int rc; + int byte_counter = 0; + + /* Exit immediately if no result can be stored */ + if (!params) + return -EINVAL; + + /* Mark all optional parameters invalid by default */ + params->c0=-1; + params->p0=-1; + params->p1t=-1; + params->p1r=-1; + params->p3t=-1; + params->p3r=-1; + + /* Decode applicable SAPIs */ + rc = decode_hdrcomp_applicable_sapis(src, src_len, + params->nsapi, + ¶ms->nsapi_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode C0 (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, 0, + 255, ¶ms->c0, NULL); + if (rc <= 0) + return byte_counter; + if ((params->c0 != 0x80) && (params->c0 != 0xC0)) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Decode P0 (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, 0, + 3, ¶ms->p0, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1T (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 265, 65535, ¶ms->p1t, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1R (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 265, 65535, ¶ms->p1r, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P3T (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 265, 65535, ¶ms->p3t, NULL); + if (rc <= 0) + return byte_counter; + if (params->p3t < 2 * params->p1t) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Decode P3R (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 265, 65535, ¶ms->p3r, NULL); + if (rc <= 0) + return byte_counter; + if (params->p3r < 2 * params->p1r) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + + +/* Lookup algorithm identfier by entity ID */ +static int lookup_algorithm_identifier(int entity, struct + gprs_sndcp_hdrcomp_entity_algo_table + *lt, unsigned int lt_len, + int compclass) +{ + int i; + if ((lt) && (lt_len > 0)) { + for (i = 0; i < lt_len; i++) { + if ((lt[i].entity == entity) + && (lt[i].compclass == compclass)) + return lt[i].algo; + } + } + + return -1; +} + +/* + * Helper function for decode_comp_field(), decodes + * numeric pcomp/dcomp values + */ +static int decode_comp_values(struct gprs_sndcp_comp_field *comp_field, + const uint8_t * src, int compclass) +{ + int src_counter = 0; + int i; + + if (comp_field->p) { + /* Determine the number of expected PCOMP/DCOMP values */ + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + /* For protocol compression */ + switch (comp_field->algo) { + case RFC_1144: + comp_field->comp_len = RFC1144_PCOMP_NUM; + break; + case RFC_2507: + comp_field->comp_len = RFC2507_PCOMP_NUM; + break; + case ROHC: + comp_field->comp_len = ROHC_PCOMP_NUM; + break; + + /* Exit if the algorithem type encodes + something unknown / unspecified */ + default: + return -EINVAL; + } + } else { + /* For data compression */ + switch (comp_field->algo) { + case V42BIS: + comp_field->comp_len = V42BIS_DCOMP_NUM; + break; + case V44: + comp_field->comp_len = V44_DCOMP_NUM; + break; + + /* Exit if the algorithem type encodes + something unknown / unspecified */ + default: + return -EINVAL; + } + } + + for (i = 0; i < comp_field->comp_len; i++) { + if (i & 1) { + comp_field->comp[i] = (*src) & 0x0F; + src++; + src_counter++; + } else + comp_field->comp[i] = ((*src) >> 4) & 0x0F; + } + + if (i & 1) { + src++; + src_counter++; + } + } + + return src_counter; +} + +/* + * Helper function for decode_comp_field(), decodes the parameters + * which are algorithm specific + */ +static int decode_comp_params(struct gprs_sndcp_comp_field *comp_field, + const uint8_t * src, int src_len, + int compclass) +{ + int rc; + + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + /* For protocol compression */ + switch (comp_field->algo) { + case RFC_1144: + comp_field->rfc1144_params = talloc_zero(NULL, struct + gprs_sndcp_hdrcomp_rfc1144_params); + rc = decode_hdrcomp_rfc1144_params(src, src_len, + comp_field-> + rfc1144_params); + if (rc < 0) + talloc_free(comp_field->rfc1144_params); + break; + case RFC_2507: + comp_field->rfc2507_params = talloc_zero(NULL, struct + gprs_sndcp_hdrcomp_rfc2507_params); + rc = decode_hdrcomp_rfc2507_params(src, src_len, + comp_field-> + rfc2507_params); + if (rc < 0) + talloc_free(comp_field->rfc1144_params); + break; + case ROHC: + comp_field->rohc_params = talloc_zero(NULL, struct + gprs_sndcp_hdrcomp_rohc_params); + rc = decode_hdrcomp_rohc_params(src, src_len, + comp_field-> + rohc_params); + if (rc < 0) + talloc_free(comp_field->rohc_params); + break; + + /* If no suitable decoder is detected, + leave the remaining bytes undecoded */ + default: + rc = src_len; + } + } else { + /* For data compression */ + switch (comp_field->algo) { + case V42BIS: + comp_field->v42bis_params = talloc_zero(NULL, struct + gprs_sndcp_datacomp_v42bis_params); + rc = decode_datacomp_v42bis_params(src, src_len, + comp_field-> + v42bis_params); + if (rc < 0) + talloc_free(comp_field->v42bis_params); + break; + case V44: + comp_field->v44_params = talloc_zero(NULL, struct + gprs_sndcp_datacomp_v44_params); + rc = decode_datacomp_v44_params(src, src_len, + comp_field-> + v44_params); + if (rc < 0) + talloc_free(comp_field->v44_params); + break; + + /* If no suitable decoder is detected, + leave the remaining bytes undecoded */ + default: + rc = src_len; + } + } + + if (rc < 0) { + comp_field->rfc1144_params = NULL; + comp_field->rfc2507_params = NULL; + comp_field->rohc_params = NULL; + comp_field->v42bis_params = NULL; + comp_field->v44_params = NULL; + } + + return rc; +} + + +/* + * Decode data or protocol control information compression field + * (see also: ETSI TS 144 065 6.6.1.1, Figure 9 and + * ETSI TS 144 065 6.5.1.1, Figure 7) + */ +static int decode_comp_field(const uint8_t * src, unsigned int src_len, + struct gprs_sndcp_comp_field *comp_field, + struct + gprs_sndcp_hdrcomp_entity_algo_table + *lt, unsigned int lt_len, int compclass) +{ + int src_counter = 0; + unsigned int len; + int rc; + + /* Exit immediately if it is clear that no + parseable data is present */ + if ((src_len < 1) || !src) + return -EINVAL; + + /* Exit immediately if no result can be stored */ + if (!comp_field) + return -EINVAL; + + /* Zero out target struct */ + memset(comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + + /* Decode Propose bit and Entity number */ + if ((*src) & 0x80) + comp_field->p = 1; + comp_field->entity = (*src) & 0x1F; + src_counter++; + src++; + + /* Decode algorithm number (if present) */ + if (comp_field->p) { + comp_field->algo = (*src) & 0x1F; + src_counter++; + src++; + } + /* Alternatively take the information from the lookup table */ + else + comp_field->algo = + lookup_algorithm_identifier(comp_field->entity, lt, + lt_len, compclass); + + /* Decode length field */ + len = *src; + src_counter++; + src++; + + + /* Decode PCOMP/DCOMP values */ + rc = decode_comp_values(comp_field, src, compclass); + if (rc < 0) + return -EINVAL; + src_counter += rc; + src += rc; + len -= rc; + + /* Decode algorithm specific payload data */ + rc = decode_comp_params(comp_field, src, len, compclass); + if (rc >= 0) + src_counter += rc; + else + return -EINVAL; + + + /* Return consumed length */ + return src_counter; +} + + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +int gprs_sndcp_parse_xid(struct llist_head *comp_fields, const uint8_t * src, + unsigned int src_len, + struct gprs_sndcp_hdrcomp_entity_algo_table + *lt, unsigned int lt_len) +{ + int src_pos = 0; + uint8_t tag; + uint16_t tag_len; + const uint8_t *val; + struct gprs_sndcp_comp_field *comp_field; + int rc; + int byte_counter = 0; + int comp_field_count = 0; + + /* Valid TLV-Tag and types */ + static const struct tlv_definition sndcp_xid_def = { + .def = { + [SNDCP_XID_VERSION_NUMBER] = {TLV_TYPE_TLV,}, + [SNDCP_XID_DATA_COMPRESSION] = {TLV_TYPE_TLV,}, + [SNDCP_XID_PROTOCOL_COMPRESSION] = {TLV_TYPE_TLV,}, + }, + }; + + /* Parse TLV-Encoded SNDCP-XID message and defer payload + to the apporpiate sub-parser functions */ + while (1) { + src_pos += + tlv_parse_one(&tag, &tag_len, &val, &sndcp_xid_def, + src + src_pos, src_len - src_pos); + + /* Decode compression parameters */ + if ((tag == SNDCP_XID_PROTOCOL_COMPRESSION) + || (tag == SNDCP_XID_DATA_COMPRESSION)) { + byte_counter = 0; + do { + /* Bail if more than the maximum number of + comp_fields is generated */ + if (comp_field_count > MAX_ENTITIES * 2) { + gprs_sndcp_free_comp_fields + (comp_fields); + return -EINVAL; + } + + /* Parse and add comp_field */ + comp_field = + talloc_zero(NULL, + struct + gprs_sndcp_comp_field); + + rc = decode_comp_field(val + byte_counter, + tag_len - + byte_counter, + comp_field, lt, + lt_len, tag); + + if (rc < 0) { + talloc_free(comp_field); + gprs_sndcp_free_comp_fields + (comp_fields); + return -EINVAL; + } else { + byte_counter += rc; + llist_add(&comp_field->list, + comp_fields); + } + + comp_field_count++; + } + while (tag_len - byte_counter > 0); + } + + /* Stop when no further TLV elements can be expected */ + if (src_len - src_pos <= 2) + break; + } + + return 0; +} + + +/* Free a list with SNDCP-XID fields */ +void gprs_sndcp_free_comp_fields(struct llist_head *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field; + struct llist_head *lh, *lh2; + + /* Exit immediately if no list is present */ + if (!comp_fields) + return; + + llist_for_each_entry(comp_field, comp_fields, list) { + if (comp_field->rfc1144_params) + talloc_free(comp_field->rfc1144_params); + if (comp_field->rfc2507_params) + talloc_free(comp_field->rfc2507_params); + if (comp_field->rohc_params) + talloc_free(comp_field->rohc_params); + if (comp_field->v42bis_params) + talloc_free(comp_field->v42bis_params); + if (comp_field->v44_params) + talloc_free(comp_field->v44_params); + } + + llist_for_each_safe(lh, lh2, comp_fields) { + llist_del(lh); + talloc_free(lh); + } +} + + +/* Fill up lookutable from a list with comression entitiy fields */ +int gprs_sndcp_fill_table(struct gprs_sndcp_hdrcomp_entity_algo_table *lt, + unsigned int lt_len, + const struct llist_head *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field; + int i = 0; + + if (!(comp_fields)) + return -EINVAL; + if (!(lt)) + return -EINVAL; + + memset(lt, 0, + lt_len * + sizeof(struct gprs_sndcp_hdrcomp_entity_algo_table)); + + llist_for_each_entry(comp_field, comp_fields, list) { + + lt[i].entity = comp_field->entity; + lt[i].algo = comp_field->algo; + lt[i].compclass = + gprs_sndcp_get_compression_class(comp_field); + + if (lt[i].compclass < 0) { + memset(lt, 0, lt_len * + sizeof(struct + gprs_sndcp_hdrcomp_entity_algo_table)); + return -EINVAL; + } + + i++; + } + + return i; +} + + +/* + * Helper for gprs_sndcp_dump_comp_fields(), + * dumps protocol compression parameters + */ +static void dump_pcomp_params(const struct gprs_sndcp_comp_field *comp_field, unsigned int logl) +{ + int i; + switch (comp_field->algo) { + case RFC_1144: + LOGP(DSNDCP, LOGL_DEBUG, + " gprs_sndcp_hdrcomp_rfc1144_params {\n"); + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi_len=%i;\n", + comp_field->rfc1144_params->nsapi_len); + if (comp_field->rfc1144_params->nsapi_len == 0) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rfc1144_params->nsapi_len; i++) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[%i]=%i;\n", i, + comp_field->rfc1144_params->nsapi[i]); + LOGP(DSNDCP, logl, " s01=%i;\n", + comp_field->rfc1144_params->s01); + LOGP(DSNDCP, logl, " }\n"); + break; + case RFC_2507: + LOGP(DSNDCP, LOGL_DEBUG, + " gprs_sndcp_hdrcomp_rfc2507_params {\n"); + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi_len=%i;\n", + comp_field->rfc2507_params->nsapi_len); + if (comp_field->rfc2507_params->nsapi_len == 0) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rfc2507_params->nsapi_len; i++) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[%i]=%i;\n", i, + comp_field->rfc2507_params->nsapi[i]); + LOGP(DSNDCP, LOGL_DEBUG, + " f_max_period=%i;\n", + comp_field->rfc2507_params->f_max_period); + LOGP(DSNDCP, LOGL_DEBUG, + " f_max_time=%i;\n", + comp_field->rfc2507_params->f_max_time); + LOGP(DSNDCP, LOGL_DEBUG, + " max_header=%i;\n", + comp_field->rfc2507_params->max_header); + LOGP(DSNDCP, LOGL_DEBUG, + " tcp_space=%i;\n", + comp_field->rfc2507_params->tcp_space); + LOGP(DSNDCP, LOGL_DEBUG, + " non_tcp_space=%i;\n", + comp_field->rfc2507_params->non_tcp_space); + LOGP(DSNDCP, logl, " }\n"); + break; + case ROHC: + LOGP(DSNDCP, LOGL_DEBUG, + " gprs_sndcp_hdrcomp_rohc_params {\n"); + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi_len=%i;\n", + comp_field->rohc_params->nsapi_len); + if (comp_field->rohc_params->nsapi_len == 0) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rohc_params->nsapi_len; i++) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[%i]=%i;\n", i, + comp_field->rohc_params->nsapi[i]); + LOGP(DSNDCP, LOGL_DEBUG, + " max_cid=%i;\n", + comp_field->rohc_params->max_cid); + LOGP(DSNDCP, LOGL_DEBUG, + " max_header=%i;\n", + comp_field->rohc_params->max_header); + if (comp_field->rohc_params->profile_len == 0) + LOGP(DSNDCP, LOGL_DEBUG, + " profile[] = NULL;\n"); + for (i = 0; i < comp_field->rohc_params->profile_len; i++) + LOGP(DSNDCP, LOGL_DEBUG, + " profile[%i]=%04x;\n", + i, comp_field->rohc_params->profile[i]); + LOGP(DSNDCP, logl, " }\n"); + break; + } + + +} + + +/* + * Helper for gprs_sndcp_dump_comp_fields(), + * data protocol compression parameters + */ +static void dump_dcomp_params(const struct gprs_sndcp_comp_field *comp_field, unsigned int logl) +{ + int i; + switch (comp_field->algo) { + case V42BIS: + LOGP(DSNDCP, LOGL_DEBUG, + " gprs_sndcp_datacomp_v42bis_params {\n"); + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi_len=%i;\n", + comp_field->v42bis_params->nsapi_len); + if (comp_field->v42bis_params->nsapi_len == 0) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->v42bis_params->nsapi_len; i++) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[%i]=%i;\n", i, + comp_field->v42bis_params->nsapi[i]); + LOGP(DSNDCP, logl, " p0=%i;\n", + comp_field->v42bis_params->p0); + LOGP(DSNDCP, logl, " p1=%i;\n", + comp_field->v42bis_params->p1); + LOGP(DSNDCP, logl, " p2=%i;\n", + comp_field->v42bis_params->p2); + LOGP(DSNDCP, logl, " }\n"); + break; + case V44: + LOGP(DSNDCP, LOGL_DEBUG, + " gprs_sndcp_datacomp_v44_params {\n"); + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi_len=%i;\n", + comp_field->v44_params->nsapi_len); + if (comp_field->v44_params->nsapi_len == 0) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->v44_params->nsapi_len; i++) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[%i]=%i;\n", i, + comp_field->v44_params->nsapi[i]); + LOGP(DSNDCP, logl, " c0=%i;\n", + comp_field->v44_params->c0); + LOGP(DSNDCP, logl, " p0=%i;\n", + comp_field->v44_params->p0); + LOGP(DSNDCP, logl, " p1t=%i;\n", + comp_field->v44_params->p1t); + LOGP(DSNDCP, logl, " p1r=%i;\n", + comp_field->v44_params->p1r); + LOGP(DSNDCP, logl, " p3t=%i;\n", + comp_field->v44_params->p3t); + LOGP(DSNDCP, logl, " p3r=%i;\n", + comp_field->v44_params->p3r); + LOGP(DSNDCP, logl, " }\n"); + break; + } +} + + +/* Dump a list with SNDCP-XID fields (Debug) */ +void gprs_sndcp_dump_comp_fields(const struct llist_head *comp_fields, unsigned int logl) +{ + struct gprs_sndcp_comp_field *comp_field; + int i; + int compclass; + + llist_for_each_entry(comp_field, comp_fields, list) { + LOGP(DSNDCP, logl, "SNDCP-XID:\n"); + LOGP(DSNDCP, LOGL_DEBUG, + "struct gprs_sndcp_comp_field {\n"); + LOGP(DSNDCP, logl, " entity=%i;\n", comp_field->entity); + LOGP(DSNDCP, logl, " algo=%i;\n", comp_field->algo); + LOGP(DSNDCP, logl, " comp_len=%i;\n", comp_field->comp_len); + if (comp_field->comp_len == 0) + LOGP(DSNDCP, logl, " comp[] = NULL;\n"); + for (i = 0; i < comp_field->comp_len; i++) + LOGP(DSNDCP, logl, " comp[%i]=%i;\n", i, + comp_field->comp[i]); + + compclass = gprs_sndcp_get_compression_class(comp_field); + + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + dump_pcomp_params(comp_field,logl); + } else if (compclass == SNDCP_XID_DATA_COMPRESSION) { + dump_dcomp_params(comp_field,logl); + } + + LOGP(DSNDCP, logl, "}\n"); + LOGP(DSNDCP, logl, "\n"); + } + +} -- To view, visit https://gerrit.osmocom.org/641 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e Gerrit-PatchSet: 4 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte From gerrit-no-reply at lists.osmocom.org Thu Aug 4 08:40:42 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Thu, 4 Aug 2016 08:40:42 +0000 Subject: [PATCH] openbsc[master]: Added code to control GPRS TCP/IP header compression. In-Reply-To: References: Message-ID: Added code to control GPRS TCP/IP header compression. In this commit two modules were added: gprs_sndcp_comp_entity.h/c: This part handles the creation and destruction of conpression entites. It handles the allocation and freeing of the memory and offers functions to query compression parameters (i.e. which compression entity should be used if a packet from NSAPI x has to be compressed?) gprs_sndcp_hdrcomp.c/h: This is the code that performs the actual header compression. It takes care that the packets are compressed/decompressed with the right modes etc. It works, but is not yet ready for merging. Both files depend on each other so that they only can be merged both at the same time. Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 --- M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_sndcp_comp_entity.h A openbsc/include/openbsc/gprs_sndcp_hdrcomp.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/gprs_sndcp_comp_entity.c A openbsc/src/gprs/gprs_sndcp_hdrcomp.c 6 files changed, 702 insertions(+), 15 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/42/642/4 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index b37103f..e159db5 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,8 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h gprs_sndcp_xid.h + gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h gprs_sndcp_xid.h \ + gprs_sndcp_comp_entity.h gprs_sndcp_hdrcomp.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_sndcp_comp_entity.h b/openbsc/include/openbsc/gprs_sndcp_comp_entity.h new file mode 100644 index 0000000..3e3ea44 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_comp_entity.h @@ -0,0 +1,91 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_SNDCP_COMP_ENTITY_H +#define _GPRS_SNDCP_COMP_ENTITY_H + +#include +#include +#include + +/* Header / Data compression entity */ +struct gprs_sndcp_comp_entity +{ + struct llist_head list; + + /* Serves as an ID in case we want to delete this entity later */ + int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + + /* Specifies to which NSAPIs the compression entity is assigned */ + int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + int nsapi[11]; /* Applicable NSAPIs (default 0) */ + + /* Assigned pcomp values */ + int comp_len; /* Number of contained PCOMP / DCOMP values */ + int comp[16]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */ + + /* Algorithm parameters */ + int algo; /* Algorithm type (see gprs_sndcp_xid.h) */ + int compclass; /* See gprs_sndcp_xid.h/c */ + void *state; /* Algorithm status and parameters */ +}; + +/* Free a list with compression entities */ +void gprs_sndcp_comp_entities_free (struct llist_head *comp_entities); + +/* Delete a compression entity */ +void gprs_sndcp_comp_entities_delete (struct llist_head *comp_entities, + int entity); + +/* Create and Add a new compression entity +(returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entities_add (struct llist_head *comp_entities, + const struct gprs_sndcp_comp_field *comp_field); + +/* Find compression entity by its entity number */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_entity (const struct llist_head*comp_entities, + int entity); + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_comp (const struct llist_head *comp_entities, + int comp); + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_nsapi (const struct llist_head *comp_entities, + int nsapi); + +/* Find a comp_index for a given pcomp/dcomp value */ +int +gprs_sndcp_comp_entity_find_comp_index_by_comp (const struct gprs_sndcp_comp_entity + *comp_entity, int comp); + +/* Find a pcomp/dcomp value for a given comp_index */ +int +gprs_sndcp_comp_entity_find_comp_by_comp_index (const struct gprs_sndcp_comp_entity + *comp_entity, + int comp_index); + +#endif diff --git a/openbsc/include/openbsc/gprs_sndcp_hdrcomp.h b/openbsc/include/openbsc/gprs_sndcp_hdrcomp.h new file mode 100644 index 0000000..e73bad1 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_hdrcomp.h @@ -0,0 +1,68 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_SNDCP_HDRCOMP_H +#define _GPRS_SNDCP_HDRCOMP_H + +#include +#include +#include + +/* 1=Bypass any header compression, 0=Normal */ +#define GPRS_SNDCP_HDRCOMP_BYPASS 0 + +/* Header compression entity */ +struct gprs_sndcp_hdrcomp_compression_entity { + + /* Specifies to which NSAPIs the compression entity is assigned */ + int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + int nsapi[11]; /* Applicable NSAPIs (default 0) */ + + /* Assigned pcomp values */ + int pcomp_len; /* Number of contained PCOMP / DCOMP values */ + int pcomp[16]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */ + + /* Algorithm parameters */ + int compclass; /* 1=Header compression, 2=Data compression */ + int algo; /* Algorithm type (see gprs_sndcp_xid.h) */ + void *status; /* Algorithm status and parameters */ +}; + + +/* Initalize header compression */ +int gprs_sndcp_hdrcomp_init(struct gprs_sndcp_comp_entity *comp_entity, + struct gprs_sndcp_comp_field *comp_field); + +/* Terminate header compression */ +void gprs_sndcp_hdrcomp_term(struct gprs_sndcp_comp_entity *comp_entity); + +/* Expand header compressed packet */ +int gprs_sndcp_hdrcomp_expand(uint8_t * packet, int packet_len, int pcomp, + struct llist_head *comp_entities); + +/* Expand header compressed packet */ +int gprs_sndcp_hdrcomp_compress(uint8_t * packet, int packet_len, + int *pcomp, + struct llist_head *comp_entities, + int nsapi); + +#endif diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 67e9943..3d6c82a 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -21,7 +21,8 @@ $(OSMO_LIBS) $(LIBCRYPTO_LIBS) -lrt osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \ - slhc.c gprs_sndcp_xid.c \ + slhc.c gprs_sndcp_xid.c gprs_sndcp_comp_entity.c \ + gprs_sndcp_hdrcomp.c \ sgsn_main.c sgsn_vty.c sgsn_libgtp.c \ gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c \ gprs_llc_xid.c crc24.c \ diff --git a/openbsc/src/gprs/gprs_sndcp_comp_entity.c b/openbsc/src/gprs/gprs_sndcp_comp_entity.c index 095a32a..baaa8f9 100644 --- a/openbsc/src/gprs/gprs_sndcp_comp_entity.c +++ b/openbsc/src/gprs/gprs_sndcp_comp_entity.c @@ -36,7 +36,7 @@ /* Create a new compression entity from a XID-Field */ static struct gprs_sndcp_comp_entity * -gprs_sndcp_comp_entity_create (struct gprs_sndcp_comp_field *comp_field) +gprs_sndcp_comp_entity_create (const struct gprs_sndcp_comp_field *comp_field) { struct gprs_sndcp_comp_entity *comp_entity; comp_entity = talloc_zero (NULL, struct gprs_sndcp_comp_entity); @@ -118,26 +118,29 @@ void gprs_sndcp_comp_entities_free (struct llist_head *comp_entities) { - if (comp_entities) { - struct gprs_sndcp_comp_entity *comp_entity; + struct llist_head *lh, *lh2; + struct gprs_sndcp_comp_entity *comp_entity; + if (comp_entities) { llist_for_each_entry (comp_entity, comp_entities, list) { /* Free compression entity */ if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { LOGP (DSNDCP, LOGL_INFO, - "Deleting (free) header compression entity %i ...\n", + "Deleting header compression entity %i ...\n", comp_entity->entity); gprs_sndcp_hdrcomp_term (comp_entity); } else LOGP (DSNDCP, LOGL_INFO, - "Deleting (free) data compression entity %i ...\n", + "Deleting data compression entity %i ...\n", comp_entity->entity); - - talloc_free (comp_entity); } + llist_for_each_safe(lh, lh2, comp_entities) { + llist_del(lh); + talloc_free(lh); + } } } @@ -181,7 +184,7 @@ struct gprs_sndcp_comp_entity * gprs_sndcp_comp_entities_add (struct llist_head - *comp_entities, struct + *comp_entities, const struct gprs_sndcp_comp_field *comp_field) { struct gprs_sndcp_comp_entity *comp_entity; @@ -203,7 +206,7 @@ /* Find compression entity by its entity number */ struct gprs_sndcp_comp_entity * -gprs_sndcp_comp_entity_find_by_entity (struct +gprs_sndcp_comp_entity_find_by_entity (const struct llist_head *comp_entities, int entity) { struct gprs_sndcp_comp_entity *comp_entity; @@ -223,7 +226,7 @@ /* Find which compression entity handles the specified pcomp/dcomp */ struct gprs_sndcp_comp_entity * -gprs_sndcp_comp_entity_find_by_comp (struct +gprs_sndcp_comp_entity_find_by_comp (const struct llist_head *comp_entities, int comp) { struct gprs_sndcp_comp_entity *comp_entity; @@ -246,7 +249,7 @@ /* Find which compression entity handles the specified nsapi */ struct gprs_sndcp_comp_entity * -gprs_sndcp_comp_entity_find_by_nsapi (struct +gprs_sndcp_comp_entity_find_by_nsapi (const struct llist_head *comp_entities, int nsapi) { struct gprs_sndcp_comp_entity *comp_entity; @@ -273,7 +276,7 @@ /* Find a comp_index for a given pcomp/dcomp value */ int -gprs_sndcp_comp_entity_find_comp_index_by_comp (struct +gprs_sndcp_comp_entity_find_comp_index_by_comp (const struct gprs_sndcp_comp_entity *comp_entity, int comp) { @@ -305,7 +308,7 @@ /* Find a pcomp/dcomp value for a given comp_index */ int -gprs_sndcp_comp_entity_find_comp_by_comp_index (struct +gprs_sndcp_comp_entity_find_comp_by_comp_index (const struct gprs_sndcp_comp_entity *comp_entity, int comp_index) { diff --git a/openbsc/src/gprs/gprs_sndcp_hdrcomp.c b/openbsc/src/gprs/gprs_sndcp_hdrcomp.c new file mode 100644 index 0000000..8796684 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_hdrcomp.c @@ -0,0 +1,523 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* Enable private debug messages */ +#define GPRS_SNDCP_HDRCOMP_DEBUG 1 + +/* Test RFC1144 implementation + (Caution: GPRS_SNDCP_HDRCOMP_BYPASS in .h file has to be set to 1!) */ +#define GPRS_SNDCP_HDRCOMP_RFC1144_TEST 0 + +/* Exit immediately in case of RFC1144 test failure */ +#define GPRS_SNDCP_HDRCOMP_RFC1144_TEST_EXITONERR 1 + +/* For debug/test only! */ +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST == 1 +static struct slcompress *test_compression_state_tx = NULL; +static struct slcompress *test_compression_state_rx = NULL; +static int test_errors = 0; +static int gprs_sndcp_hdrcomp_test_ind(uint8_t * packet, int packet_len); +static int gprs_sndcp_hdrcomp_test_req(uint8_t * packet, int packet_len); +#endif + + +/* Initalize header compression */ +int gprs_sndcp_hdrcomp_init(struct gprs_sndcp_comp_entity *comp_entity, + struct gprs_sndcp_comp_field *comp_field) +{ + /* Note: This function is automatically called from + gprs_sndcp_comp_entity.c when a new header compression + entity is created by gprs_sndcp.c */ + + if ((comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + && (comp_entity->algo == RFC_1144)) { + comp_entity->status = + slhc_init(comp_field->rfc1144_params->s01 + 1, + comp_field->rfc1144_params->s01 + 1); + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression initalized.\n"); + return 0; + } + + /* Just in case someone tries to initalize an unknown or unsupported + header compresson. Since everything is checked during the SNDCP + negotiation process, this should never happen! */ + LOGP(DSNDCP, LOGL_ERROR, + "Unknown or unsupported header compression type requested for initalization, could not initalize...\n"); + return -EINVAL; + +} + + +/* Terminate header compression */ +void gprs_sndcp_hdrcomp_term(struct gprs_sndcp_comp_entity *comp_entity) +{ + /* Note: This function is automatically called from + gprs_sndcp_comp_entity.c when a header compression + entity is deleted by gprs_sndcp.c */ + + if ((comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + && (comp_entity->algo == RFC_1144)) { + if (comp_entity->status) { + slhc_free((struct slcompress *) comp_entity-> + status); + comp_entity->status = NULL; + } + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression terminated.\n"); + return; + } + + /* Just in case someone tries to initalize an unknown or unsupported + header compresson. Since everything is checked during the SNDCP + negotiation process, this should never happen! */ + LOGP(DSNDCP, LOGL_ERROR, + "Unknown or unsupported header compression type requested for termiation, could not initalize...\n"); +} + + +/* Display compressor status */ +static void gprs_sndcp_hdrcomp_rfc1144_stat(struct slcompress *comp) +{ + slhc_i_status(comp); + slhc_o_status(comp); +} + + +/* Compress a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_hdrcomp_rfc1144_compress(struct slcompress *comp, + uint8_t * packet, + int packet_len, + int *pcomp_index) +{ + uint8_t *packet_compressed; + uint8_t *packet_compressed_ptr; /* Not used */ + int packet_compressed_len; + + /* Reserve some space for to store the compression result */ + packet_compressed = talloc_zero_size(NULL, packet_len); + + /* Run compressor */ + memcpy(packet_compressed, packet, packet_len); + packet_compressed_len = + slhc_compress(comp, packet, packet_len, + (uint8_t *) packet_compressed, + &packet_compressed_ptr, 0); + + /* Copy back compression result */ + memcpy(packet, packet_compressed, packet_len); + talloc_free(packet_compressed); + + /* Generate pcomp_index */ + if ((packet[0] & SL_TYPE_COMPRESSED_TCP) == SL_TYPE_COMPRESSED_TCP) { + *pcomp_index = 2; + /* Remove tag for compressed TCP, because the packet + type is already define by pcomp */ + // packet[0] &= 0x7F; + } else if ((packet[0] & SL_TYPE_UNCOMPRESSED_TCP) == + SL_TYPE_UNCOMPRESSED_TCP) { + *pcomp_index = 1; + + /* Remove tag for uncompressed TCP, because the + packet type is already define by pcomp */ + packet[0] &= 0x4F; + } else + *pcomp_index = 0; + + return packet_compressed_len; +} + +/* Expand a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_hdrcomp_rfc1144_expand(struct slcompress *comp, + uint8_t * packet, + int packet_len, + int pcomp_index) +{ + int packet_decompressed_len; + int type = -1; + + /* Note: this function should never be called with pcomp_index=0, + since this condition is already filtered + out by gprs_sndcp_hdrcomp_expand() */ + + /* Determine the packet type by the PCOMP index */ + switch (pcomp_index) { + case 1: + type = SL_TYPE_UNCOMPRESSED_TCP; + break; + case 2: + type = SL_TYPE_COMPRESSED_TCP; + break; + } + + /* Restore the original version nibble on + marked uncompressed packets */ + if (type == SL_TYPE_UNCOMPRESSED_TCP) { + LOGP(DSNDCP, LOGL_INFO, + "Uncompressed rfc1144 packet received...\n"); + + + /* Just in case the phone tags uncompressed tcp-packets + (normally this is handled by pcomp so there is + no need for tagging the packets) */ + packet[0] &= 0x4F; + packet_decompressed_len = + slhc_remember(comp, packet, packet_len); + return packet_decompressed_len; + } + + /* Uncompress compressed packets */ + else if (type == SL_TYPE_COMPRESSED_TCP) { + LOGP(DSNDCP, LOGL_INFO, + "Compressed rfc1144 packet received...\n"); + packet_decompressed_len = + slhc_uncompress(comp, packet, packet_len); + return packet_decompressed_len; + } + + + /* Regular or unknown packets will not be touched */ + return packet_len; +} + + +/* Expand header compressed packet */ +int gprs_sndcp_hdrcomp_expand(uint8_t * packet, int packet_len, int pcomp, + struct llist_head *comp_entities) +{ + int rc; + int pcomp_index = 0; + struct gprs_sndcp_comp_entity *comp_entity; + + /* Skip on pcomp=0 */ + if (pcomp == 0) { + LOGP(DSNDCP, LOGL_INFO, + "Uncompressed packet received (pcomp=0), skipping compression...\n"); + return packet_len; + } + + /* Find out which compression entity handles the packet */ + comp_entity = + gprs_sndcp_comp_entity_find_by_comp(comp_entities, pcomp); + + /* Skip compression if no suitable compression entity can be found! */ + if (comp_entity == NULL) { + LOGP(DSNDCP, LOGL_ERROR, + "Compressed packet received (pcomp=%i) but no suitable compression entity found, skipping compression...\n", + pcomp); + return packet_len; + } + + /* Find pcomp_index */ + pcomp_index = + gprs_sndcp_comp_entity_find_comp_index_by_comp(comp_entity, + pcomp); + +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST == 1 + /* Test mode */ + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_expand(): testing compression...!\n"); + rc = gprs_sndcp_hdrcomp_test_ind(packet, packet_len); +#else + /* Normal operation: */ + rc = gprs_sndcp_hdrcomp_rfc1144_expand((struct slcompress *) + comp_entity->status, packet, + packet_len, pcomp_index); + gprs_sndcp_hdrcomp_rfc1144_stat((struct slcompress *) comp_entity-> + status); +#endif + + LOGP(DSNDCP, LOGL_DEBUG, + "Header expansion done, old length=%i, new length=%i, pcomp=%i, pcomp_index=%i\n", + packet_len, rc, pcomp, pcomp_index); + return rc; +} + + +/* Expand header compressed packet */ +int gprs_sndcp_hdrcomp_compress(uint8_t * packet, int packet_len, + int *pcomp, + struct llist_head *comp_entities, + int nsapi) +{ + int rc; + int pcomp_index = 0; + struct gprs_sndcp_comp_entity *comp_entity; + + /* Find out which compression entity handles the packet */ + comp_entity = + gprs_sndcp_comp_entity_find_by_nsapi(comp_entities, nsapi); + + /* Skip compression if no suitable compression entity can be found! */ + if (comp_entity == NULL) { + LOGP(DSNDCP, LOGL_INFO, + "No suitable compression entity found for nsapi %i, skipping compression...\n", + nsapi); + *pcomp = 0; + return packet_len; + } +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST == 1 + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_expand(): testing compression...!\n"); + rc = gprs_sndcp_hdrcomp_test_req(packet, packet_len); + *pcomp = 0; + return rc; +#else + /* Normal operation: */ + rc = gprs_sndcp_hdrcomp_rfc1144_compress((struct slcompress *) + comp_entity->status, + packet, packet_len, + &pcomp_index); + gprs_sndcp_hdrcomp_rfc1144_stat((struct slcompress *) comp_entity-> + status); +#endif + + /* Find pcomp value */ + *pcomp = + gprs_sndcp_comp_entity_find_comp_by_comp_index(comp_entity, + pcomp_index); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header compression done, old length=%i, new length=%i, pcomp=%i, pcomp_index=%i\n", + packet_len, rc, *pcomp, pcomp_index); + return rc; +} + + + + + + + +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST == 1 + +/* + * This is a test implementation to make sure the rfc1144 compression + * implementation works as expected. All data is first compressed and + * decompressed on both directions. + */ + +/* FIXME: FOR EXPERIMENTATION ONLY! REMOVE AS SOON AS POSSIBLE */ +static uint16_t header_checksum(uint8_t * iph, unsigned int ihl) +{ + int i; + uint16_t temp; + uint32_t accumulator = 0xFFFF; + + for (i = 0; i < ihl * 2; i++) { + temp = ((*iph) << 8) & 0xFF00; + iph++; + temp |= (*iph) & 0xFF; + iph++; + + accumulator += temp; + if (accumulator > 0xFFFF) { + accumulator++; + accumulator &= 0xFFFF; + } + } + + return (uint16_t) (htons(~accumulator) & 0xFFFF); +} + +/* Check packet integrity */ +static int gprs_sndcp_hdrcomp_test_check_packet(uint8_t * packet, + uint8_t * packet_backup, + int packet_len, + int + packet_len_uncompressed) +{ + uint16_t checksum; + + if (packet_len != packet_len_uncompressed) { + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): Error: Packet length mismatch!\n"); +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST_EXITONERR == 1 + exit(1); +#endif + return -1; + } + + /* Check packet integrety */ + if (memcmp(packet, packet_backup, packet_len)) { + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): Warning: Packet content!\n"); + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): %s\n", + osmo_hexdump_nospc(packet_backup, 80)); + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): %s\n", + osmo_hexdump_nospc(packet, 80)); + + checksum = header_checksum(packet, 5); + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): %04x\n", + checksum); + + if (checksum == 0x0000) { + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): Checksum looks good!\n"); + + if (memcmp + (packet + 20, packet_backup + 20, + packet_len - 20)) + test_errors++; + else + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): Packet looks also good!\n"); + } else { + test_errors++; +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST_EXITONERR == 1 + exit(1); +#endif + return -1; + } + } + + return 0; +} + +/* FIXME: FOR EXPERIMENTATION ONLY! REMOVE AS SOON AS POSSIBLE */ +static int gprs_sndcp_hdrcomp_test_ind(uint8_t * packet, int packet_len) +{ + int packet_len_compressed; + int packet_len_uncompressed; + int pcomp; + uint8_t *packet_backup; + + if (test_compression_state_tx == NULL) + test_compression_state_tx = slhc_init(8, 8); + if (test_compression_state_rx == NULL) + test_compression_state_rx = slhc_init(8, 8); + + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): packet_len=%i\n", packet_len); + packet_backup = talloc_zero_size(NULL, packet_len); + memcpy(packet_backup, packet, packet_len); + + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): IND: %s\n", + osmo_hexdump_nospc(packet, packet_len)); + packet_len_compressed = + gprs_sndcp_hdrcomp_rfc1144_compress(test_compression_state_rx, + packet, packet_len, + &pcomp); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): IND (COMP): %s\n", + osmo_hexdump_nospc(packet, packet_len_compressed)); + packet_len_uncompressed = + gprs_sndcp_hdrcomp_rfc1144_expand(test_compression_state_tx, + packet, + packet_len_compressed, + pcomp); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): IND (DECOMP): %s\n", + osmo_hexdump_nospc(packet, packet_len_uncompressed)); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): packet_len=%i packet_len_compressed=%i packet_len_uncompressed=%i\n", + packet_len, packet_len_compressed, packet_len_uncompressed); + + gprs_sndcp_hdrcomp_test_check_packet(packet, packet_backup, + packet_len, + packet_len_uncompressed); + talloc_free(packet_backup); + gprs_sndcp_hdrcomp_rfc1144_stat(test_compression_state_rx); + gprs_sndcp_hdrcomp_rfc1144_stat(test_compression_state_tx); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): Test errors: %i\n", + test_errors); + return packet_len; +} + +/* FIXME: FOR EXPERIMENTATION ONLY! REMOVE AS SOON AS POSSIBLE */ +static int gprs_sndcp_hdrcomp_test_req(uint8_t * packet, int packet_len) +{ + int packet_len_compressed; + int packet_len_uncompressed; + int pcomp; + uint8_t *packet_backup; + + if (test_compression_state_tx == NULL) + test_compression_state_tx = slhc_init(8, 8); + if (test_compression_state_rx == NULL) + test_compression_state_rx = slhc_init(8, 8); + + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_req(): packet_len=%i\n", packet_len); + packet_backup = talloc_zero_size(NULL, packet_len); + memcpy(packet_backup, packet, packet_len); + + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_req(): REQ: %s\n", + osmo_hexdump_nospc(packet, packet_len)); + packet_len_compressed = + gprs_sndcp_hdrcomp_rfc1144_compress(test_compression_state_tx, + packet, packet_len, + &pcomp); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_req(): REQ (COMP): %s\n", + osmo_hexdump_nospc(packet, packet_len_compressed)); + packet_len_uncompressed = + gprs_sndcp_hdrcomp_rfc1144_expand(test_compression_state_rx, + packet, + packet_len_compressed, + pcomp); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_req(): REQ (DECOMP): %s\n", + osmo_hexdump_nospc(packet, packet_len_uncompressed)); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_req(): packet_len=%i packet_len_compressed=%i packet_len_uncompressed=%i\n", + packet_len, packet_len_compressed, packet_len_uncompressed); + + gprs_sndcp_hdrcomp_test_check_packet(packet, packet_backup, + packet_len, + packet_len_uncompressed); + talloc_free(packet_backup); + gprs_sndcp_hdrcomp_rfc1144_stat(test_compression_state_rx); + gprs_sndcp_hdrcomp_rfc1144_stat(test_compression_state_tx); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): Test errors: %i\n", + test_errors); + return packet_len; +} + +#endif -- To view, visit https://gerrit.osmocom.org/642 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 Gerrit-PatchSet: 4 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter From gerrit-no-reply at lists.osmocom.org Thu Aug 4 08:40:42 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Thu, 4 Aug 2016 08:40:42 +0000 Subject: [PATCH] openbsc[master]: Added LLC-XID encoder / decoder In-Reply-To: References: Message-ID: Hello Harald Welte, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/638 to look at the new patch set (#4). Added LLC-XID encoder / decoder The lle-xid encoder/decoder is needed to encode and decode llc xid parameter messages. We need this to exchange sndcp-parameters (SNDCP-XID) and also simple parameters such as encryption IOVs Change-Id: Ia06e4cb08bf9b48c2a4682606d1b1a91d19a9d37 --- M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_llc_xid.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_llc_xid.c A openbsc/src/gprs/gprs_sndcp_comp_entity.c 5 files changed, 678 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/38/638/4 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 9ef8a15..9e8c554 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,7 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_sndcp.h slhc.h + gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_llc_xid.h b/openbsc/include/openbsc/gprs_llc_xid.h new file mode 100644 index 0000000..a4104ec --- /dev/null +++ b/openbsc/include/openbsc/gprs_llc_xid.h @@ -0,0 +1,63 @@ +/* GPRS LLC XID field encoding/decoding as per 3GPP TS 04.64 */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_LLC_XID_H +#define _GPRS_LLC_XID_H + +#include +#include + +/* TS 101 351 6.4.1.6 Exchange Identification (XID) + command/response parameter field */ +struct gprs_llc_xid_field { + struct llist_head list; + uint8_t type; /* See also Table 6: LLC layer parameter + negotiation */ + uint8_t *data; /* Payload data (octets) */ + unsigned int data_len; /* Payload length */ +}; + +/* Transform a list with XID fields into a XID message (dst) */ +int gprs_llc_compile_xid(const struct llist_head *xid_fields, uint8_t *dst, + int bytes_maxlen); + +/* Transform a XID message (dst) into a list of XID fields */ +int gprs_llc_parse_xid(struct llist_head *xid_fields, const uint8_t *src, + int bytes_len); + +/* Free llist with xid fields */ +void gprs_llc_free_xid(struct llist_head *xid_fields); + +/* Create a duplicate of an XID-Field */ +struct gprs_llc_xid_field *gprs_llc_duplicate_xid_field(const struct + gprs_llc_xid_field + *xid_field); + +/* Copy an llist with xid fields */ +void gprs_llc_copy_xid(struct llist_head *xid_fields_copy, + const struct llist_head *xid_fields_orig); + +/* Dump a list with XID fields (Debug) */ +void gprs_llc_dump_xid_fields(const struct llist_head *xid_fields, + unsigned int logl); + +#endif diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index a118a19..b3a5137 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -23,7 +23,8 @@ osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \ slhc.c \ sgsn_main.c sgsn_vty.c sgsn_libgtp.c \ - gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c crc24.c \ + gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c \ + gprs_llc_xid.c crc24.c \ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ diff --git a/openbsc/src/gprs/gprs_llc_xid.c b/openbsc/src/gprs/gprs_llc_xid.c new file mode 100644 index 0000000..e2ec163 --- /dev/null +++ b/openbsc/src/gprs/gprs_llc_xid.c @@ -0,0 +1,281 @@ +/* GPRS LLC XID field encoding/decoding as per 3GPP TS 04.64 */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +/* Parse XID parameter field */ +static int +decode_xid_field(const uint8_t *src, uint8_t src_len, + struct gprs_llc_xid_field *xid_field) +{ + uint8_t xl; + uint8_t type; + uint8_t len; + int src_counter = 0; + + /* Exit immediately if it is clear that no + parseable data is present */ + if ((src_len < 1) || !src) + return -EINVAL; + + /* Exit immediately if no result can be stored */ + if (!xid_field) + return -EINVAL; + + /* Extract header info */ + xl = (*src >> 7) & 1; + type = (*src >> 2) & 0x1F; + + /* Extract length field */ + len = (*src) & 0x3; + src++; + src_counter++; + if (xl) { + if (src_len < 2) + return -EINVAL; + len = (len << 6) & 0xC0; + len |= ((*src) >> 2) & 0x3F; + src++; + src_counter++; + } + + /* Fill out struct */ + xid_field->type = type; + xid_field->data_len = len; + if (len > 0) { + if (src_len < src_counter + len) + return -EINVAL; + xid_field->data = + talloc_zero_size(NULL, xid_field->data_len); + memcpy(xid_field->data, src, xid_field->data_len); + } else + xid_field->data = NULL; + + /* Return consumed length */ + return src_counter + len; +} + + +/* Encode XID parameter field */ +static int +encode_xid_field(uint8_t *dst, int dst_maxlen, + const struct gprs_llc_xid_field *xid_field) +{ + int xl = 0; + + /* Exit immediately if no source struct is available */ + if (!xid_field) + return -EINVAL; + + /* When the length does not fit into 2 bits, + we need extended length fields */ + if (xid_field->data_len > 3) + xl = 1; + + /* Exit immediately if it is clear that no + encoding result can be stored */ + if (dst_maxlen < xid_field->data_len + 1 + xl) + return -EINVAL; + + /* There are only 5 bits reserved for the type, exit on exceed */ + if (xid_field->type > 31) + return -EINVAL; + + /* Encode header */ + memset(dst, 0, dst_maxlen); + if (xl) + dst[0] |= 0x80; + dst[0] |= (((xid_field->type) & 0x1F) << 2); + + if (xl) { + dst[0] |= (((xid_field->data_len) >> 6) & 0x03); + dst[1] = ((xid_field->data_len) << 2) & 0xFC; + } else + dst[0] |= ((xid_field->data_len) & 0x03); + + /* Append payload data */ + if ((xid_field->data) && (xid_field->data_len)) + memcpy(dst + 1 + xl, xid_field->data, + xid_field->data_len); + + /* Return generated length */ + return xid_field->data_len + 1 + xl; +} + + +/* Transform a list with XID fields into a XID message (dst) */ +int +gprs_llc_compile_xid(const struct llist_head *xid_fields, uint8_t *dst, + int dst_maxlen) +{ + struct gprs_llc_xid_field *xid_field; + int rc; + int byte_counter = 0; + + llist_for_each_entry(xid_field, xid_fields, list) { + /* Encode XID-Field */ + rc = encode_xid_field(dst, dst_maxlen, xid_field); + if (rc < 0) + return -EINVAL; + + /* Advance pointer and lower maxlen for the + next encoding round */ + dst += rc; + byte_counter += rc; + dst_maxlen -= rc; + } + + /* Return generated length */ + return byte_counter; +} + + +/* Transform a XID message (dst) into a list of XID fields */ +int +gprs_llc_parse_xid(struct llist_head *xid_fields, const uint8_t *src, + int src_len) +{ + struct gprs_llc_xid_field *xid_field; + int rc; + int max_loops = src_len; + + while (1) { + /* Bail in case decode_xid_field() constantly returns zero */ + if (max_loops <= 0) { + gprs_llc_free_xid(xid_fields); + return -EINVAL; + } + + /* Decode XID field */ + xid_field = talloc_zero(NULL, struct gprs_llc_xid_field); + rc = decode_xid_field(src, src_len, xid_field); + + /* Immediately stop on error */ + if (rc < 0) { + gprs_llc_free_xid(xid_fields); + return -EINVAL; + } + + /* Add parsed XID field to list */ + llist_add(&xid_field->list, xid_fields); + + /* Advance pointer and lower dst_len for the next + decoding round */ + src += rc; + src_len -= rc; + + /* We are (scuccessfully) done when no further byes are left */ + if (src_len == 0) + return 0; + + max_loops--; + } +} + + +/* Free llist with xid fields */ +void gprs_llc_free_xid(struct llist_head *xid_fields) +{ + struct gprs_llc_xid_field *xid_field; + struct llist_head *lh, *lh2; + + if (xid_fields) { + llist_for_each_entry(xid_field, xid_fields, list) { + if ((xid_field->data) && (xid_field->data_len)) + talloc_free(xid_field->data); + } + + llist_for_each_safe(lh, lh2, xid_fields) { + llist_del(lh); + talloc_free(lh); + } + } +} + + +/* Create a duplicate of an XID-Field */ +struct gprs_llc_xid_field *gprs_llc_duplicate_xid_field(const struct + gprs_llc_xid_field + *xid_field) +{ + struct gprs_llc_xid_field *duplicate_of_xid_field; + + /* Create a copy of the XID field in memory */ + duplicate_of_xid_field = + talloc_zero(NULL, struct gprs_llc_xid_field); + memcpy(duplicate_of_xid_field, xid_field, + sizeof(struct gprs_llc_xid_field)); + duplicate_of_xid_field->data = + talloc_zero_size(NULL, xid_field->data_len); + memcpy(duplicate_of_xid_field->data, xid_field->data, + xid_field->data_len); + + /* Wipeout all llist information in the duplicate (just to be sure) */ + memset(&duplicate_of_xid_field->list, 0, + sizeof(struct llist_head)); + + return duplicate_of_xid_field; +} + +/* Copy an llist with xid fields */ +void gprs_llc_copy_xid(struct llist_head *xid_fields_copy, + const struct llist_head *xid_fields_orig) +{ + struct gprs_llc_xid_field *xid_field; + + /* Make sure that the target list is empty */ + gprs_llc_free_xid(xid_fields_copy); + + /* Create duplicates and add them to the target list */ + llist_for_each_entry(xid_field, xid_fields_orig, list) { + llist_add(&gprs_llc_duplicate_xid_field(xid_field)->list, xid_fields_copy); + } +} + +/* Dump a list with XID fields (Debug) */ +void gprs_llc_dump_xid_fields(const struct llist_head *xid_fields, unsigned int logl) +{ + struct gprs_llc_xid_field *xid_field; + + llist_for_each_entry(xid_field, xid_fields, list) { + LOGP(DSNDCP, logl, + "XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + osmo_hexdump_nospc(xid_field->data, + xid_field->data_len)); + } +} diff --git a/openbsc/src/gprs/gprs_sndcp_comp_entity.c b/openbsc/src/gprs/gprs_sndcp_comp_entity.c new file mode 100644 index 0000000..095a32a --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_comp_entity.c @@ -0,0 +1,331 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +/* Create a new compression entity from a XID-Field */ +static struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_create (struct gprs_sndcp_comp_field *comp_field) +{ + struct gprs_sndcp_comp_entity *comp_entity; + comp_entity = talloc_zero (NULL, struct gprs_sndcp_comp_entity); + + /* Copy relevant information from the SNDCP-XID field */ + comp_entity->entity = comp_field->entity; + comp_entity->comp_len = comp_field->comp_len; + memcpy (comp_entity->comp, comp_field->comp, + comp_field->comp_len * sizeof (int)); + + if (comp_field->rfc1144_params) { + comp_entity->nsapi_len = + comp_field->rfc1144_params->nsapi_len; + memcpy (comp_entity->nsapi, + comp_field->rfc1144_params->nsapi, + comp_entity->nsapi_len * sizeof (int)); + } + else if (comp_field->rfc2507_params) { + comp_entity->nsapi_len = + comp_field->rfc2507_params->nsapi_len; + memcpy (comp_entity->nsapi, + comp_field->rfc2507_params->nsapi, + comp_entity->nsapi_len * sizeof (int)); + } + else if (comp_field->rohc_params) { + comp_entity->nsapi_len = comp_field->rohc_params->nsapi_len; + memcpy (comp_entity->nsapi, comp_field->rohc_params->nsapi, + comp_entity->nsapi_len * sizeof (int)); + } + else if (comp_field->v42bis_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy (comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + comp_entity->nsapi_len * sizeof (int)); + } + else if (comp_field->v44_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy (comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + comp_entity->nsapi_len * sizeof (int)); + } + else { + talloc_free (comp_entity); + LOGP (DSNDCP, LOGL_ERROR, + "Comp field contained invalid parameters, compression entity not created!\n"); + return NULL; + } + + comp_entity->algo = comp_field->algo; + comp_entity->state = NULL; + + /* Determine of which class our compression entity will be + (Protocol or Data compresson ?) */ + comp_entity->compclass = + gprs_sndcp_get_compression_class (comp_field); + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + if (gprs_sndcp_hdrcomp_init (comp_entity, comp_field) == 0) + LOGP (DSNDCP, LOGL_INFO, + "New header compression entity (%i) created.\n", + comp_entity->entity); + else { + talloc_free (comp_entity); + LOGP (DSNDCP, LOGL_ERROR, + "Header compression entity (%i) creation failed!\n", + comp_entity->entity); + return NULL; + } + } + else + LOGP (DSNDCP, LOGL_INFO, + "New data compression entity (%i) created.\n", + comp_entity->entity); + + return comp_entity; +} + +/* Free a list with compression entities */ +void +gprs_sndcp_comp_entities_free (struct llist_head *comp_entities) +{ + if (comp_entities) { + struct gprs_sndcp_comp_entity *comp_entity; + + llist_for_each_entry (comp_entity, comp_entities, list) { + /* Free compression entity */ + if (comp_entity->compclass == + SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP (DSNDCP, LOGL_INFO, + "Deleting (free) header compression entity %i ...\n", + comp_entity->entity); + gprs_sndcp_hdrcomp_term (comp_entity); + } + else + LOGP (DSNDCP, LOGL_INFO, + "Deleting (free) data compression entity %i ...\n", + comp_entity->entity); + + talloc_free (comp_entity); + } + + } +} + +/* Delete a compression entity */ +void +gprs_sndcp_comp_entities_delete (struct llist_head *comp_entities, int entity) +{ + struct gprs_sndcp_comp_entity *comp_entity; + struct gprs_sndcp_comp_entity *comp_entity_to_delete = NULL; + + if (comp_entities) { + + llist_for_each_entry (comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) + comp_entity_to_delete = comp_entity; + } + + if (comp_entity_to_delete) { + if (comp_entity_to_delete->compclass == + SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP (DSNDCP, LOGL_INFO, + "Deleting header compression entity %i ...\n", + comp_entity_to_delete->entity); + gprs_sndcp_hdrcomp_term + (comp_entity_to_delete); + } + else + LOGP (DSNDCP, LOGL_INFO, + "Deleting data compression entity %i ...\n", + comp_entity_to_delete->entity); + + /* Delete compression entity */ + llist_del (&comp_entity_to_delete->list); + talloc_free (comp_entity_to_delete); + } + } +} + +/* Create and Add a new compression entity +(returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entities_add (struct + llist_head + *comp_entities, struct + gprs_sndcp_comp_field *comp_field) +{ + struct gprs_sndcp_comp_entity *comp_entity; + + /* Just to be sure, if the entity is already in + the list it will be deleted now */ + gprs_sndcp_comp_entities_delete (comp_entities, comp_field->entity); + + /* Create and add a new entity to the list */ + comp_entity = gprs_sndcp_comp_entity_create (comp_field); + + if (comp_entity) { + llist_add (&comp_entity->list, comp_entities); + return comp_entity; + } + + return NULL; +} + +/* Find compression entity by its entity number */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_entity (struct + llist_head *comp_entities, int entity) +{ + struct gprs_sndcp_comp_entity *comp_entity; + + if (comp_entities) { + llist_for_each_entry (comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) + return comp_entity; + } + } + + LOGP (DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given entity number %i.\n", + entity); + return NULL; +} + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_comp (struct + llist_head *comp_entities, int comp) +{ + struct gprs_sndcp_comp_entity *comp_entity; + int i; + + if (comp_entities) { + llist_for_each_entry (comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return comp_entity; + } + } + } + + LOGP (DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given pcomp/dcomp value %i.\n", + comp); + return NULL; +} + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_nsapi (struct + llist_head *comp_entities, int nsapi) +{ + struct gprs_sndcp_comp_entity *comp_entity; + int i; + + if (comp_entities) { + llist_for_each_entry (comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->nsapi_len; i++) { + if (comp_entity->nsapi[i] == nsapi) + return comp_entity; + } + } + + LOGP (DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given nsapi value %i\n", + nsapi); + return NULL; + } + + LOGP (DSNDCP, LOGL_ERROR, + "Compression entity list contained null-pointer!\n"); + return NULL; +} + +/* Find a comp_index for a given pcomp/dcomp value */ +int +gprs_sndcp_comp_entity_find_comp_index_by_comp (struct + gprs_sndcp_comp_entity + *comp_entity, int comp) +{ + int i; + + if (comp_entity) { + /* A pcomp/dcomp field set to zero always disables + all sort of compression and is assigned fix. So we + just return zero in this case */ + if (comp == 0) + return 0; + + /* Look in the pcomp/dcomp list for the index */ + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return i + 1; + } + + LOGP (DSNDCP, LOGL_ERROR, + "Could not find a matching comp_index for given pcomp/dcomp value %i\n", + comp); + return 0; + } + + LOGP (DSNDCP, LOGL_ERROR, + "Compression entity contained null-pointer!\n"); + return 0; +} + +/* Find a pcomp/dcomp value for a given comp_index */ +int +gprs_sndcp_comp_entity_find_comp_by_comp_index (struct + gprs_sndcp_comp_entity + *comp_entity, int comp_index) +{ + if (comp_entity) { + /* A comp_index of zero translates to zero right away. */ + if (comp_index == 0) + return 0; + + if (comp_index > comp_entity->comp_len) { + LOGP (DSNDCP, LOGL_ERROR, + "Could not find a matching pcomp/dcomp value for given comp_index value %i.\n", + comp_index); + return 0; + } + + /* Look in the pcomp/dcomp list for the comp_index */ + return comp_entity->comp[comp_index - 1]; + } + + LOGP (DSNDCP, LOGL_ERROR, + "Compression entity contained null-pointer!\n"); + return 0; +} -- To view, visit https://gerrit.osmocom.org/638 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia06e4cb08bf9b48c2a4682606d1b1a91d19a9d37 Gerrit-PatchSet: 4 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Thu Aug 4 08:48:10 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Thu, 4 Aug 2016 08:48:10 +0000 Subject: [PATCH] openbsc[master]: Added code to control GPRS TCP/IP header compression. In-Reply-To: References: Message-ID: Added code to control GPRS TCP/IP header compression. In this commit two modules were added: gprs_sndcp_comp_entity.h/c: This part handles the creation and destruction of conpression entites. It handles the allocation and freeing of the memory and offers functions to query compression parameters (i.e. which compression entity should be used if a packet from NSAPI x has to be compressed?) gprs_sndcp_hdrcomp.c/h: This is the code that performs the actual header compression. It takes care that the packets are compressed/decompressed with the right modes etc. It works, but is not yet ready for merging. Both files depend on each other so that they only can be merged both at the same time. Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 --- M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_sndcp_comp_entity.h A openbsc/include/openbsc/gprs_sndcp_hdrcomp.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/gprs_sndcp_comp_entity.c A openbsc/src/gprs/gprs_sndcp_hdrcomp.c 6 files changed, 702 insertions(+), 15 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/42/642/5 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index b37103f..e159db5 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,8 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h gprs_sndcp_xid.h + gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h gprs_sndcp_xid.h \ + gprs_sndcp_comp_entity.h gprs_sndcp_hdrcomp.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_sndcp_comp_entity.h b/openbsc/include/openbsc/gprs_sndcp_comp_entity.h new file mode 100644 index 0000000..3e3ea44 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_comp_entity.h @@ -0,0 +1,91 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_SNDCP_COMP_ENTITY_H +#define _GPRS_SNDCP_COMP_ENTITY_H + +#include +#include +#include + +/* Header / Data compression entity */ +struct gprs_sndcp_comp_entity +{ + struct llist_head list; + + /* Serves as an ID in case we want to delete this entity later */ + int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + + /* Specifies to which NSAPIs the compression entity is assigned */ + int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + int nsapi[11]; /* Applicable NSAPIs (default 0) */ + + /* Assigned pcomp values */ + int comp_len; /* Number of contained PCOMP / DCOMP values */ + int comp[16]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */ + + /* Algorithm parameters */ + int algo; /* Algorithm type (see gprs_sndcp_xid.h) */ + int compclass; /* See gprs_sndcp_xid.h/c */ + void *state; /* Algorithm status and parameters */ +}; + +/* Free a list with compression entities */ +void gprs_sndcp_comp_entities_free (struct llist_head *comp_entities); + +/* Delete a compression entity */ +void gprs_sndcp_comp_entities_delete (struct llist_head *comp_entities, + int entity); + +/* Create and Add a new compression entity +(returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entities_add (struct llist_head *comp_entities, + const struct gprs_sndcp_comp_field *comp_field); + +/* Find compression entity by its entity number */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_entity (const struct llist_head*comp_entities, + int entity); + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_comp (const struct llist_head *comp_entities, + int comp); + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_nsapi (const struct llist_head *comp_entities, + int nsapi); + +/* Find a comp_index for a given pcomp/dcomp value */ +int +gprs_sndcp_comp_entity_find_comp_index_by_comp (const struct gprs_sndcp_comp_entity + *comp_entity, int comp); + +/* Find a pcomp/dcomp value for a given comp_index */ +int +gprs_sndcp_comp_entity_find_comp_by_comp_index (const struct gprs_sndcp_comp_entity + *comp_entity, + int comp_index); + +#endif diff --git a/openbsc/include/openbsc/gprs_sndcp_hdrcomp.h b/openbsc/include/openbsc/gprs_sndcp_hdrcomp.h new file mode 100644 index 0000000..ffad997 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_hdrcomp.h @@ -0,0 +1,68 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_SNDCP_HDRCOMP_H +#define _GPRS_SNDCP_HDRCOMP_H + +#include +#include +#include + +/* 1=Bypass any header compression, 0=Normal */ +#define GPRS_SNDCP_HDRCOMP_BYPASS 0 + +/* Header compression entity */ +struct gprs_sndcp_hdrcomp_compression_entity { + + /* Specifies to which NSAPIs the compression entity is assigned */ + int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + int nsapi[11]; /* Applicable NSAPIs (default 0) */ + + /* Assigned pcomp values */ + int pcomp_len; /* Number of contained PCOMP / DCOMP values */ + int pcomp[16]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */ + + /* Algorithm parameters */ + int compclass; /* 1=Header compression, 2=Data compression */ + int algo; /* Algorithm type (see gprs_sndcp_xid.h) */ + void *status; /* Algorithm status and parameters */ +}; + + +/* Initalize header compression */ +int gprs_sndcp_hdrcomp_init(struct gprs_sndcp_comp_entity *comp_entity, + const struct gprs_sndcp_comp_field *comp_field); + +/* Terminate header compression */ +void gprs_sndcp_hdrcomp_term(struct gprs_sndcp_comp_entity *comp_entity); + +/* Expand header compressed packet */ +int gprs_sndcp_hdrcomp_expand(uint8_t * packet, int packet_len, int pcomp, + const struct llist_head *comp_entities); + +/* Expand header compressed packet */ +int gprs_sndcp_hdrcomp_compress(uint8_t * packet, int packet_len, + int *pcomp, + const struct llist_head *comp_entities, + int nsapi); + +#endif diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 67e9943..3d6c82a 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -21,7 +21,8 @@ $(OSMO_LIBS) $(LIBCRYPTO_LIBS) -lrt osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \ - slhc.c gprs_sndcp_xid.c \ + slhc.c gprs_sndcp_xid.c gprs_sndcp_comp_entity.c \ + gprs_sndcp_hdrcomp.c \ sgsn_main.c sgsn_vty.c sgsn_libgtp.c \ gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c \ gprs_llc_xid.c crc24.c \ diff --git a/openbsc/src/gprs/gprs_sndcp_comp_entity.c b/openbsc/src/gprs/gprs_sndcp_comp_entity.c index 095a32a..baaa8f9 100644 --- a/openbsc/src/gprs/gprs_sndcp_comp_entity.c +++ b/openbsc/src/gprs/gprs_sndcp_comp_entity.c @@ -36,7 +36,7 @@ /* Create a new compression entity from a XID-Field */ static struct gprs_sndcp_comp_entity * -gprs_sndcp_comp_entity_create (struct gprs_sndcp_comp_field *comp_field) +gprs_sndcp_comp_entity_create (const struct gprs_sndcp_comp_field *comp_field) { struct gprs_sndcp_comp_entity *comp_entity; comp_entity = talloc_zero (NULL, struct gprs_sndcp_comp_entity); @@ -118,26 +118,29 @@ void gprs_sndcp_comp_entities_free (struct llist_head *comp_entities) { - if (comp_entities) { - struct gprs_sndcp_comp_entity *comp_entity; + struct llist_head *lh, *lh2; + struct gprs_sndcp_comp_entity *comp_entity; + if (comp_entities) { llist_for_each_entry (comp_entity, comp_entities, list) { /* Free compression entity */ if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { LOGP (DSNDCP, LOGL_INFO, - "Deleting (free) header compression entity %i ...\n", + "Deleting header compression entity %i ...\n", comp_entity->entity); gprs_sndcp_hdrcomp_term (comp_entity); } else LOGP (DSNDCP, LOGL_INFO, - "Deleting (free) data compression entity %i ...\n", + "Deleting data compression entity %i ...\n", comp_entity->entity); - - talloc_free (comp_entity); } + llist_for_each_safe(lh, lh2, comp_entities) { + llist_del(lh); + talloc_free(lh); + } } } @@ -181,7 +184,7 @@ struct gprs_sndcp_comp_entity * gprs_sndcp_comp_entities_add (struct llist_head - *comp_entities, struct + *comp_entities, const struct gprs_sndcp_comp_field *comp_field) { struct gprs_sndcp_comp_entity *comp_entity; @@ -203,7 +206,7 @@ /* Find compression entity by its entity number */ struct gprs_sndcp_comp_entity * -gprs_sndcp_comp_entity_find_by_entity (struct +gprs_sndcp_comp_entity_find_by_entity (const struct llist_head *comp_entities, int entity) { struct gprs_sndcp_comp_entity *comp_entity; @@ -223,7 +226,7 @@ /* Find which compression entity handles the specified pcomp/dcomp */ struct gprs_sndcp_comp_entity * -gprs_sndcp_comp_entity_find_by_comp (struct +gprs_sndcp_comp_entity_find_by_comp (const struct llist_head *comp_entities, int comp) { struct gprs_sndcp_comp_entity *comp_entity; @@ -246,7 +249,7 @@ /* Find which compression entity handles the specified nsapi */ struct gprs_sndcp_comp_entity * -gprs_sndcp_comp_entity_find_by_nsapi (struct +gprs_sndcp_comp_entity_find_by_nsapi (const struct llist_head *comp_entities, int nsapi) { struct gprs_sndcp_comp_entity *comp_entity; @@ -273,7 +276,7 @@ /* Find a comp_index for a given pcomp/dcomp value */ int -gprs_sndcp_comp_entity_find_comp_index_by_comp (struct +gprs_sndcp_comp_entity_find_comp_index_by_comp (const struct gprs_sndcp_comp_entity *comp_entity, int comp) { @@ -305,7 +308,7 @@ /* Find a pcomp/dcomp value for a given comp_index */ int -gprs_sndcp_comp_entity_find_comp_by_comp_index (struct +gprs_sndcp_comp_entity_find_comp_by_comp_index (const struct gprs_sndcp_comp_entity *comp_entity, int comp_index) { diff --git a/openbsc/src/gprs/gprs_sndcp_hdrcomp.c b/openbsc/src/gprs/gprs_sndcp_hdrcomp.c new file mode 100644 index 0000000..94b9f12 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_hdrcomp.c @@ -0,0 +1,523 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* Enable private debug messages */ +#define GPRS_SNDCP_HDRCOMP_DEBUG 1 + +/* Test RFC1144 implementation + (Caution: GPRS_SNDCP_HDRCOMP_BYPASS in .h file has to be set to 1!) */ +#define GPRS_SNDCP_HDRCOMP_RFC1144_TEST 0 + +/* Exit immediately in case of RFC1144 test failure */ +#define GPRS_SNDCP_HDRCOMP_RFC1144_TEST_EXITONERR 1 + +/* For debug/test only! */ +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST == 1 +static struct slcompress *test_compression_state_tx = NULL; +static struct slcompress *test_compression_state_rx = NULL; +static int test_errors = 0; +static int gprs_sndcp_hdrcomp_test_ind(uint8_t * packet, int packet_len); +static int gprs_sndcp_hdrcomp_test_req(uint8_t * packet, int packet_len); +#endif + + +/* Initalize header compression */ +int gprs_sndcp_hdrcomp_init(struct gprs_sndcp_comp_entity *comp_entity, + const struct gprs_sndcp_comp_field *comp_field) +{ + /* Note: This function is automatically called from + gprs_sndcp_comp_entity.c when a new header compression + entity is created by gprs_sndcp.c */ + + if ((comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + && (comp_entity->algo == RFC_1144)) { + comp_entity->state = + slhc_init(comp_field->rfc1144_params->s01 + 1, + comp_field->rfc1144_params->s01 + 1); + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression initalized.\n"); + return 0; + } + + /* Just in case someone tries to initalize an unknown or unsupported + header compresson. Since everything is checked during the SNDCP + negotiation process, this should never happen! */ + LOGP(DSNDCP, LOGL_ERROR, + "Unknown or unsupported header compression type requested for initalization, could not initalize...\n"); + return -EINVAL; + +} + + +/* Terminate header compression */ +void gprs_sndcp_hdrcomp_term(struct gprs_sndcp_comp_entity *comp_entity) +{ + /* Note: This function is automatically called from + gprs_sndcp_comp_entity.c when a header compression + entity is deleted by gprs_sndcp.c */ + + if ((comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + && (comp_entity->algo == RFC_1144)) { + if (comp_entity->state) { + slhc_free((struct slcompress *) comp_entity-> + state); + comp_entity->state = NULL; + } + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression terminated.\n"); + return; + } + + /* Just in case someone tries to initalize an unknown or unsupported + header compresson. Since everything is checked during the SNDCP + negotiation process, this should never happen! */ + LOGP(DSNDCP, LOGL_ERROR, + "Unknown or unsupported header compression type requested for termiation, could not initalize...\n"); +} + + +/* Display compressor status */ +static void gprs_sndcp_hdrcomp_rfc1144_stat(struct slcompress *comp) +{ + slhc_i_status(comp); + slhc_o_status(comp); +} + + +/* Compress a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_hdrcomp_rfc1144_compress(struct slcompress *comp, + uint8_t * packet, + int packet_len, + int *pcomp_index) +{ + uint8_t *packet_compressed; + uint8_t *packet_compressed_ptr; /* Not used */ + int packet_compressed_len; + + /* Reserve some space for to store the compression result */ + packet_compressed = talloc_zero_size(NULL, packet_len); + + /* Run compressor */ + memcpy(packet_compressed, packet, packet_len); + packet_compressed_len = + slhc_compress(comp, packet, packet_len, + (uint8_t *) packet_compressed, + &packet_compressed_ptr, 0); + + /* Copy back compression result */ + memcpy(packet, packet_compressed, packet_len); + talloc_free(packet_compressed); + + /* Generate pcomp_index */ + if ((packet[0] & SL_TYPE_COMPRESSED_TCP) == SL_TYPE_COMPRESSED_TCP) { + *pcomp_index = 2; + /* Remove tag for compressed TCP, because the packet + type is already define by pcomp */ + // packet[0] &= 0x7F; + } else if ((packet[0] & SL_TYPE_UNCOMPRESSED_TCP) == + SL_TYPE_UNCOMPRESSED_TCP) { + *pcomp_index = 1; + + /* Remove tag for uncompressed TCP, because the + packet type is already define by pcomp */ + packet[0] &= 0x4F; + } else + *pcomp_index = 0; + + return packet_compressed_len; +} + +/* Expand a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_hdrcomp_rfc1144_expand(struct slcompress *comp, + uint8_t * packet, + int packet_len, + int pcomp_index) +{ + int packet_decompressed_len; + int type = -1; + + /* Note: this function should never be called with pcomp_index=0, + since this condition is already filtered + out by gprs_sndcp_hdrcomp_expand() */ + + /* Determine the packet type by the PCOMP index */ + switch (pcomp_index) { + case 1: + type = SL_TYPE_UNCOMPRESSED_TCP; + break; + case 2: + type = SL_TYPE_COMPRESSED_TCP; + break; + } + + /* Restore the original version nibble on + marked uncompressed packets */ + if (type == SL_TYPE_UNCOMPRESSED_TCP) { + LOGP(DSNDCP, LOGL_INFO, + "Uncompressed rfc1144 packet received...\n"); + + + /* Just in case the phone tags uncompressed tcp-packets + (normally this is handled by pcomp so there is + no need for tagging the packets) */ + packet[0] &= 0x4F; + packet_decompressed_len = + slhc_remember(comp, packet, packet_len); + return packet_decompressed_len; + } + + /* Uncompress compressed packets */ + else if (type == SL_TYPE_COMPRESSED_TCP) { + LOGP(DSNDCP, LOGL_INFO, + "Compressed rfc1144 packet received...\n"); + packet_decompressed_len = + slhc_uncompress(comp, packet, packet_len); + return packet_decompressed_len; + } + + + /* Regular or unknown packets will not be touched */ + return packet_len; +} + + +/* Expand header compressed packet */ +int gprs_sndcp_hdrcomp_expand(uint8_t * packet, int packet_len, int pcomp, + const struct llist_head *comp_entities) +{ + int rc; + int pcomp_index = 0; + struct gprs_sndcp_comp_entity *comp_entity; + + /* Skip on pcomp=0 */ + if (pcomp == 0) { + LOGP(DSNDCP, LOGL_INFO, + "Uncompressed packet received (pcomp=0), skipping compression...\n"); + return packet_len; + } + + /* Find out which compression entity handles the packet */ + comp_entity = + gprs_sndcp_comp_entity_find_by_comp(comp_entities, pcomp); + + /* Skip compression if no suitable compression entity can be found! */ + if (comp_entity == NULL) { + LOGP(DSNDCP, LOGL_ERROR, + "Compressed packet received (pcomp=%i) but no suitable compression entity found, skipping compression...\n", + pcomp); + return packet_len; + } + + /* Find pcomp_index */ + pcomp_index = + gprs_sndcp_comp_entity_find_comp_index_by_comp(comp_entity, + pcomp); + +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST == 1 + /* Test mode */ + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_expand(): testing compression...!\n"); + rc = gprs_sndcp_hdrcomp_test_ind(packet, packet_len); +#else + /* Normal operation: */ + rc = gprs_sndcp_hdrcomp_rfc1144_expand((struct slcompress *) + comp_entity->state, packet, + packet_len, pcomp_index); + gprs_sndcp_hdrcomp_rfc1144_stat((struct slcompress *) comp_entity-> + state); +#endif + + LOGP(DSNDCP, LOGL_DEBUG, + "Header expansion done, old length=%i, new length=%i, pcomp=%i, pcomp_index=%i\n", + packet_len, rc, pcomp, pcomp_index); + return rc; +} + + +/* Expand header compressed packet */ +int gprs_sndcp_hdrcomp_compress(uint8_t * packet, int packet_len, + int *pcomp, + const struct llist_head *comp_entities, + int nsapi) +{ + int rc; + int pcomp_index = 0; + struct gprs_sndcp_comp_entity *comp_entity; + + /* Find out which compression entity handles the packet */ + comp_entity = + gprs_sndcp_comp_entity_find_by_nsapi(comp_entities, nsapi); + + /* Skip compression if no suitable compression entity can be found! */ + if (comp_entity == NULL) { + LOGP(DSNDCP, LOGL_INFO, + "No suitable compression entity found for nsapi %i, skipping compression...\n", + nsapi); + *pcomp = 0; + return packet_len; + } +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST == 1 + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_expand(): testing compression...!\n"); + rc = gprs_sndcp_hdrcomp_test_req(packet, packet_len); + *pcomp = 0; + return rc; +#else + /* Normal operation: */ + rc = gprs_sndcp_hdrcomp_rfc1144_compress((struct slcompress *) + comp_entity->state, + packet, packet_len, + &pcomp_index); + gprs_sndcp_hdrcomp_rfc1144_stat((struct slcompress *) comp_entity-> + state); +#endif + + /* Find pcomp value */ + *pcomp = + gprs_sndcp_comp_entity_find_comp_by_comp_index(comp_entity, + pcomp_index); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header compression done, old length=%i, new length=%i, pcomp=%i, pcomp_index=%i\n", + packet_len, rc, *pcomp, pcomp_index); + return rc; +} + + + + + + + +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST == 1 + +/* + * This is a test implementation to make sure the rfc1144 compression + * implementation works as expected. All data is first compressed and + * decompressed on both directions. + */ + +/* FIXME: FOR EXPERIMENTATION ONLY! REMOVE AS SOON AS POSSIBLE */ +static uint16_t header_checksum(uint8_t * iph, unsigned int ihl) +{ + int i; + uint16_t temp; + uint32_t accumulator = 0xFFFF; + + for (i = 0; i < ihl * 2; i++) { + temp = ((*iph) << 8) & 0xFF00; + iph++; + temp |= (*iph) & 0xFF; + iph++; + + accumulator += temp; + if (accumulator > 0xFFFF) { + accumulator++; + accumulator &= 0xFFFF; + } + } + + return (uint16_t) (htons(~accumulator) & 0xFFFF); +} + +/* Check packet integrity */ +static int gprs_sndcp_hdrcomp_test_check_packet(uint8_t * packet, + uint8_t * packet_backup, + int packet_len, + int + packet_len_uncompressed) +{ + uint16_t checksum; + + if (packet_len != packet_len_uncompressed) { + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): Error: Packet length mismatch!\n"); +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST_EXITONERR == 1 + exit(1); +#endif + return -1; + } + + /* Check packet integrety */ + if (memcmp(packet, packet_backup, packet_len)) { + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): Warning: Packet content!\n"); + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): %s\n", + osmo_hexdump_nospc(packet_backup, 80)); + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): %s\n", + osmo_hexdump_nospc(packet, 80)); + + checksum = header_checksum(packet, 5); + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): %04x\n", + checksum); + + if (checksum == 0x0000) { + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): Checksum looks good!\n"); + + if (memcmp + (packet + 20, packet_backup + 20, + packet_len - 20)) + test_errors++; + else + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): Packet looks also good!\n"); + } else { + test_errors++; +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST_EXITONERR == 1 + exit(1); +#endif + return -1; + } + } + + return 0; +} + +/* FIXME: FOR EXPERIMENTATION ONLY! REMOVE AS SOON AS POSSIBLE */ +static int gprs_sndcp_hdrcomp_test_ind(uint8_t * packet, int packet_len) +{ + int packet_len_compressed; + int packet_len_uncompressed; + int pcomp; + uint8_t *packet_backup; + + if (test_compression_state_tx == NULL) + test_compression_state_tx = slhc_init(8, 8); + if (test_compression_state_rx == NULL) + test_compression_state_rx = slhc_init(8, 8); + + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): packet_len=%i\n", packet_len); + packet_backup = talloc_zero_size(NULL, packet_len); + memcpy(packet_backup, packet, packet_len); + + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): IND: %s\n", + osmo_hexdump_nospc(packet, packet_len)); + packet_len_compressed = + gprs_sndcp_hdrcomp_rfc1144_compress(test_compression_state_rx, + packet, packet_len, + &pcomp); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): IND (COMP): %s\n", + osmo_hexdump_nospc(packet, packet_len_compressed)); + packet_len_uncompressed = + gprs_sndcp_hdrcomp_rfc1144_expand(test_compression_state_tx, + packet, + packet_len_compressed, + pcomp); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): IND (DECOMP): %s\n", + osmo_hexdump_nospc(packet, packet_len_uncompressed)); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): packet_len=%i packet_len_compressed=%i packet_len_uncompressed=%i\n", + packet_len, packet_len_compressed, packet_len_uncompressed); + + gprs_sndcp_hdrcomp_test_check_packet(packet, packet_backup, + packet_len, + packet_len_uncompressed); + talloc_free(packet_backup); + gprs_sndcp_hdrcomp_rfc1144_stat(test_compression_state_rx); + gprs_sndcp_hdrcomp_rfc1144_stat(test_compression_state_tx); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): Test errors: %i\n", + test_errors); + return packet_len; +} + +/* FIXME: FOR EXPERIMENTATION ONLY! REMOVE AS SOON AS POSSIBLE */ +static int gprs_sndcp_hdrcomp_test_req(uint8_t * packet, int packet_len) +{ + int packet_len_compressed; + int packet_len_uncompressed; + int pcomp; + uint8_t *packet_backup; + + if (test_compression_state_tx == NULL) + test_compression_state_tx = slhc_init(8, 8); + if (test_compression_state_rx == NULL) + test_compression_state_rx = slhc_init(8, 8); + + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_req(): packet_len=%i\n", packet_len); + packet_backup = talloc_zero_size(NULL, packet_len); + memcpy(packet_backup, packet, packet_len); + + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_req(): REQ: %s\n", + osmo_hexdump_nospc(packet, packet_len)); + packet_len_compressed = + gprs_sndcp_hdrcomp_rfc1144_compress(test_compression_state_tx, + packet, packet_len, + &pcomp); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_req(): REQ (COMP): %s\n", + osmo_hexdump_nospc(packet, packet_len_compressed)); + packet_len_uncompressed = + gprs_sndcp_hdrcomp_rfc1144_expand(test_compression_state_rx, + packet, + packet_len_compressed, + pcomp); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_req(): REQ (DECOMP): %s\n", + osmo_hexdump_nospc(packet, packet_len_uncompressed)); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_req(): packet_len=%i packet_len_compressed=%i packet_len_uncompressed=%i\n", + packet_len, packet_len_compressed, packet_len_uncompressed); + + gprs_sndcp_hdrcomp_test_check_packet(packet, packet_backup, + packet_len, + packet_len_uncompressed); + talloc_free(packet_backup); + gprs_sndcp_hdrcomp_rfc1144_stat(test_compression_state_rx); + gprs_sndcp_hdrcomp_rfc1144_stat(test_compression_state_tx); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): Test errors: %i\n", + test_errors); + return packet_len; +} + +#endif -- To view, visit https://gerrit.osmocom.org/642 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 Gerrit-PatchSet: 5 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter From gerrit-no-reply at lists.osmocom.org Thu Aug 4 08:56:13 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Thu, 4 Aug 2016 08:56:13 +0000 Subject: [PATCH] openbsc[master]: Added code to control GPRS TCP/IP header compression. In-Reply-To: References: Message-ID: Added code to control GPRS TCP/IP header compression. In this commit two modules were added: gprs_sndcp_comp_entity.h/c: This part handles the creation and destruction of conpression entites. It handles the allocation and freeing of the memory and offers functions to query compression parameters (i.e. which compression entity should be used if a packet from NSAPI x has to be compressed?) gprs_sndcp_hdrcomp.c/h: This is the code that performs the actual header compression. It takes care that the packets are compressed/decompressed with the right modes etc. It works, but is not yet ready for merging. Both files depend on each other so that they only can be merged both at the same time. Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 --- M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/gprs_llc.h A openbsc/include/openbsc/gprs_sndcp_comp_entity.h A openbsc/include/openbsc/gprs_sndcp_hdrcomp.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/gprs_sndcp_comp_entity.c A openbsc/src/gprs/gprs_sndcp_hdrcomp.c 7 files changed, 718 insertions(+), 15 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/42/642/6 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index b37103f..e159db5 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,8 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h gprs_sndcp_xid.h + gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h gprs_sndcp_xid.h \ + gprs_sndcp_comp_entity.h gprs_sndcp_hdrcomp.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h index 0e497a0..39d17f4 100644 --- a/openbsc/include/openbsc/gprs_llc.h +++ b/openbsc/include/openbsc/gprs_llc.h @@ -146,6 +146,16 @@ #define NUM_SAPIS 16 +/* Lists holding the compression entities */ +struct comp_ent { + /* + * In this two list_heads we will store the data and protocol + * compression entities, together with their compression states + */ + struct llist_head proto; + struct llist_head data; +}; + struct gprs_llc_llme { struct llist_head list; @@ -166,6 +176,12 @@ uint16_t nsei; struct gprs_llc_lle lle[NUM_SAPIS]; + /* Compression entities */ + struct comp_ent comp; + + /* Copy of the XID fields we sent */ + struct llist_head xid; + /* Internal management */ uint32_t age_timestamp; }; diff --git a/openbsc/include/openbsc/gprs_sndcp_comp_entity.h b/openbsc/include/openbsc/gprs_sndcp_comp_entity.h new file mode 100644 index 0000000..3e3ea44 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_comp_entity.h @@ -0,0 +1,91 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_SNDCP_COMP_ENTITY_H +#define _GPRS_SNDCP_COMP_ENTITY_H + +#include +#include +#include + +/* Header / Data compression entity */ +struct gprs_sndcp_comp_entity +{ + struct llist_head list; + + /* Serves as an ID in case we want to delete this entity later */ + int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + + /* Specifies to which NSAPIs the compression entity is assigned */ + int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + int nsapi[11]; /* Applicable NSAPIs (default 0) */ + + /* Assigned pcomp values */ + int comp_len; /* Number of contained PCOMP / DCOMP values */ + int comp[16]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */ + + /* Algorithm parameters */ + int algo; /* Algorithm type (see gprs_sndcp_xid.h) */ + int compclass; /* See gprs_sndcp_xid.h/c */ + void *state; /* Algorithm status and parameters */ +}; + +/* Free a list with compression entities */ +void gprs_sndcp_comp_entities_free (struct llist_head *comp_entities); + +/* Delete a compression entity */ +void gprs_sndcp_comp_entities_delete (struct llist_head *comp_entities, + int entity); + +/* Create and Add a new compression entity +(returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entities_add (struct llist_head *comp_entities, + const struct gprs_sndcp_comp_field *comp_field); + +/* Find compression entity by its entity number */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_entity (const struct llist_head*comp_entities, + int entity); + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_comp (const struct llist_head *comp_entities, + int comp); + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_nsapi (const struct llist_head *comp_entities, + int nsapi); + +/* Find a comp_index for a given pcomp/dcomp value */ +int +gprs_sndcp_comp_entity_find_comp_index_by_comp (const struct gprs_sndcp_comp_entity + *comp_entity, int comp); + +/* Find a pcomp/dcomp value for a given comp_index */ +int +gprs_sndcp_comp_entity_find_comp_by_comp_index (const struct gprs_sndcp_comp_entity + *comp_entity, + int comp_index); + +#endif diff --git a/openbsc/include/openbsc/gprs_sndcp_hdrcomp.h b/openbsc/include/openbsc/gprs_sndcp_hdrcomp.h new file mode 100644 index 0000000..ffad997 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_hdrcomp.h @@ -0,0 +1,68 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_SNDCP_HDRCOMP_H +#define _GPRS_SNDCP_HDRCOMP_H + +#include +#include +#include + +/* 1=Bypass any header compression, 0=Normal */ +#define GPRS_SNDCP_HDRCOMP_BYPASS 0 + +/* Header compression entity */ +struct gprs_sndcp_hdrcomp_compression_entity { + + /* Specifies to which NSAPIs the compression entity is assigned */ + int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + int nsapi[11]; /* Applicable NSAPIs (default 0) */ + + /* Assigned pcomp values */ + int pcomp_len; /* Number of contained PCOMP / DCOMP values */ + int pcomp[16]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */ + + /* Algorithm parameters */ + int compclass; /* 1=Header compression, 2=Data compression */ + int algo; /* Algorithm type (see gprs_sndcp_xid.h) */ + void *status; /* Algorithm status and parameters */ +}; + + +/* Initalize header compression */ +int gprs_sndcp_hdrcomp_init(struct gprs_sndcp_comp_entity *comp_entity, + const struct gprs_sndcp_comp_field *comp_field); + +/* Terminate header compression */ +void gprs_sndcp_hdrcomp_term(struct gprs_sndcp_comp_entity *comp_entity); + +/* Expand header compressed packet */ +int gprs_sndcp_hdrcomp_expand(uint8_t * packet, int packet_len, int pcomp, + const struct llist_head *comp_entities); + +/* Expand header compressed packet */ +int gprs_sndcp_hdrcomp_compress(uint8_t * packet, int packet_len, + int *pcomp, + const struct llist_head *comp_entities, + int nsapi); + +#endif diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 67e9943..3d6c82a 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -21,7 +21,8 @@ $(OSMO_LIBS) $(LIBCRYPTO_LIBS) -lrt osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \ - slhc.c gprs_sndcp_xid.c \ + slhc.c gprs_sndcp_xid.c gprs_sndcp_comp_entity.c \ + gprs_sndcp_hdrcomp.c \ sgsn_main.c sgsn_vty.c sgsn_libgtp.c \ gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c \ gprs_llc_xid.c crc24.c \ diff --git a/openbsc/src/gprs/gprs_sndcp_comp_entity.c b/openbsc/src/gprs/gprs_sndcp_comp_entity.c index 095a32a..baaa8f9 100644 --- a/openbsc/src/gprs/gprs_sndcp_comp_entity.c +++ b/openbsc/src/gprs/gprs_sndcp_comp_entity.c @@ -36,7 +36,7 @@ /* Create a new compression entity from a XID-Field */ static struct gprs_sndcp_comp_entity * -gprs_sndcp_comp_entity_create (struct gprs_sndcp_comp_field *comp_field) +gprs_sndcp_comp_entity_create (const struct gprs_sndcp_comp_field *comp_field) { struct gprs_sndcp_comp_entity *comp_entity; comp_entity = talloc_zero (NULL, struct gprs_sndcp_comp_entity); @@ -118,26 +118,29 @@ void gprs_sndcp_comp_entities_free (struct llist_head *comp_entities) { - if (comp_entities) { - struct gprs_sndcp_comp_entity *comp_entity; + struct llist_head *lh, *lh2; + struct gprs_sndcp_comp_entity *comp_entity; + if (comp_entities) { llist_for_each_entry (comp_entity, comp_entities, list) { /* Free compression entity */ if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { LOGP (DSNDCP, LOGL_INFO, - "Deleting (free) header compression entity %i ...\n", + "Deleting header compression entity %i ...\n", comp_entity->entity); gprs_sndcp_hdrcomp_term (comp_entity); } else LOGP (DSNDCP, LOGL_INFO, - "Deleting (free) data compression entity %i ...\n", + "Deleting data compression entity %i ...\n", comp_entity->entity); - - talloc_free (comp_entity); } + llist_for_each_safe(lh, lh2, comp_entities) { + llist_del(lh); + talloc_free(lh); + } } } @@ -181,7 +184,7 @@ struct gprs_sndcp_comp_entity * gprs_sndcp_comp_entities_add (struct llist_head - *comp_entities, struct + *comp_entities, const struct gprs_sndcp_comp_field *comp_field) { struct gprs_sndcp_comp_entity *comp_entity; @@ -203,7 +206,7 @@ /* Find compression entity by its entity number */ struct gprs_sndcp_comp_entity * -gprs_sndcp_comp_entity_find_by_entity (struct +gprs_sndcp_comp_entity_find_by_entity (const struct llist_head *comp_entities, int entity) { struct gprs_sndcp_comp_entity *comp_entity; @@ -223,7 +226,7 @@ /* Find which compression entity handles the specified pcomp/dcomp */ struct gprs_sndcp_comp_entity * -gprs_sndcp_comp_entity_find_by_comp (struct +gprs_sndcp_comp_entity_find_by_comp (const struct llist_head *comp_entities, int comp) { struct gprs_sndcp_comp_entity *comp_entity; @@ -246,7 +249,7 @@ /* Find which compression entity handles the specified nsapi */ struct gprs_sndcp_comp_entity * -gprs_sndcp_comp_entity_find_by_nsapi (struct +gprs_sndcp_comp_entity_find_by_nsapi (const struct llist_head *comp_entities, int nsapi) { struct gprs_sndcp_comp_entity *comp_entity; @@ -273,7 +276,7 @@ /* Find a comp_index for a given pcomp/dcomp value */ int -gprs_sndcp_comp_entity_find_comp_index_by_comp (struct +gprs_sndcp_comp_entity_find_comp_index_by_comp (const struct gprs_sndcp_comp_entity *comp_entity, int comp) { @@ -305,7 +308,7 @@ /* Find a pcomp/dcomp value for a given comp_index */ int -gprs_sndcp_comp_entity_find_comp_by_comp_index (struct +gprs_sndcp_comp_entity_find_comp_by_comp_index (const struct gprs_sndcp_comp_entity *comp_entity, int comp_index) { diff --git a/openbsc/src/gprs/gprs_sndcp_hdrcomp.c b/openbsc/src/gprs/gprs_sndcp_hdrcomp.c new file mode 100644 index 0000000..94b9f12 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_hdrcomp.c @@ -0,0 +1,523 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* Enable private debug messages */ +#define GPRS_SNDCP_HDRCOMP_DEBUG 1 + +/* Test RFC1144 implementation + (Caution: GPRS_SNDCP_HDRCOMP_BYPASS in .h file has to be set to 1!) */ +#define GPRS_SNDCP_HDRCOMP_RFC1144_TEST 0 + +/* Exit immediately in case of RFC1144 test failure */ +#define GPRS_SNDCP_HDRCOMP_RFC1144_TEST_EXITONERR 1 + +/* For debug/test only! */ +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST == 1 +static struct slcompress *test_compression_state_tx = NULL; +static struct slcompress *test_compression_state_rx = NULL; +static int test_errors = 0; +static int gprs_sndcp_hdrcomp_test_ind(uint8_t * packet, int packet_len); +static int gprs_sndcp_hdrcomp_test_req(uint8_t * packet, int packet_len); +#endif + + +/* Initalize header compression */ +int gprs_sndcp_hdrcomp_init(struct gprs_sndcp_comp_entity *comp_entity, + const struct gprs_sndcp_comp_field *comp_field) +{ + /* Note: This function is automatically called from + gprs_sndcp_comp_entity.c when a new header compression + entity is created by gprs_sndcp.c */ + + if ((comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + && (comp_entity->algo == RFC_1144)) { + comp_entity->state = + slhc_init(comp_field->rfc1144_params->s01 + 1, + comp_field->rfc1144_params->s01 + 1); + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression initalized.\n"); + return 0; + } + + /* Just in case someone tries to initalize an unknown or unsupported + header compresson. Since everything is checked during the SNDCP + negotiation process, this should never happen! */ + LOGP(DSNDCP, LOGL_ERROR, + "Unknown or unsupported header compression type requested for initalization, could not initalize...\n"); + return -EINVAL; + +} + + +/* Terminate header compression */ +void gprs_sndcp_hdrcomp_term(struct gprs_sndcp_comp_entity *comp_entity) +{ + /* Note: This function is automatically called from + gprs_sndcp_comp_entity.c when a header compression + entity is deleted by gprs_sndcp.c */ + + if ((comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + && (comp_entity->algo == RFC_1144)) { + if (comp_entity->state) { + slhc_free((struct slcompress *) comp_entity-> + state); + comp_entity->state = NULL; + } + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression terminated.\n"); + return; + } + + /* Just in case someone tries to initalize an unknown or unsupported + header compresson. Since everything is checked during the SNDCP + negotiation process, this should never happen! */ + LOGP(DSNDCP, LOGL_ERROR, + "Unknown or unsupported header compression type requested for termiation, could not initalize...\n"); +} + + +/* Display compressor status */ +static void gprs_sndcp_hdrcomp_rfc1144_stat(struct slcompress *comp) +{ + slhc_i_status(comp); + slhc_o_status(comp); +} + + +/* Compress a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_hdrcomp_rfc1144_compress(struct slcompress *comp, + uint8_t * packet, + int packet_len, + int *pcomp_index) +{ + uint8_t *packet_compressed; + uint8_t *packet_compressed_ptr; /* Not used */ + int packet_compressed_len; + + /* Reserve some space for to store the compression result */ + packet_compressed = talloc_zero_size(NULL, packet_len); + + /* Run compressor */ + memcpy(packet_compressed, packet, packet_len); + packet_compressed_len = + slhc_compress(comp, packet, packet_len, + (uint8_t *) packet_compressed, + &packet_compressed_ptr, 0); + + /* Copy back compression result */ + memcpy(packet, packet_compressed, packet_len); + talloc_free(packet_compressed); + + /* Generate pcomp_index */ + if ((packet[0] & SL_TYPE_COMPRESSED_TCP) == SL_TYPE_COMPRESSED_TCP) { + *pcomp_index = 2; + /* Remove tag for compressed TCP, because the packet + type is already define by pcomp */ + // packet[0] &= 0x7F; + } else if ((packet[0] & SL_TYPE_UNCOMPRESSED_TCP) == + SL_TYPE_UNCOMPRESSED_TCP) { + *pcomp_index = 1; + + /* Remove tag for uncompressed TCP, because the + packet type is already define by pcomp */ + packet[0] &= 0x4F; + } else + *pcomp_index = 0; + + return packet_compressed_len; +} + +/* Expand a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_hdrcomp_rfc1144_expand(struct slcompress *comp, + uint8_t * packet, + int packet_len, + int pcomp_index) +{ + int packet_decompressed_len; + int type = -1; + + /* Note: this function should never be called with pcomp_index=0, + since this condition is already filtered + out by gprs_sndcp_hdrcomp_expand() */ + + /* Determine the packet type by the PCOMP index */ + switch (pcomp_index) { + case 1: + type = SL_TYPE_UNCOMPRESSED_TCP; + break; + case 2: + type = SL_TYPE_COMPRESSED_TCP; + break; + } + + /* Restore the original version nibble on + marked uncompressed packets */ + if (type == SL_TYPE_UNCOMPRESSED_TCP) { + LOGP(DSNDCP, LOGL_INFO, + "Uncompressed rfc1144 packet received...\n"); + + + /* Just in case the phone tags uncompressed tcp-packets + (normally this is handled by pcomp so there is + no need for tagging the packets) */ + packet[0] &= 0x4F; + packet_decompressed_len = + slhc_remember(comp, packet, packet_len); + return packet_decompressed_len; + } + + /* Uncompress compressed packets */ + else if (type == SL_TYPE_COMPRESSED_TCP) { + LOGP(DSNDCP, LOGL_INFO, + "Compressed rfc1144 packet received...\n"); + packet_decompressed_len = + slhc_uncompress(comp, packet, packet_len); + return packet_decompressed_len; + } + + + /* Regular or unknown packets will not be touched */ + return packet_len; +} + + +/* Expand header compressed packet */ +int gprs_sndcp_hdrcomp_expand(uint8_t * packet, int packet_len, int pcomp, + const struct llist_head *comp_entities) +{ + int rc; + int pcomp_index = 0; + struct gprs_sndcp_comp_entity *comp_entity; + + /* Skip on pcomp=0 */ + if (pcomp == 0) { + LOGP(DSNDCP, LOGL_INFO, + "Uncompressed packet received (pcomp=0), skipping compression...\n"); + return packet_len; + } + + /* Find out which compression entity handles the packet */ + comp_entity = + gprs_sndcp_comp_entity_find_by_comp(comp_entities, pcomp); + + /* Skip compression if no suitable compression entity can be found! */ + if (comp_entity == NULL) { + LOGP(DSNDCP, LOGL_ERROR, + "Compressed packet received (pcomp=%i) but no suitable compression entity found, skipping compression...\n", + pcomp); + return packet_len; + } + + /* Find pcomp_index */ + pcomp_index = + gprs_sndcp_comp_entity_find_comp_index_by_comp(comp_entity, + pcomp); + +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST == 1 + /* Test mode */ + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_expand(): testing compression...!\n"); + rc = gprs_sndcp_hdrcomp_test_ind(packet, packet_len); +#else + /* Normal operation: */ + rc = gprs_sndcp_hdrcomp_rfc1144_expand((struct slcompress *) + comp_entity->state, packet, + packet_len, pcomp_index); + gprs_sndcp_hdrcomp_rfc1144_stat((struct slcompress *) comp_entity-> + state); +#endif + + LOGP(DSNDCP, LOGL_DEBUG, + "Header expansion done, old length=%i, new length=%i, pcomp=%i, pcomp_index=%i\n", + packet_len, rc, pcomp, pcomp_index); + return rc; +} + + +/* Expand header compressed packet */ +int gprs_sndcp_hdrcomp_compress(uint8_t * packet, int packet_len, + int *pcomp, + const struct llist_head *comp_entities, + int nsapi) +{ + int rc; + int pcomp_index = 0; + struct gprs_sndcp_comp_entity *comp_entity; + + /* Find out which compression entity handles the packet */ + comp_entity = + gprs_sndcp_comp_entity_find_by_nsapi(comp_entities, nsapi); + + /* Skip compression if no suitable compression entity can be found! */ + if (comp_entity == NULL) { + LOGP(DSNDCP, LOGL_INFO, + "No suitable compression entity found for nsapi %i, skipping compression...\n", + nsapi); + *pcomp = 0; + return packet_len; + } +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST == 1 + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_expand(): testing compression...!\n"); + rc = gprs_sndcp_hdrcomp_test_req(packet, packet_len); + *pcomp = 0; + return rc; +#else + /* Normal operation: */ + rc = gprs_sndcp_hdrcomp_rfc1144_compress((struct slcompress *) + comp_entity->state, + packet, packet_len, + &pcomp_index); + gprs_sndcp_hdrcomp_rfc1144_stat((struct slcompress *) comp_entity-> + state); +#endif + + /* Find pcomp value */ + *pcomp = + gprs_sndcp_comp_entity_find_comp_by_comp_index(comp_entity, + pcomp_index); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header compression done, old length=%i, new length=%i, pcomp=%i, pcomp_index=%i\n", + packet_len, rc, *pcomp, pcomp_index); + return rc; +} + + + + + + + +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST == 1 + +/* + * This is a test implementation to make sure the rfc1144 compression + * implementation works as expected. All data is first compressed and + * decompressed on both directions. + */ + +/* FIXME: FOR EXPERIMENTATION ONLY! REMOVE AS SOON AS POSSIBLE */ +static uint16_t header_checksum(uint8_t * iph, unsigned int ihl) +{ + int i; + uint16_t temp; + uint32_t accumulator = 0xFFFF; + + for (i = 0; i < ihl * 2; i++) { + temp = ((*iph) << 8) & 0xFF00; + iph++; + temp |= (*iph) & 0xFF; + iph++; + + accumulator += temp; + if (accumulator > 0xFFFF) { + accumulator++; + accumulator &= 0xFFFF; + } + } + + return (uint16_t) (htons(~accumulator) & 0xFFFF); +} + +/* Check packet integrity */ +static int gprs_sndcp_hdrcomp_test_check_packet(uint8_t * packet, + uint8_t * packet_backup, + int packet_len, + int + packet_len_uncompressed) +{ + uint16_t checksum; + + if (packet_len != packet_len_uncompressed) { + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): Error: Packet length mismatch!\n"); +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST_EXITONERR == 1 + exit(1); +#endif + return -1; + } + + /* Check packet integrety */ + if (memcmp(packet, packet_backup, packet_len)) { + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): Warning: Packet content!\n"); + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): %s\n", + osmo_hexdump_nospc(packet_backup, 80)); + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): %s\n", + osmo_hexdump_nospc(packet, 80)); + + checksum = header_checksum(packet, 5); + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): %04x\n", + checksum); + + if (checksum == 0x0000) { + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): Checksum looks good!\n"); + + if (memcmp + (packet + 20, packet_backup + 20, + packet_len - 20)) + test_errors++; + else + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): Packet looks also good!\n"); + } else { + test_errors++; +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST_EXITONERR == 1 + exit(1); +#endif + return -1; + } + } + + return 0; +} + +/* FIXME: FOR EXPERIMENTATION ONLY! REMOVE AS SOON AS POSSIBLE */ +static int gprs_sndcp_hdrcomp_test_ind(uint8_t * packet, int packet_len) +{ + int packet_len_compressed; + int packet_len_uncompressed; + int pcomp; + uint8_t *packet_backup; + + if (test_compression_state_tx == NULL) + test_compression_state_tx = slhc_init(8, 8); + if (test_compression_state_rx == NULL) + test_compression_state_rx = slhc_init(8, 8); + + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): packet_len=%i\n", packet_len); + packet_backup = talloc_zero_size(NULL, packet_len); + memcpy(packet_backup, packet, packet_len); + + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): IND: %s\n", + osmo_hexdump_nospc(packet, packet_len)); + packet_len_compressed = + gprs_sndcp_hdrcomp_rfc1144_compress(test_compression_state_rx, + packet, packet_len, + &pcomp); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): IND (COMP): %s\n", + osmo_hexdump_nospc(packet, packet_len_compressed)); + packet_len_uncompressed = + gprs_sndcp_hdrcomp_rfc1144_expand(test_compression_state_tx, + packet, + packet_len_compressed, + pcomp); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): IND (DECOMP): %s\n", + osmo_hexdump_nospc(packet, packet_len_uncompressed)); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): packet_len=%i packet_len_compressed=%i packet_len_uncompressed=%i\n", + packet_len, packet_len_compressed, packet_len_uncompressed); + + gprs_sndcp_hdrcomp_test_check_packet(packet, packet_backup, + packet_len, + packet_len_uncompressed); + talloc_free(packet_backup); + gprs_sndcp_hdrcomp_rfc1144_stat(test_compression_state_rx); + gprs_sndcp_hdrcomp_rfc1144_stat(test_compression_state_tx); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): Test errors: %i\n", + test_errors); + return packet_len; +} + +/* FIXME: FOR EXPERIMENTATION ONLY! REMOVE AS SOON AS POSSIBLE */ +static int gprs_sndcp_hdrcomp_test_req(uint8_t * packet, int packet_len) +{ + int packet_len_compressed; + int packet_len_uncompressed; + int pcomp; + uint8_t *packet_backup; + + if (test_compression_state_tx == NULL) + test_compression_state_tx = slhc_init(8, 8); + if (test_compression_state_rx == NULL) + test_compression_state_rx = slhc_init(8, 8); + + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_req(): packet_len=%i\n", packet_len); + packet_backup = talloc_zero_size(NULL, packet_len); + memcpy(packet_backup, packet, packet_len); + + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_req(): REQ: %s\n", + osmo_hexdump_nospc(packet, packet_len)); + packet_len_compressed = + gprs_sndcp_hdrcomp_rfc1144_compress(test_compression_state_tx, + packet, packet_len, + &pcomp); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_req(): REQ (COMP): %s\n", + osmo_hexdump_nospc(packet, packet_len_compressed)); + packet_len_uncompressed = + gprs_sndcp_hdrcomp_rfc1144_expand(test_compression_state_rx, + packet, + packet_len_compressed, + pcomp); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_req(): REQ (DECOMP): %s\n", + osmo_hexdump_nospc(packet, packet_len_uncompressed)); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_req(): packet_len=%i packet_len_compressed=%i packet_len_uncompressed=%i\n", + packet_len, packet_len_compressed, packet_len_uncompressed); + + gprs_sndcp_hdrcomp_test_check_packet(packet, packet_backup, + packet_len, + packet_len_uncompressed); + talloc_free(packet_backup); + gprs_sndcp_hdrcomp_rfc1144_stat(test_compression_state_rx); + gprs_sndcp_hdrcomp_rfc1144_stat(test_compression_state_tx); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): Test errors: %i\n", + test_errors); + return packet_len; +} + +#endif -- To view, visit https://gerrit.osmocom.org/642 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 Gerrit-PatchSet: 6 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter From gerrit-no-reply at lists.osmocom.org Thu Aug 4 09:00:14 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Thu, 4 Aug 2016 09:00:14 +0000 Subject: [PATCH] openbsc[master]: V42BIS integration In-Reply-To: References: Message-ID: Hello Harald Welte, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/644 to look at the new patch set (#8). V42BIS integration The previously committed SPANDSP v42bis implementation has been minimaly edited to fit our needs Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d --- M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/debug.h M openbsc/include/openbsc/v42bis.h R openbsc/include/openbsc/v42bis_private.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/v42bis.c 6 files changed, 116 insertions(+), 12 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/44/644/8 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index e159db5..e404b17 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,8 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h gprs_sndcp_xid.h \ - gprs_sndcp_comp_entity.h gprs_sndcp_hdrcomp.h + gprs_sndcp_comp_entity.h gprs_sndcp_hdrcomp.h v42bis.h \ + v42bis_private.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 90ddca5..f98439f 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -28,7 +28,6 @@ DNS, DBSSGP, DLLC, - DSNDCP, DSLHC, DNAT, DCTRL, @@ -37,6 +36,8 @@ DGTPHUB, DRANAP, DSUA, + DSNDCP, + DV42BIS, Debug_LastEntry, }; diff --git a/openbsc/include/openbsc/v42bis.h b/openbsc/include/openbsc/v42bis.h index f13e5c5..e7592e8 100644 --- a/openbsc/include/openbsc/v42bis.h +++ b/openbsc/include/openbsc/v42bis.h @@ -36,6 +36,8 @@ #if !defined(_SPANDSP_V42BIS_H_) #define _SPANDSP_V42BIS_H_ +#define SPAN_DECLARE(x) x + #define V42BIS_MAX_BITS 12 #define V42BIS_MAX_CODEWORDS 4096 /* 2^V42BIS_MAX_BITS */ #define V42BIS_TABLE_SIZE 5021 /* This should be a prime >(2^V42BIS_MAX_BITS) */ diff --git a/openbsc/include/openbsc/private_v42bis.h b/openbsc/include/openbsc/v42bis_private.h similarity index 100% rename from openbsc/include/openbsc/private_v42bis.h rename to openbsc/include/openbsc/v42bis_private.h diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 3d6c82a..2c03a45 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -22,7 +22,7 @@ osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \ slhc.c gprs_sndcp_xid.c gprs_sndcp_comp_entity.c \ - gprs_sndcp_hdrcomp.c \ + gprs_sndcp_hdrcomp.c v42bis.c \ sgsn_main.c sgsn_vty.c sgsn_libgtp.c \ gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c \ gprs_llc_xid.c crc24.c \ diff --git a/openbsc/src/gprs/v42bis.c b/openbsc/src/gprs/v42bis.c index d8d3f3f..fc42be4 100644 --- a/openbsc/src/gprs/v42bis.c +++ b/openbsc/src/gprs/v42bis.c @@ -31,9 +31,8 @@ /*! \file */ -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif +#define FALSE 0 +#define TRUE 1 #include #include @@ -44,13 +43,9 @@ #include #include -#include "spandsp/telephony.h" -#include "spandsp/logging.h" -#include "spandsp/bit_operations.h" -#include "spandsp/v42bis.h" +#include +#include -#include "spandsp/private/logging.h" -#include "spandsp/private/v42bis.h" /* Fixed parameters from the spec. */ #define V42BIS_N3 8 /* Character size (bits) */ @@ -74,6 +69,111 @@ V42BIS_RESET = 2 /* Force reinitialisation */ }; +/*! \brief Find the bit position of the highest set bit in a word + \param bits The word to be searched + \return The bit number of the highest set bit, or -1 if the word is zero. */ +static __inline__ int top_bit(unsigned int bits) +{ +/* + * Note: This function was taken from spandsp/bit_operations.h + * without modification + */ + +#if defined(SPANDSP_USE_86_ASM) + int res; + + __asm__ (" xorl %[res],%[res];\n" + " decl %[res];\n" + " bsrl %[bits],%[res]\n" + : [res] "=&r" (res) + : [bits] "rm" (bits)); + return res; +#elif defined(__ppc__) || defined(__powerpc__) + int res; + + __asm__ ("cntlzw %[res],%[bits];\n" + : [res] "=&r" (res) + : [bits] "r" (bits)); + return 31 - res; +#elif defined(_M_IX86) + /* Visual Studio i386 */ + __asm + { + xor eax, eax + dec eax + bsr eax, bits + } +#elif defined(_M_X64) + /* Visual Studio x86_64 */ + /* TODO: Need the appropriate x86_64 code */ + int res; + + if (bits == 0) + return -1; + res = 0; + if (bits & 0xFFFF0000) + { + bits &= 0xFFFF0000; + res += 16; + } + if (bits & 0xFF00FF00) + { + bits &= 0xFF00FF00; + res += 8; + } + if (bits & 0xF0F0F0F0) + { + bits &= 0xF0F0F0F0; + res += 4; + } + if (bits & 0xCCCCCCCC) + { + bits &= 0xCCCCCCCC; + res += 2; + } + if (bits & 0xAAAAAAAA) + { + bits &= 0xAAAAAAAA; + res += 1; + } + return res; +#else + int res; + + if (bits == 0) + return -1; + res = 0; + if (bits & 0xFFFF0000) + { + bits &= 0xFFFF0000; + res += 16; + } + if (bits & 0xFF00FF00) + { + bits &= 0xFF00FF00; + res += 8; + } + if (bits & 0xF0F0F0F0) + { + bits &= 0xF0F0F0F0; + res += 4; + } + if (bits & 0xCCCCCCCC) + { + bits &= 0xCCCCCCCC; + res += 2; + } + if (bits & 0xAAAAAAAA) + { + bits &= 0xAAAAAAAA; + res += 1; + } + return res; +#endif +} +/*- End of function --------------------------------------------------------*/ + + static __inline__ void push_compressed_raw_octet(v42bis_compress_state_t *ss, int octet) { ss->output_buf[ss->output_octet_count++] = (uint8_t) octet; -- To view, visit https://gerrit.osmocom.org/644 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d Gerrit-PatchSet: 8 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte From gerrit-no-reply at lists.osmocom.org Thu Aug 4 09:08:19 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Thu, 4 Aug 2016 09:08:19 +0000 Subject: [PATCH] libosmocore[master]: Add function to send TRAP over Control Interface Message-ID: Review at https://gerrit.osmocom.org/649 Add function to send TRAP over Control Interface Change-Id: Ic0b8d88c4f5c4d42c3f8fb754f8eabf049c9e388 Related: OS#1646 --- M include/osmocom/ctrl/control_if.h M src/ctrl/control_if.c 2 files changed, 21 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/49/649/1 diff --git a/include/osmocom/ctrl/control_if.h b/include/osmocom/ctrl/control_if.h index 181c60a..65603d4 100644 --- a/include/osmocom/ctrl/control_if.h +++ b/include/osmocom/ctrl/control_if.h @@ -20,6 +20,7 @@ int ctrl_cmd_send(struct osmo_wqueue *queue, struct ctrl_cmd *cmd); +int ctrl_cmd_send_trap(struct ctrl_handle *ctrl, char *name, char *value); struct ctrl_handle *ctrl_interface_setup(void *data, uint16_t port, ctrl_cmd_lookup lookup); struct ctrl_handle *ctrl_interface_setup_dynip(void *data, diff --git a/src/ctrl/control_if.c b/src/ctrl/control_if.c index 6d9a9fb..aac6239 100644 --- a/src/ctrl/control_if.c +++ b/src/ctrl/control_if.c @@ -117,6 +117,26 @@ return ret; } +/*! \brief Send TRAP over given Control Interface + * \param[in] ctrl Control Interface over which TRAP will be sent + * \param[in] name Name of the TRAP variable + * \param[in] value Value of the TRAP variable + * \return Negative value on error, result of ctrl_cmd_send_to_all() otherwise + */ +int ctrl_cmd_send_trap(struct ctrl_handle *ctrl, char *name, char *value) +{ + struct ctrl_cmd *cmd = ctrl_cmd_create(NULL, CTRL_TYPE_TRAP); + if (!cmd) + return -ENOMEM; + + cmd->id = "0"; /* It's a TRAP! */ + cmd->variable = name; + cmd->reply = value; + int r = ctrl_cmd_send_to_all(ctrl, cmd); + talloc_free(cmd); + return r; +} + struct ctrl_cmd *ctrl_cmd_trap(struct ctrl_cmd *cmd) { struct ctrl_cmd *trap; -- To view, visit https://gerrit.osmocom.org/649 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ic0b8d88c4f5c4d42c3f8fb754f8eabf049c9e388 Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Max From gerrit-no-reply at lists.osmocom.org Thu Aug 4 09:31:25 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Thu, 4 Aug 2016 09:31:25 +0000 Subject: [ABANDON] osmo-bts[master]: Simplify pcu_tx_data_ind() In-Reply-To: References: Message-ID: Max has abandoned this change. Change subject: Simplify pcu_tx_data_ind() ...................................................................... Abandoned -- To view, visit https://gerrit.osmocom.org/611 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: abandon Gerrit-Change-Id: Ib196a36ae2bae36d37144337bed71f40414dbb64 Gerrit-PatchSet: 2 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max From gerrit-no-reply at lists.osmocom.org Thu Aug 4 11:37:51 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 4 Aug 2016 11:37:51 +0000 Subject: openbsc[master]: Improve code re-use In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/631 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I9bad8f0dd1d69bd28816bf047d85840e3411bb9c Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: daniel Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 4 11:38:26 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 4 Aug 2016 11:38:26 +0000 Subject: openbsc[master]: Add python functions to get/set ctrl variables In-Reply-To: References: Message-ID: Patch Set 2: Code-Review+1 -- To view, visit https://gerrit.osmocom.org/645 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I2bc275b801a4b78642653f5b0a91e8cbea25422a Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 4 11:38:54 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 4 Aug 2016 11:38:54 +0000 Subject: openbsc[master]: Add web proxy for control interface In-Reply-To: References: Message-ID: Patch Set 2: Code-Review+1 -- To view, visit https://gerrit.osmocom.org/647 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Id3fc7e6dcf28fe543dc32930e737eae5bc188656 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 4 11:39:52 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 4 Aug 2016 11:39:52 +0000 Subject: libosmocore[master]: Add function to send TRAP over Control Interface In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/649 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ic0b8d88c4f5c4d42c3f8fb754f8eabf049c9e388 Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 4 11:40:36 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 4 Aug 2016 11:40:36 +0000 Subject: libosmocore[master]: Add control interface port for GGSN In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 (1 comment) https://gerrit.osmocom.org/#/c/648/1/include/osmocom/ctrl/ports.h File include/osmocom/ctrl/ports.h: Line 9: #define OSMO_CTRL_PORT_GGSN 4252 please also update osmo-gsm-manuals.git when adding numbers here. -- To view, visit https://gerrit.osmocom.org/648 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ie7232189fe3265a8631fd3652b2c8c152cdee918 Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 4 11:41:40 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 4 Aug 2016 11:41:40 +0000 Subject: libosmocore[master]: Extend L1SAP with Measurements In-Reply-To: References: Message-ID: Patch Set 2: > [...]we do not have to have presence > field for ber/bto/link quality. Shall I add it just in case? no need, we can do without. -- To view, visit https://gerrit.osmocom.org/622 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I2b127eb1856c4cd1bc46490a89592a595f1ee86b Gerrit-PatchSet: 2 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 4 11:41:55 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 4 Aug 2016 11:41:55 +0000 Subject: osmo-pcu[master]: Extend BTS <-> PCU protocol with measurement In-Reply-To: References: Message-ID: Patch Set 2: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/624 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ide0e29b668ee38516605c1763fda85e87e867813 Gerrit-PatchSet: 2 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 4 11:44:46 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 4 Aug 2016 11:44:46 +0000 Subject: osmo-bts[master]: Fill measurements data for L1SAP In-Reply-To: References: Message-ID: Patch Set 4: Code-Review-1 (1 comment) > I'm not sure if we need to bump BTS<->PCU version here - the change > is backward-compatible. Please advice. In which way is it backwards-compatible? Only an old PCU woul work with a new BTS, but not the other way around, right? In that case, the version must be bumped. https://gerrit.osmocom.org/#/c/623/4/include/osmo-bts/pcuif_proto.h File include/osmo-bts/pcuif_proto.h: Line 53: uint16_t ber10k; /*!< \brief BER in units of 0.01% */ all previous struct members are tab-aligned, yours not? -- To view, visit https://gerrit.osmocom.org/623 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ic9693a044756fb1c7bd2ff3cfa0db042c3c4e01c Gerrit-PatchSet: 4 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 4 13:23:48 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Thu, 4 Aug 2016 13:23:48 +0000 Subject: libosmocore[master]: Add control interface port for GGSN In-Reply-To: References: Message-ID: Patch Set 1: Sent to ML as manuals are not part of gerrit yet. -- To view, visit https://gerrit.osmocom.org/648 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ie7232189fe3265a8631fd3652b2c8c152cdee918 Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Max Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 4 14:10:19 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 4 Aug 2016 14:10:19 +0000 Subject: [PATCH] osmo-bts[master]: osmo-bts-trx: Fix PCS1900 operation Message-ID: Review at https://gerrit.osmocom.org/650 osmo-bts-trx: Fix PCS1900 operation As the ARFCN numbers in DCS (1800) and PCS (1900) are not unique, we need to specify the band in the upper bits of the ARFCN value before calling gsm_arfcn2freq10(). Change-Id: I637b76bc1fc749eed8e364412d76606589991c02 --- M src/osmo-bts-trx/trx_if.c 1 file changed, 12 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/50/650/1 diff --git a/src/osmo-bts-trx/trx_if.c b/src/osmo-bts-trx/trx_if.c index bef6c09..42d383c 100644 --- a/src/osmo-bts-trx/trx_if.c +++ b/src/osmo-bts-trx/trx_if.c @@ -288,11 +288,16 @@ int trx_if_cmd_rxtune(struct trx_l1h *l1h, uint16_t arfcn) { + struct phy_instance *pinst = l1h->phy_inst; uint16_t freq10; + + if (pinst->trx->bts->band == GSM_BAND_1900) + arfcn |= ARFCN_PCS; freq10 = gsm_arfcn2freq10(arfcn, 1); /* RX = uplink */ if (freq10 == 0xffff) { - LOGP(DTRX, LOGL_ERROR, "Arfcn %d not defined.\n", arfcn); + LOGP(DTRX, LOGL_ERROR, "Arfcn %d not defined.\n", + arfcn & ~ARFCN_FLAG_MASK); return -ENOTSUP; } @@ -301,11 +306,16 @@ int trx_if_cmd_txtune(struct trx_l1h *l1h, uint16_t arfcn) { + struct phy_instance *pinst = l1h->phy_inst; uint16_t freq10; + + if (pinst->trx->bts->band == GSM_BAND_1900) + arfcn |= ARFCN_PCS; freq10 = gsm_arfcn2freq10(arfcn, 0); /* TX = downlink */ if (freq10 == 0xffff) { - LOGP(DTRX, LOGL_ERROR, "Arfcn %d not defined.\n", arfcn); + LOGP(DTRX, LOGL_ERROR, "Arfcn %d not defined.\n", + arfcn & ~ARFCN_FLAG_MASK); return -ENOTSUP; } -- To view, visit https://gerrit.osmocom.org/650 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I637b76bc1fc749eed8e364412d76606589991c02 Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Harald Welte From gerrit-no-reply at lists.osmocom.org Thu Aug 4 14:10:19 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 4 Aug 2016 14:10:19 +0000 Subject: [PATCH] osmo-bts[master]: osmo-bts-trx: log decoder bit errors as DEBUG, not NOTICE Message-ID: Review at https://gerrit.osmocom.org/651 osmo-bts-trx: log decoder bit errors as DEBUG, not NOTICE It is not an exceptional situation if the air-interface is experiencing non-recoverable decoding errors. At bad signal conditions and/or interference, this is perfectly normal. Let's use DEBUG instead of NOTICE log level. Change-Id: Ifd39c53ec22f57cdb5299e5d76ff6ff1482d3beb --- M src/osmo-bts-trx/scheduler_trx.c 1 file changed, 1 insertion(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/51/651/1 diff --git a/src/osmo-bts-trx/scheduler_trx.c b/src/osmo-bts-trx/scheduler_trx.c index 3a6ede3..693bf61 100644 --- a/src/osmo-bts-trx/scheduler_trx.c +++ b/src/osmo-bts-trx/scheduler_trx.c @@ -875,7 +875,7 @@ /* decode */ rc = xcch_decode(l2, *bursts_p, &n_errors, &n_bits_total); if (rc) { - LOGP(DL1C, LOGL_NOTICE, "Received bad data frame at fn=%u " + LOGP(DL1C, LOGL_DEBUG, "Received bad data frame at fn=%u " "(%u/%u) for %s\n", *first_fn, (*first_fn) % l1ts->mf_period, l1ts->mf_period, trx_chan_desc[chan].name); -- To view, visit https://gerrit.osmocom.org/651 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ifd39c53ec22f57cdb5299e5d76ff6ff1482d3beb Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Harald Welte From gerrit-no-reply at lists.osmocom.org Thu Aug 4 14:17:00 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Thu, 4 Aug 2016 14:17:00 +0000 Subject: [PATCH] openbsc[master]: Added SNDCP-XID encoder / decoder In-Reply-To: References: Message-ID: Hello Harald Welte, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/641 to look at the new patch set (#5). Added SNDCP-XID encoder / decoder The SNDCP-XID (or layer-3 xid) is used to exchange layer-3 parameters such as compression. The encoder encodes a bytestream that is then sent as regular XID field from LLC. We will need the SNDCP-XID to negotiate the parameters for our upcomming GPRS data and header compression features Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e --- M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_sndcp_xid.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_sndcp_xid.c 4 files changed, 2,201 insertions(+), 3 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/41/641/5 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 9e8c554..b37103f 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,7 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h + gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h gprs_sndcp_xid.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_sndcp_xid.h b/openbsc/include/openbsc/gprs_sndcp_xid.h new file mode 100644 index 0000000..9068152 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_xid.h @@ -0,0 +1,201 @@ +#ifndef _GPRS_SNDCP_XID_H +#define _GPRS_SNDCP_XID_H + +#include +#include + +#define CURRENT_SNDCP_VERSION 0 /* See TS 144 065, clause 8 */ +#define MAX_ENTITIES 32 /* TS 144 065 reserves 5 bit for compr. entity num. */ + +/* According to: TS 144 065 6.5.1.1 Format of the protocol control information + compression field (Figure 7) + + TS 144 065 6.6.1.1 Format of the data compression + field (Figure 9) */ + +struct gprs_sndcp_comp_field { + struct llist_head list; + + /* Propose bit (P), see also: 6.5.1.1.2 and 6.6.1.1.2 */ + unsigned int p; + + /* Entity number, see also: 6.5.1.1.3 and 6.6.1.1.3 */ + unsigned int entity; + + /* Algorithm identifier, see also: 6.5.1.1.4 and 6.6.1.1.4 */ + int algo; + + /* Number of contained PCOMP / DCOMP values */ + unsigned int comp_len; + + /* PCOMP / DCOMP values, see also: 6.5.1.1.5 and 6.6.1.1.5 */ + unsigned int comp[16]; + + /* Note: Only one of the following struct pointers may, + be used unused pointers must be set to NULL! */ + struct gprs_sndcp_hdrcomp_rfc1144_params *rfc1144_params; + struct gprs_sndcp_hdrcomp_rfc2507_params *rfc2507_params; + struct gprs_sndcp_hdrcomp_rohc_params *rohc_params; + struct gprs_sndcp_datacomp_v42bis_params *v42bis_params; + struct gprs_sndcp_datacomp_v44_params *v44_params; +}; + +/* According to: TS 144 065 6.5.1.1.4 Algorithm identifier */ +enum gprs_sndcp_hdr_comp_algo { + RFC_1144 = 0, /* TCP/IP header compression, see also 6.5.2 */ + RFC_2507 = 1, /* TCP/UDP/IP header compression, see also: 6.5.3 */ + ROHC = 2, /* Robust Header Compression, see also 6.5.4 */ +}; + +/* According to: TS 144 065 6.5.1.1.4 Algorithm identifier */ +enum gprs_sndcp_data_comp_algo { + V42BIS = 0, /* V42bis data compression, see also 6.6.2 */ + V44 = 1, /* V44 data compression, see also: 6.6.3 */ +}; + +/* According to: TS 144 065 8 SNDCP XID parameters */ +enum gprs_sndcp_xid_param_types { + SNDCP_XID_VERSION_NUMBER = 0, + SNDCP_XID_DATA_COMPRESSION = 1, /* See also: subclause 6.6.1 */ + SNDCP_XID_PROTOCOL_COMPRESSION = 2, /* See also: subclause 6.5.1 */ +}; + +/* According to: TS 144 065 6.5.2.1 Parameters (Table 5) */ +struct gprs_sndcp_hdrcomp_rfc1144_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int s01; /* (default 15) */ +}; + +/* According to: TS 144 065 6.5.2.2 Assignment of PCOMP values */ +enum gprs_sndcp_hdrcomp_rfc1144_pcomp { + RFC1144_PCOMP1 = 0, /* Uncompressed TCP */ + RFC1144_PCOMP2 = 1, /* Compressed TCP */ + RFC1144_PCOMP_NUM = 2 /* Number of pcomp values */ +}; + + + +/* According to: TS 144 065 6.5.3.1 Parameters (Table 6) */ +struct gprs_sndcp_hdrcomp_rfc2507_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int f_max_period; /* (default 256) */ + int f_max_time; /* (default 5) */ + int max_header; /* (default 168) */ + int tcp_space; /* (default 15) */ + int non_tcp_space; /* (default 15) */ +}; + +/* According to: TS 144 065 6.5.3.2 Assignment of PCOMP values for RFC2507 */ +enum gprs_sndcp_hdrcomp_rfc2507_pcomp { + RFC2507_PCOMP1 = 0, /* Full Header */ + RFC2507_PCOMP2 = 1, /* Compressed TCP */ + RFC2507_PCOMP3 = 2, /* Compressed TCP non delta */ + RFC2507_PCOMP4 = 3, /* Compressed non TCP */ + RFC2507_PCOMP5 = 4, /* Context state */ + RFC2507_PCOMP_NUM = 5 /* Number of pcomp values */ +}; + + + +/* According to: TS 144 065 6.5.4.1 Parameter (Table 10) */ +struct gprs_sndcp_hdrcomp_rohc_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int max_cid; /* (default 15) */ + int max_header; /* (default 168) */ + unsigned int profile_len; /* (default 1) */ + uint16_t profile[16]; /* (default 0, ROHC uncompressed) */ +}; + +/* According to: TS 144 065 6.5.4.2 Assignment of PCOMP values for ROHC */ +enum gprs_sndcp_hdrcomp_rohc_pcomp { + ROHC_PCOMP1 = 0, /* ROHC small CIDs */ + ROHC_PCOMP2 = 1, /* ROHC large CIDs */ + ROHC_PCOMP_NUM = 2 /* Number of pcomp values */ +}; + +/* ROHC compression profiles, see also: + http://www.iana.org/assignments/rohc-pro-ids/rohc-pro-ids.xhtml */ +enum gprs_sndcp_xid_rohc_profiles { + ROHC_UNCOMPRESSED = 0x0000, /* ROHC uncompressed [RFC5795] */ + ROHC_RTP = 0x0001, /* ROHC RTP [RFC3095] */ + ROHCV2_RTP = 0x0101, /* ROHCv2 RTP [RFC5225] */ + ROHC_UDP = 0x0002, /* ROHC UDP [RFC3095] */ + ROHCv2_UDP = 0x0102, /* ROHCv2 UDP [RFC5225] */ + ROHC_ESP = 0x0003, /* ROHC ESP [RFC3095] */ + ROHCV2_ESP = 0x0103, /* ROHCv2 ESP [RFC5225] */ + ROHC_IP = 0x0004, /* ROHC IP [RFC3843] */ + ROHCV2_IP = 0x0104, /* ROHCv2 IP [RFC5225] */ + ROHC_LLA = 0x0005, /* ROHC LLA [RFC4362] */ + ROHC_LLA_WITH_R_MODE = 0x0105, /* ROHC LLA with R-mode [RFC3408] */ + ROHC_TCP = 0x0006, /* ROHC TCP [RFC6846] */ + ROHC_RTP_UDP_LITE = 0x0007, /* ROHC RTP/UDP-Lite [RFC4019] */ + ROHCV2_RTP_UDP_LITE = 0x0107, /* ROHCv2 RTP/UDP-Lite [RFC5225] */ + ROHC_UDP_LITE = 0x0008, /* ROHC UDP-Lite [RFC4019] */ + ROHCV2_UDP_LITE = 0x0108, /* ROHCv2 UDP-Lite [RFC5225] */ +}; + + + +/* According to: TS 144 065 6.6.2.1 Parameters (Table 7a) */ +struct gprs_sndcp_datacomp_v42bis_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int p0; /* (default 3) */ + int p1; /* (default 2048) */ + int p2; /* (default 20) */ + +}; + +/* According to: ETSI TS 144 065 6.6.2.2 Assignment of DCOMP values */ +enum gprs_sndcp_datacomp_v42bis_dcomp { + V42BIS_DCOMP1 = 0, /* V42bis enabled */ + V42BIS_DCOMP_NUM = 1 /* Number of dcomp values */ +}; + + + +/* According to: TS 144 065 6.6.3.1 Parameters (Table 7c) */ +struct gprs_sndcp_datacomp_v44_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int c0; /* (default 10000000) */ + int p0; /* (default 3) */ + int p1t; /* Refer to subclause 6.6.3.1.4 */ + int p1r; /* Refer to subclause 6.6.3.1.5 */ + int p3t; /* (default 3 x p1t) */ + int p3r; /* (default 3 x p1r) */ +}; + +/* According to: ETSI TS 144 065 6.6.3.2 Assignment of DCOMP values */ +enum gprs_sndcp_datacomp_v44_dcomp { + V44_DCOMP1 = 0, /* Packet method compressed */ + V44_DCOMP2 = 1, /* Multi packet method compressed */ + V44_DCOMP_NUM = 2 /* Number of dcomp values */ +}; + +/* Transform a list with compression fields into an SNDCP-XID message (dst) */ +int gprs_sndcp_compile_xid(const struct llist_head *comp_fields, uint8_t *dst, + unsigned int dst_maxlen); + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +int gprs_sndcp_parse_xid(struct llist_head *comp_fields, + const uint8_t *src, unsigned int src_len, + const struct llist_head *comp_fields_req); + +/* Free a list with SNDCP-XID fields */ +void gprs_sndcp_free_comp_fields(struct llist_head *comp_fields); + +/* Find out to which compression class the specified comp-field belongs + (header compression or data compression?) */ +int gprs_sndcp_get_compression_class(const struct gprs_sndcp_comp_field + *comp_field); + +/* Dump a list with SNDCP-XID fields (Debug) */ +void gprs_sndcp_dump_comp_fields(const struct llist_head *comp_fields, + unsigned int logl); + + +#endif diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index b3a5137..67e9943 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -21,7 +21,7 @@ $(OSMO_LIBS) $(LIBCRYPTO_LIBS) -lrt osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \ - slhc.c \ + slhc.c gprs_sndcp_xid.c \ sgsn_main.c sgsn_vty.c sgsn_libgtp.c \ gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c \ gprs_llc_xid.c crc24.c \ @@ -32,7 +32,7 @@ osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ - $(LIBCRYPTO_LIBS) -lrt + $(LIBCRYPTO_LIBS) -lrt -lm osmo_gtphub_SOURCES = gtphub_main.c gtphub.c gtphub_sock.c gtphub_ares.c \ gtphub_vty.c sgsn_ares.c gprs_utils.c diff --git a/openbsc/src/gprs/gprs_sndcp_xid.c b/openbsc/src/gprs/gprs_sndcp_xid.c new file mode 100644 index 0000000..1bf1a03 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_xid.c @@ -0,0 +1,1997 @@ +/* GPRS SNDCP XID field encoding/decoding as per 3GPP TS 144 065 */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* When the propose bit in an SNDCP-XID compression field is set to zero, + the algorithm identifier is stripped. The algoritm parameters are specific + for each algorithms. The following struct is used to pass the information + about the referenced algorithm to the parser. */ +struct gprs_sndcp_hdrcomp_entity_algo_table { + unsigned int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + unsigned int algo; /* see also: 6.5.1.1.4 and 6.6.1.1.4 */ + unsigned int compclass; /* Can be either SNDCP_XID_DATA_COMPRESSION or + SNDCP_XID_PROTOCOL_COMPRESSION */ +}; + +/* + * FUNCTIONS RELATED TO SNDCP-XID ENCODING + */ + +/* Encode applicable sapis (works the same in all three compression schemes) */ +static int encode_hdrcomp_applicable_sapis(uint8_t * dst, + const unsigned int *nsapis, + unsigned int nsapis_len) +{ + /* + * NOTE: Buffer *dst needs offer at 2 bytes + * of space to store the generation results + */ + + uint16_t blob; + unsigned int nsapi; + int i; + + /* Encode applicable SAPIs */ + blob = 0; + for (i = 0; i < nsapis_len; i++) { + nsapi = nsapis[i]; + /* + * Only NSAPI 5 to 15 are applicable for user traffic (PDP- + * contexts). Only for these NSAPIs SNDCP-XID parameters + * can apply. See also ETSI TS 144 065 5.1 Service primitives + */ + if ((nsapi < 5) || (nsapi > 15)) + return -EINVAL; + blob |= (1 << nsapi); + } + + /* Store result */ + *dst = (blob >> 8) & 0xFF; + dst++; + *dst = blob & 0xFF; + + return 2; +} + + +/* + * Encode rfc1144 parameter field + * (see also: ETSI TS 144 065 6.5.2.1, Table 5) + */ +static int encode_hdrcomp_rfc1144_params(uint8_t * dst, + unsigned int dst_maxlen, + const struct + gprs_sndcp_hdrcomp_rfc1144_params + *params) +{ + /* + * NOTE: Buffer *dst should offer at least 3 bytes + * of space to store the generation results + */ + + int dst_counter = 0; + int rc; + + /* Exit immediately if no source struct is available */ + if (!params) + return -EINVAL; + + /* Exit immediately if no sufficient memory space is supplied */ + if ((dst_maxlen < 3) || !dst) + return -EINVAL; + + /* + * Exit if number of possible nsapis exceeds valid range + * (Only 11 nsapis possible for PDP-Contexts) + */ + if ((params->nsapi_len < 0) || (params->nsapi_len > 11)) + return -EINVAL; + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_hdrcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode s01 (see also: ETSI TS 144 065 6.5.2.1, Table 5) */ + *dst = params->s01; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + + +/* + * Encode rfc2507 parameter field + * (see also: ETSI TS 144 065 6.5.3.1, Table 6) + */ +static int encode_hdrcomp_rfc2507_params(uint8_t * dst, + unsigned int dst_maxlen, + const struct + gprs_sndcp_hdrcomp_rfc2507_params + *params) +{ + /* + * NOTE: Buffer *dst should offer at least 3 bytes + * of space to store the generation results + */ + + int dst_counter = 0; + int rc; + + /* Exit immediately if no source struct is available */ + if (!params) + return -EINVAL; + + /* Exit immediately if no sufficient memory space is supplied */ + if ((dst_maxlen < 9) || !dst) + return -EINVAL; + + /* + * Exit if number of possible nsapis exceeds valid range + * (Only 11 nsapis possible for PDP-Contexts) + */ + if ((params->nsapi_len < 0) || (params->nsapi_len > 11)) + return -EINVAL; + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_hdrcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode F_MAX_PERIOD (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + if ((params->f_max_period < 1) || (params->f_max_period > 65535)) + return -EINVAL; + *dst = (params->f_max_period >> 8) & 0xFF; + dst++; + dst_counter++; + *dst = (params->f_max_period) & 0xFF; + dst++; + dst_counter++; + + /* Encode F_MAX_TIME (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + if ((params->f_max_time < 1) || (params->f_max_time > 255)) + return -EINVAL; + *dst = params->f_max_time; + dst++; + dst_counter++; + + /* Encode MAX_HEADER (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + if ((params->max_header < 60) || (params->max_header > 255)) + return -EINVAL; + *dst = params->max_header; + dst++; + dst_counter++; + + /* Encode TCP_SPACE (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + if ((params->tcp_space < 3) || (params->tcp_space > 255)) + return -EINVAL; + *dst = params->tcp_space; + dst++; + dst_counter++; + + /* Encode NON_TCP_SPACE (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + if ((params->non_tcp_space < 3) || (params->tcp_space > 65535)) + return -EINVAL; + *dst = (params->non_tcp_space >> 8) & 0xFF; + dst++; + dst_counter++; + *dst = (params->non_tcp_space) & 0xFF; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + + +/* + * Encode ROHC parameter field + * (see also: ETSI TS 144 065 6.5.4.1, Table 10) + */ +static int encode_hdrcomp_rohc_params(uint8_t * dst, + unsigned int dst_maxlen, const struct + gprs_sndcp_hdrcomp_rohc_params + *params) +{ + /* + * NOTE: Buffer *dst should offer at least 36 + * (2 * 16 Profiles + 2 * 3 Parameter) bytes + * of memory space to store generation results + */ + + int i; + int dst_counter = 0; + int rc; + + /* Exit immediately if no source struct is available */ + if (!params) + return -EINVAL; + + /* Exit immediately if no sufficient memory space is supplied */ + if ((dst_maxlen < 38) || !dst) + return -EINVAL; + + /* + * Exit if number of possible nsapis exceeds valid range + * (Only 11 nsapis possible for PDP-Contexts) + */ + if ((params->nsapi_len < 0) || (params->nsapi_len > 11)) + return -EINVAL; + + /* + * Exit if number of ROHC profiles exceeds limit + * (ROHC supports only a maximum of 16 different profiles) + */ + if ((params->profile_len < 0) || (params->profile_len > 16)) + return -EINVAL; + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_hdrcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode MAX_CID (see also: ETSI TS 144 065 6.5.4.1, Table 10) */ + if ((params->max_cid < 0) || (params->max_cid > 16383)) + return -EINVAL; + *dst = (params->max_cid >> 8) & 0xFF; + dst++; + *dst = params->max_cid & 0xFF; + dst++; + dst_counter += 2; + + /* Encode MAX_HEADER (see also: ETSI TS 144 065 6.5.4.1, Table 10) */ + if ((params->max_header < 60) || (params->max_header > 255)) + return -EINVAL; + *dst = (params->max_header >> 8) & 0xFF; + dst++; + *dst = params->max_header & 0xFF; + dst++; + dst_counter += 2; + + /* Encode ROHC Profiles (see also: ETSI TS 144 065 6.5.4.1, Table 10) */ + for (i = 0; i < params->profile_len; i++) { + *dst = (params->profile[i] >> 8) & 0xFF; + dst++; + *dst = params->profile[i] & 0xFF; + dst++; + dst_counter += 2; + } + + /* Return generated length */ + return dst_counter; +} + + +/* + * Encode V42bis parameter field + * (see also: ETSI TS 144 065 6.6.2.1, Table 7a) + */ +static int encode_datacomp_v42bis_params(uint8_t * dst, + unsigned int dst_maxlen, + const struct + gprs_sndcp_datacomp_v42bis_params + *params) +{ + /* + * NOTE: Buffer *dst should offer at least 6 bytes + * of space to store the generation results + */ + + int dst_counter = 0; + int rc; + + /* Exit immediately if no source struct is available */ + if (!params) + return -EINVAL; + + /* Exit immediately if no sufficient memory space is supplied */ + if ((dst_maxlen < 6) || !dst) + return -EINVAL; + + /* + * Exit if number of possible nsapis exceeds valid range + * (Only 11 nsapis possible for PDP-Contexts) + */ + if ((params->nsapi_len < 0) || (params->nsapi_len > 11)) + return -EINVAL; + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_hdrcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode P0 (see also: ETSI TS 144 065 6.6.2.1, Table 7a) */ + if ((params->p0 < 0) || (params->p0 > 3)) + return -EINVAL; + *dst = params->p0 & 0x03; + dst++; + dst_counter++; + + /* Encode P1 (see also: ETSI TS 144 065 6.6.2.1, Table 7a) */ + if ((params->p1 < 512) || (params->p1 > 65535)) + return -EINVAL; + *dst = (params->p1 >> 8) & 0xFF; + dst++; + *dst = params->p1 & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P2 (see also: ETSI TS 144 065 6.6.2.1, Table 7a) */ + if ((params->p2 < 6) || (params->p2 > 250)) + return -EINVAL; + *dst = params->p2; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + + +/* + * Encode V44 parameter field + * (see also: ETSI TS 144 065 6.6.3.1, Table 7c) + */ +static int encode_datacomp_v44_params(uint8_t * dst, + unsigned int dst_maxlen, const struct + gprs_sndcp_datacomp_v44_params + *params) +{ + /* + * NOTE: Buffer *dst should offer at least 12 bytes + * of space to store the generation results + */ + + int dst_counter = 0; + int rc; + + /* Exit immediately if no source struct is available */ + if (!params) + return -EINVAL; + + /* Exit immediately if no sufficient memory space is supplied */ + if ((dst_maxlen < 12) || !dst) + return -EINVAL; + + /* + * Exit if number of possible nsapis exceeds valid range + * (Only 11 nsapis possible for PDP-Contexts) + */ + if ((params->nsapi_len < 0) || (params->nsapi_len > 11)) + return -EINVAL; + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_hdrcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode C0 (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + if ((params->c0 == 0x80) || (params->c0 == 0xC0)) { + *dst = params->c0 & 0xC0; + dst++; + dst_counter++; + } else + return -EINVAL; + + /* Encode P0 (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + if ((params->p0 < 0) || (params->p0 > 3)) + return -EINVAL; + *dst = params->p0 & 0x03; + dst++; + dst_counter++; + + /* Encode P1T (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + if ((params->p1t < 256) || (params->p1t > 65535)) + return -EINVAL; + *dst = (params->p1t >> 8) & 0xFF; + dst++; + *dst = params->p1t & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P1R (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + if ((params->p1r < 256) || (params->p1r > 65535)) + return -EINVAL; + *dst = (params->p1r >> 8) & 0xFF; + dst++; + *dst = params->p1r & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P3T (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + if ((params->p3t < 0) || (params->p3t > 65535)) + return -EINVAL; + if (params->p3t < 2 * params->p1t) + return -EINVAL; + *dst = (params->p3t >> 8) & 0xFF; + dst++; + *dst = params->p3t & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P3R (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + if ((params->p3r < 0) || (params->p3r > 65535)) + return -EINVAL; + if (params->p3r < 2 * params->p1r) + return -EINVAL; + *dst = (params->p3r >> 8) & 0xFF; + dst++; + *dst = params->p3r & 0xFF; + dst++; + dst_counter += 2; + + /* Return generated length */ + return dst_counter; +} + + +/* + * Encode data or protocol control information compression field + * (see also: ETSI TS 144 065 6.6.1.1, Figure 9 and + * ETSI TS 144 065 6.5.1.1, Figure 7) + */ +static int encode_comp_field(uint8_t * dst, unsigned int dst_maxlen, + const struct gprs_sndcp_comp_field + *comp_field) +{ + int dst_counter = 0; + int len; + int expected_length; + int i; + + uint8_t payload_bytes[256]; + int payload_bytes_len = -1; + + /* If possible, try do encode payload bytes first */ + if (comp_field->rfc1144_params) + payload_bytes_len = + encode_hdrcomp_rfc1144_params(payload_bytes, + sizeof(payload_bytes), + comp_field-> + rfc1144_params); + else if (comp_field->rfc2507_params) + payload_bytes_len = + encode_hdrcomp_rfc2507_params(payload_bytes, + sizeof(payload_bytes), + comp_field-> + rfc2507_params); + else if (comp_field->rohc_params) + payload_bytes_len = + encode_hdrcomp_rohc_params(payload_bytes, + sizeof(payload_bytes), + comp_field->rohc_params); + else if (comp_field->v42bis_params) + payload_bytes_len = + encode_datacomp_v42bis_params(payload_bytes, + sizeof(payload_bytes), + comp_field-> + v42bis_params); + else if (comp_field->v44_params) + payload_bytes_len = + encode_datacomp_v44_params(payload_bytes, + sizeof(payload_bytes), + comp_field->v44_params); + else + return -EINVAL; + + /* Exit immediately if payload byte generation failed */ + if (payload_bytes_len < 0) + return -EINVAL; + + /* Exit immediately if no source struct is available */ + if (!comp_field) + return -EINVAL; + + /* Check if comp_len is within bounds */ + if ((comp_field->comp_len < 0) || (comp_field->comp_len > 16)) + return -EINVAL; + + /* Calculate length field of the data block */ + if (comp_field->p) { + len = + payload_bytes_len + + ceil((double) (comp_field->comp_len) / 2.0); + expected_length = len + 3; + } else { + len = payload_bytes_len; + expected_length = len + 2; + } + + /* Exit immediately if no sufficient memory space is supplied */ + if ((dst_maxlen < expected_length) || !dst) + return -EINVAL; + + /* Check if the entity number is within bounds */ + if ((comp_field->entity < 0) || (comp_field->entity > 0x1f)) + return -EINVAL; + + /* Check if the algorithm number is within bounds */ + if ((comp_field->algo < 0) || (comp_field->algo > 0x1f)) + return -EINVAL; + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode Propose bit */ + if (comp_field->p) + *dst |= (1 << 7); + + /* Encode entity number */ + *dst |= comp_field->entity & 0x1F; + dst++; + dst_counter++; + + /* Encode algorithm number */ + if (comp_field->p) { + *dst |= comp_field->algo & 0x1F; + dst++; + dst_counter++; + } + + /* Encode length field */ + *dst |= len & 0xFF; + dst++; + dst_counter++; + + /* Encode PCOMP/DCOMP values */ + if (comp_field->p) { + for (i = 0; i < comp_field->comp_len; i++) { + /* Check if submitted PCOMP/DCOMP + values are within bounds */ + if ((comp_field->comp[i] < 0) + || (comp_field->comp[i] > 0x0F)) + return -EINVAL; + + if (i & 1) { + *dst |= comp_field->comp[i] & 0x0F; + dst++; + dst_counter++; + } else + *dst |= (comp_field->comp[i] << 4) & 0xF0; + } + + if (i & 1) { + dst++; + dst_counter++; + } + } + + /* Append payload bytes */ + memcpy(dst, payload_bytes, payload_bytes_len); + dst_counter += payload_bytes_len; + + /* Return generated length */ + return dst_counter; +} + + +/* Find out to which compression class the specified comp-field belongs + (header compression or data compression?) */ +int gprs_sndcp_get_compression_class(const struct gprs_sndcp_comp_field + *comp_field) +{ + if (comp_field->rfc1144_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->rfc2507_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->rohc_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->v42bis_params) + return SNDCP_XID_DATA_COMPRESSION; + else if (comp_field->v44_params) + return SNDCP_XID_DATA_COMPRESSION; + else + return -EINVAL; +} + + +/* Convert all compression fields to bytstreams */ +static int gprs_sndcp_pack_fields(const struct llist_head *comp_fields, + uint8_t * dst, + unsigned int dst_maxlen, int class) +{ + struct gprs_sndcp_comp_field *comp_field; + int byte_counter = 0; + int rc; + + llist_for_each_entry(comp_field, comp_fields, list) { + if (class == gprs_sndcp_get_compression_class(comp_field)) { + rc = encode_comp_field(dst + byte_counter, + dst_maxlen - byte_counter, + comp_field); + + /* Immediately stop on error */ + if (rc < 0) + return rc; + + byte_counter += rc; + } + } + + /* Return generated length */ + return byte_counter; +} + + +/* Transform a list with compression fields into an SNDCP-XID message (dst) */ +int gprs_sndcp_compile_xid(const struct llist_head *comp_fields, + uint8_t * dst, unsigned int dst_maxlen) +{ + int rc; + int byte_counter = 0; + uint8_t comp_bytes[512]; + uint8_t xid_version_number[1] = { CURRENT_SNDCP_VERSION }; + + /* Exit immediately if no sufficient memory space is supplied */ + if ((dst_maxlen < 2 + sizeof(xid_version_number)) || !dst) + return -EINVAL; + + /* Prepend header */ + dst = + tlv_put(dst, SNDCP_XID_VERSION_NUMBER, + sizeof(xid_version_number), xid_version_number); + byte_counter += (sizeof(xid_version_number) + 2); + + /* Add data compression fields */ + rc = gprs_sndcp_pack_fields(comp_fields, comp_bytes, + sizeof(comp_bytes), + SNDCP_XID_DATA_COMPRESSION); + if (rc < 0) + return rc; + else if (rc > 0) { + dst = + tlv_put(dst, SNDCP_XID_DATA_COMPRESSION, rc, + comp_bytes); + byte_counter += rc + 2; + } + + /* Add header compression fields */ + rc = gprs_sndcp_pack_fields(comp_fields, comp_bytes, + sizeof(comp_bytes), + SNDCP_XID_PROTOCOL_COMPRESSION); + if (rc < 0) + return rc; + else if (rc > 0) { + dst = + tlv_put(dst, SNDCP_XID_PROTOCOL_COMPRESSION, rc, + comp_bytes); + byte_counter += rc + 2; + } + + /* Return generated length */ + return byte_counter; +} + + + + + + + + + + +/* + * FUNCTIONS RELATED TO SNDCP-XID DECODING + */ + +/* Decode applicable sapis (works the same in all three compression schemes) */ +static int decode_hdrcomp_applicable_sapis(const uint8_t * src, + unsigned int src_len, + unsigned int *nsapis, + unsigned int *nsapis_len) +{ + uint16_t blob; + int i; + int nsapi_len = 0; + + /* Exit immediately if no result can be stored */ + if (!nsapis) + return -EINVAL; + + /* Exit immediately if not enough input data is available */ + if (src_len < 2) + return -EINVAL; + + /* Read bitmask */ + blob = *src; + blob = (blob << 8) & 0xFF00; + src++; + blob |= (*src) & 0xFF; + blob = (blob >> 5); + + /* Decode applicable SAPIs */ + for (i = 0; i < 15; i++) { + if ((blob >> i) & 1) { + nsapis[nsapi_len] = i + 5; + nsapi_len++; + } + } + + /* Return consumed length */ + *nsapis_len = nsapi_len; + return 2; +} + +/* Decode 16 bit field */ +static int decode_hdrcomp_16_bit_field(const uint8_t * src, + unsigned int src_len, + int value_min, int value_max, + int *value_int, + uint16_t * value_uint16) +{ + uint16_t blob; + + /* Reset values to zero (just to be sure) */ + if (value_int) + *value_int = -1; + if (value_uint16) + *value_uint16 = 0; + + /* Exit if not enough src are available */ + if (src_len < 2) + return -EINVAL; + + /* Decode bit value */ + blob = *src; + blob = (blob << 8) & 0xFF00; + src++; + blob |= *src; + + /* Check if parsed value is within bounds */ + if (blob < value_min) + return -EINVAL; + if (blob > value_max) + return -EINVAL; + + /* Hand back results to the caller */ + if (value_int) + *value_int = blob; + if (value_uint16) + *value_uint16 = blob; + + /* Return consumed length */ + return 2; +} + +/* Decode 8 bit field */ +static int decode_hdrcomp_8_bit_field(const uint8_t * src, + unsigned int src_len, + int value_min, int value_max, + int *value_int, + uint8_t * value_uint8) +{ + uint8_t blob; + + /* Reset values to invalid (just to be sure) */ + if (value_int) + *value_int = -1; + if (value_uint8) + *value_uint8 = 0; + + /* Exit if not enough src are available */ + if (src_len < 1) + return -EINVAL; + + /* Decode bit value */ + blob = *src; + + /* Check if parsed value is within bounds */ + if (blob < value_min) + return -EINVAL; + if (blob > value_max) + return -EINVAL; + + /* Hand back results to the caller */ + if (value_int) + *value_int = blob; + if (value_uint8) + *value_uint8 = blob; + + /* Return consumed length */ + return 1; +} + + + + +/* Decode rfc1144 parameter field see also: ETSI TS 144 065 6.5.2.1, Table 5) */ +static int decode_hdrcomp_rfc1144_params(const uint8_t * src, + unsigned int src_len, struct + gprs_sndcp_hdrcomp_rfc1144_params + *params) +{ + int rc; + int byte_counter = 0; + + /* Exit immediately if no result can be stored */ + if (!params) + return -EINVAL; + + /* Mark all optional parameters invalid by default */ + params->s01 = -1; + + /* Decode applicable SAPIs */ + rc = decode_hdrcomp_applicable_sapis(src, src_len, + params->nsapi, + ¶ms->nsapi_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* + * Decode parameter S0 -1 + * (see also: ETSI TS 144 065 6.5.2.1, Table 5) + */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, 0, + 255, ¶ms->s01, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* + * Decode rfc2507 parameter field + * (see also: ETSI TS 144 065 6.5.3.1, Table 6) + */ +static int decode_hdrcomp_rfc2507_params(const uint8_t * src, + unsigned int src_len, struct + gprs_sndcp_hdrcomp_rfc2507_params + *params) +{ + int rc; + int byte_counter = 0; + + /* Exit immediately if no result can be stored */ + if (!params) + return -EINVAL; + + /* Mark all optional parameters invalid by default */ + params->f_max_period = -1; + params->f_max_time = -1; + params->max_header = -1; + params->tcp_space = -1; + params->non_tcp_space = -1; + + /* Decode applicable SAPIs */ + rc = decode_hdrcomp_applicable_sapis(src, src_len, + params->nsapi, + ¶ms->nsapi_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode F_MAX_PERIOD (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 1, 65535, ¶ms->f_max_period, + NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode F_MAX_TIME (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, 1, + 255, ¶ms->f_max_time, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_HEADER (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, + 60, 255, ¶ms->max_header, + NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode TCP_SPACE (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, 3, + 255, ¶ms->tcp_space, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode NON_TCP_SPACE (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 3, 65535, ¶ms->non_tcp_space, + NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Decode ROHC parameter field (see also: ETSI TS 144 065 6.5.4.1, Table 10) */ +static int decode_hdrcomp_rohc_params(const uint8_t * src, + unsigned int src_len, + struct gprs_sndcp_hdrcomp_rohc_params + *params) +{ + int rc; + int byte_counter = 0; + int i; + + /* Exit immediately if no result can be stored */ + if (!params) + return -EINVAL; + + /* Mark all optional parameters invalid by default */ + params->max_cid = -1; + params->max_header = -1; + + /* Decode applicable SAPIs */ + rc = decode_hdrcomp_applicable_sapis(src, src_len, + params->nsapi, + ¶ms->nsapi_len); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_CID (see also: ETSI TS 144 065 6.5.4.1, Table 10) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 0, 16383, ¶ms->max_cid, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_HEADER (see also: ETSI TS 144 065 6.5.4.1, Table 10) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 60, 255, ¶ms->max_header, + NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode Profiles (see also: ETSI TS 144 065 6.5.4.1, Table 10) */ + for (i = 0; i < 16; i++) { + params->profile_len = 0; + rc = decode_hdrcomp_16_bit_field(src, + src_len - byte_counter, + 0, 65535, NULL, + ¶ms->profile[i]); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + params->profile_len = i + 1; + } + + /* Return consumed length */ + return byte_counter; +} + + +/* + * Decode V42bis parameter field + * (see also: ETSI TS 144 065 6.6.2.1, Table 7a) + */ +static int decode_datacomp_v42bis_params(const uint8_t * src, + unsigned int src_len, struct + gprs_sndcp_datacomp_v42bis_params + *params) +{ + int rc; + int byte_counter = 0; + + /* Exit immediately if no result can be stored */ + if (!params) + return -EINVAL; + + /* Mark all optional parameters invalid by default */ + params->p0 = -1; + params->p1 = -1; + params->p2 = -1; + + /* Decode applicable SAPIs */ + rc = decode_hdrcomp_applicable_sapis(src, src_len, + params->nsapi, + ¶ms->nsapi_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode P0 (see also: ETSI TS 144 065 6.6.2.1, Table 7a) */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, 0, + 3, ¶ms->p0, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1 (see also: ETSI TS 144 065 6.6.2.1, Table 7a) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 512, 65535, ¶ms->p1, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P2 (see also: ETSI TS 144 065 6.6.2.1, Table 7a) */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, 6, + 250, ¶ms->p2, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + + +/* Decode V44 parameter field (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ +static int decode_datacomp_v44_params(const uint8_t * src, + unsigned int src_len, + struct gprs_sndcp_datacomp_v44_params + *params) +{ + int rc; + int byte_counter = 0; + + /* Exit immediately if no result can be stored */ + if (!params) + return -EINVAL; + + /* Mark all optional parameters invalid by default */ + params->c0 = -1; + params->p0 = -1; + params->p1t = -1; + params->p1r = -1; + params->p3t = -1; + params->p3r = -1; + + /* Decode applicable SAPIs */ + rc = decode_hdrcomp_applicable_sapis(src, src_len, + params->nsapi, + ¶ms->nsapi_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode C0 (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, 0, + 255, ¶ms->c0, NULL); + if (rc <= 0) + return byte_counter; + if ((params->c0 != 0x80) && (params->c0 != 0xC0)) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Decode P0 (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, 0, + 3, ¶ms->p0, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1T (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 265, 65535, ¶ms->p1t, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1R (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 265, 65535, ¶ms->p1r, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P3T (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 265, 65535, ¶ms->p3t, NULL); + if (rc <= 0) + return byte_counter; + if (params->p3t < 2 * params->p1t) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Decode P3R (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 265, 65535, ¶ms->p3r, NULL); + if (rc <= 0) + return byte_counter; + if (params->p3r < 2 * params->p1r) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + + +/* Lookup algorithm identfier by entity ID */ +static int lookup_algorithm_identifier(int entity, struct + gprs_sndcp_hdrcomp_entity_algo_table + *lt, unsigned int lt_len, + int compclass) +{ + int i; + if ((lt) && (lt_len > 0)) { + for (i = 0; i < lt_len; i++) { + if ((lt[i].entity == entity) + && (lt[i].compclass == compclass)) + return lt[i].algo; + } + } + + return -1; +} + +/* + * Helper function for decode_comp_field(), decodes + * numeric pcomp/dcomp values + */ +static int decode_comp_values(struct gprs_sndcp_comp_field *comp_field, + const uint8_t * src, int compclass) +{ + int src_counter = 0; + int i; + + if (comp_field->p) { + /* Determine the number of expected PCOMP/DCOMP values */ + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + /* For protocol compression */ + switch (comp_field->algo) { + case RFC_1144: + comp_field->comp_len = RFC1144_PCOMP_NUM; + break; + case RFC_2507: + comp_field->comp_len = RFC2507_PCOMP_NUM; + break; + case ROHC: + comp_field->comp_len = ROHC_PCOMP_NUM; + break; + + /* Exit if the algorithem type encodes + something unknown / unspecified */ + default: + return -EINVAL; + } + } else { + /* For data compression */ + switch (comp_field->algo) { + case V42BIS: + comp_field->comp_len = V42BIS_DCOMP_NUM; + break; + case V44: + comp_field->comp_len = V44_DCOMP_NUM; + break; + + /* Exit if the algorithem type encodes + something unknown / unspecified */ + default: + return -EINVAL; + } + } + + for (i = 0; i < comp_field->comp_len; i++) { + if (i & 1) { + comp_field->comp[i] = (*src) & 0x0F; + src++; + src_counter++; + } else + comp_field->comp[i] = ((*src) >> 4) & 0x0F; + } + + if (i & 1) { + src++; + src_counter++; + } + } + + return src_counter; +} + +/* + * Helper function for decode_comp_field(), decodes the parameters + * which are protocol compression specific + */ +static int decode_pcomp_params(struct gprs_sndcp_comp_field *comp_field, + const uint8_t * src, int src_len) +{ + int rc; + + switch (comp_field->algo) { + case RFC_1144: + comp_field->rfc1144_params = talloc_zero(NULL, struct + gprs_sndcp_hdrcomp_rfc1144_params); + rc = decode_hdrcomp_rfc1144_params(src, src_len, + comp_field-> + rfc1144_params); + if (rc < 0) + talloc_free(comp_field->rfc1144_params); + break; + case RFC_2507: + comp_field->rfc2507_params = talloc_zero(NULL, struct + gprs_sndcp_hdrcomp_rfc2507_params); + rc = decode_hdrcomp_rfc2507_params(src, src_len, + comp_field-> + rfc2507_params); + if (rc < 0) + talloc_free(comp_field->rfc1144_params); + break; + case ROHC: + comp_field->rohc_params = talloc_zero(NULL, struct + gprs_sndcp_hdrcomp_rohc_params); + rc = decode_hdrcomp_rohc_params(src, src_len, + comp_field->rohc_params); + if (rc < 0) + talloc_free(comp_field->rohc_params); + break; + + /* If no suitable decoder is detected, + leave the remaining bytes undecoded */ + default: + rc = src_len; + } + + if (rc < 0) { + comp_field->rfc1144_params = NULL; + comp_field->rfc2507_params = NULL; + comp_field->rohc_params = NULL; + } + + return rc; +} + +/* + * Helper function for decode_comp_field(), decodes the parameters + * which are data compression specific + */ +static int decode_dcomp_params(struct gprs_sndcp_comp_field *comp_field, + const uint8_t * src, int src_len) +{ + int rc; + + + switch (comp_field->algo) { + case V42BIS: + comp_field->v42bis_params = talloc_zero(NULL, struct + gprs_sndcp_datacomp_v42bis_params); + rc = decode_datacomp_v42bis_params(src, src_len, + comp_field-> + v42bis_params); + if (rc < 0) + talloc_free(comp_field->v42bis_params); + break; + case V44: + comp_field->v44_params = talloc_zero(NULL, struct + gprs_sndcp_datacomp_v44_params); + rc = decode_datacomp_v44_params(src, src_len, + comp_field->v44_params); + if (rc < 0) + talloc_free(comp_field->v44_params); + break; + + /* If no suitable decoder is detected, + leave the remaining bytes undecoded */ + default: + rc = src_len; + } + + + if (rc < 0) { + comp_field->v42bis_params = NULL; + comp_field->v44_params = NULL; + } + + return rc; +} + + + +/* + * Decode data or protocol control information compression field + * (see also: ETSI TS 144 065 6.6.1.1, Figure 9 and + * ETSI TS 144 065 6.5.1.1, Figure 7) + */ +static int decode_comp_field(const uint8_t * src, unsigned int src_len, + struct gprs_sndcp_comp_field *comp_field, + struct + gprs_sndcp_hdrcomp_entity_algo_table + *lt, unsigned int lt_len, int compclass) +{ + int src_counter = 0; + unsigned int len; + int rc; + + /* Exit immediately if it is clear that no + parseable data is present */ + if ((src_len < 1) || !src) + return -EINVAL; + + /* Exit immediately if no result can be stored */ + if (!comp_field) + return -EINVAL; + + /* Zero out target struct */ + memset(comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + + /* Decode Propose bit and Entity number */ + if ((*src) & 0x80) + comp_field->p = 1; + comp_field->entity = (*src) & 0x1F; + src_counter++; + src++; + + /* Decode algorithm number (if present) */ + if (comp_field->p) { + comp_field->algo = (*src) & 0x1F; + src_counter++; + src++; + } + /* Alternatively take the information from the lookup table */ + else + comp_field->algo = + lookup_algorithm_identifier(comp_field->entity, lt, + lt_len, compclass); + + /* Decode length field */ + len = *src; + src_counter++; + src++; + + + /* Decode PCOMP/DCOMP values */ + rc = decode_comp_values(comp_field, src, compclass); + if (rc < 0) + return -EINVAL; + src_counter += rc; + src += rc; + len -= rc; + + /* Decode algorithm specific payload data */ + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + rc = decode_pcomp_params(comp_field, src, len); + else if (compclass == SNDCP_XID_DATA_COMPRESSION) + rc = decode_dcomp_params(comp_field, src, len); + else + return -EINVAL; + + if (rc >= 0) + src_counter += rc; + else + return -EINVAL; + + + /* Return consumed length */ + return src_counter; +} + + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +static int gprs_sndcp_decode_xid(struct llist_head *comp_fields, + const uint8_t * src, unsigned int src_len, + struct + gprs_sndcp_hdrcomp_entity_algo_table + *lt, unsigned int lt_len) +{ + int src_pos = 0; + uint8_t tag; + uint16_t tag_len; + const uint8_t *val; + struct gprs_sndcp_comp_field *comp_field; + int rc; + int byte_counter = 0; + int comp_field_count = 0; + + /* Valid TLV-Tag and types */ + static const struct tlv_definition sndcp_xid_def = { + .def = { + [SNDCP_XID_VERSION_NUMBER] = {TLV_TYPE_TLV,}, + [SNDCP_XID_DATA_COMPRESSION] = {TLV_TYPE_TLV,}, + [SNDCP_XID_PROTOCOL_COMPRESSION] = {TLV_TYPE_TLV,}, + }, + }; + + /* Parse TLV-Encoded SNDCP-XID message and defer payload + to the apporpiate sub-parser functions */ + while (1) { + src_pos += + tlv_parse_one(&tag, &tag_len, &val, &sndcp_xid_def, + src + src_pos, src_len - src_pos); + + /* Decode compression parameters */ + if ((tag == SNDCP_XID_PROTOCOL_COMPRESSION) + || (tag == SNDCP_XID_DATA_COMPRESSION)) { + byte_counter = 0; + do { + /* Bail if more than the maximum number of + comp_fields is generated */ + if (comp_field_count > MAX_ENTITIES * 2) { + gprs_sndcp_free_comp_fields + (comp_fields); + return -EINVAL; + } + + /* Parse and add comp_field */ + comp_field = + talloc_zero(NULL, + struct + gprs_sndcp_comp_field); + + rc = decode_comp_field(val + byte_counter, + tag_len - + byte_counter, + comp_field, lt, + lt_len, tag); + + if (rc < 0) { + talloc_free(comp_field); + gprs_sndcp_free_comp_fields + (comp_fields); + return -EINVAL; + } else { + byte_counter += rc; + llist_add(&comp_field->list, + comp_fields); + } + + comp_field_count++; + } + while (tag_len - byte_counter > 0); + } + + /* Stop when no further TLV elements can be expected */ + if (src_len - src_pos <= 2) + break; + } + + return 0; +} + +/* Fill up lookutable from a list with comression entitiy fields */ +static int gprs_sndcp_fill_table(struct + gprs_sndcp_hdrcomp_entity_algo_table *lt, + unsigned int lt_len, + const struct llist_head *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field; + int i = 0; + + if (!(comp_fields)) + return -EINVAL; + if (!(lt)) + return -EINVAL; + + memset(lt, 0, + lt_len * + sizeof(struct gprs_sndcp_hdrcomp_entity_algo_table)); + + llist_for_each_entry(comp_field, comp_fields, list) { + + lt[i].entity = comp_field->entity; + lt[i].algo = comp_field->algo; + lt[i].compclass = + gprs_sndcp_get_compression_class(comp_field); + + if (lt[i].compclass < 0) { + memset(lt, 0, lt_len * + sizeof(struct + gprs_sndcp_hdrcomp_entity_algo_table)); + return -EINVAL; + } + + i++; + } + + return i; +} + + +/* + * Complete comp field params + * (if a param (dst) is not valid, it will be copied from source (src) + */ +static int complete_comp_field_params(struct gprs_sndcp_comp_field + *comp_field_dst, const struct gprs_sndcp_comp_field + *comp_field_src) +{ + if (comp_field_dst->algo < 0) + return -EINVAL; + + if ((comp_field_dst->rfc1144_params) + && (comp_field_src->rfc1144_params)) { + if (comp_field_dst->rfc1144_params->s01 < 0) + comp_field_dst->rfc1144_params->s01 = + comp_field_src->rfc1144_params->s01; + return 0; + } + + if ((comp_field_dst->rfc2507_params) + && (comp_field_src->rfc2507_params)) { + + if (comp_field_dst->rfc2507_params->f_max_period < 0) + comp_field_dst->rfc2507_params->f_max_period = + comp_field_src->rfc2507_params->f_max_period; + + if (comp_field_dst->rfc2507_params->f_max_time < 0) + comp_field_dst->rfc2507_params->f_max_time = + comp_field_src->rfc2507_params->f_max_time; + + if (comp_field_dst->rfc2507_params->max_header < 0) + comp_field_dst->rfc2507_params->max_header = + comp_field_src->rfc2507_params->max_header; + + if (comp_field_dst->rfc2507_params->tcp_space < 0) + comp_field_dst->rfc2507_params->tcp_space = + comp_field_src->rfc2507_params->tcp_space; + + if (comp_field_dst->rfc2507_params->non_tcp_space < 0) + comp_field_dst->rfc2507_params->non_tcp_space = + comp_field_src->rfc2507_params->non_tcp_space; + return 0; + } + + if ((comp_field_dst->rohc_params) + && (comp_field_src->rohc_params)) { + if (comp_field_dst->rfc1144_params->s01 < 0) + + if (comp_field_dst->rohc_params->max_cid < 0) + comp_field_dst->rohc_params->max_cid = + comp_field_src->rohc_params->max_cid; + + if (comp_field_dst->rohc_params->max_header < 0) + comp_field_dst->rohc_params->max_header = + comp_field_src->rohc_params->max_header; + + if (comp_field_dst->rohc_params->profile_len > 0) { + memcpy(comp_field_dst->rohc_params->profile, + comp_field_src->rohc_params->profile, + sizeof(comp_field_dst-> + rohc_params->profile)); + comp_field_dst->rohc_params->profile_len = + comp_field_src->rohc_params->profile_len; + } + + return 0; + } + + if ((comp_field_dst->v42bis_params) + && (comp_field_src->v42bis_params)) { + if (comp_field_dst->v42bis_params->p0 < 0) + comp_field_dst->v42bis_params->p0 = + comp_field_src->v42bis_params->p0; + if (comp_field_dst->v42bis_params->p1 < 0) + comp_field_dst->v42bis_params->p1 = + comp_field_src->v42bis_params->p1; + if (comp_field_dst->v42bis_params->p2 < 0) + comp_field_dst->v42bis_params->p2 = + comp_field_src->v42bis_params->p2; + return 0; + } + + if ((comp_field_dst->v44_params) + && (comp_field_src->v44_params)) { + if (comp_field_dst->v44_params->c0 < 0) + comp_field_dst->v44_params->c0 = + comp_field_src->v44_params->c0; + if (comp_field_dst->v44_params->p0 < 0) + comp_field_dst->v44_params->p0 = + comp_field_src->v44_params->p0; + if (comp_field_dst->v44_params->p1t < 0) + comp_field_dst->v44_params->p1t = + comp_field_src->v44_params->p1t; + if (comp_field_dst->v44_params->p1r < 0) + comp_field_dst->v44_params->p1r = + comp_field_src->v44_params->p1r; + if (comp_field_dst->v44_params->p3t < 0) + comp_field_dst->v44_params->p3t = + comp_field_src->v44_params->p3t; + if (comp_field_dst->v44_params->p3r < 0) + comp_field_dst->v44_params->p3r = + comp_field_src->v44_params->p3r; + return 0; + } + + /* + * There should be at least exist one param set + * in the destination struct, otherwise something + * must be wrong! + */ + return -EINVAL; +} + + +/* Complete missing parameters in a comp_field */ +static int gprs_sndcp_complete_comp_field(struct gprs_sndcp_comp_field + *comp_field, + const struct llist_head + *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field_src; + int rc = 0; + + if ((!comp_field) || (!comp_fields)) + return -EINVAL; + + llist_for_each_entry(comp_field_src, comp_fields, list) { + if (comp_field_src->entity == comp_field->entity) { + + /* Complete header fields */ + if (comp_field_src->comp_len > 0) { + memcpy(comp_field->comp, + comp_field_src->comp, + sizeof(comp_field_src->comp)); + comp_field->comp_len = + comp_field_src->comp_len; + } + + /* Complete parameter fields */ + rc = complete_comp_field_params(comp_field, + comp_field_src); + } + } + + return rc; +} + + +/* Complete missing parameters of all comp_field in a list */ +static int gprs_sndcp_complete_comp_fields(struct llist_head + *comp_fields_incomplete, + const struct llist_head + *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field_incomplete; + int rc; + + if ((!comp_fields_incomplete) || (!comp_fields)) + return -EINVAL; + + llist_for_each_entry(comp_field_incomplete, comp_fields_incomplete, + list) { + + rc = gprs_sndcp_complete_comp_field(comp_field_incomplete, + comp_fields); + if (rc < 0) + return -EINVAL; + + } + + return 0; +} + + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +int gprs_sndcp_parse_xid(struct llist_head *comp_fields, + const uint8_t * src, unsigned int src_len, + const struct llist_head *comp_fields_req) +{ + int rc; + int lt_len; + struct gprs_sndcp_hdrcomp_entity_algo_table lt[MAX_ENTITIES * 2]; + + if (comp_fields_req) { + /* Generate lookup table */ + lt_len = + gprs_sndcp_fill_table(lt, MAX_ENTITIES * 2, + comp_fields_req); + if (lt_len < 0) + return -EINVAL; + + /* Parse SNDCP-CID XID-Field */ + rc = gprs_sndcp_decode_xid(comp_fields, src, src_len, lt, + lt_len); + if (rc < 0) + return -EINVAL; + + rc = gprs_sndcp_complete_comp_fields(comp_fields, + comp_fields_req); + if (rc < 0) + return -EINVAL; + } else { + /* Parse SNDCP-CID XID-Field */ + rc = gprs_sndcp_decode_xid(comp_fields, src, src_len, NULL, + 0); + if (rc < 0) + return -EINVAL; + } + + return 0; +} + + +/* Free a list with SNDCP-XID fields */ +void gprs_sndcp_free_comp_fields(struct llist_head *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field; + struct llist_head *lh, *lh2; + + /* Exit immediately if no list is present */ + if (!comp_fields) + return; + + llist_for_each_entry(comp_field, comp_fields, list) { + if (comp_field->rfc1144_params) + talloc_free(comp_field->rfc1144_params); + if (comp_field->rfc2507_params) + talloc_free(comp_field->rfc2507_params); + if (comp_field->rohc_params) + talloc_free(comp_field->rohc_params); + if (comp_field->v42bis_params) + talloc_free(comp_field->v42bis_params); + if (comp_field->v44_params) + talloc_free(comp_field->v44_params); + } + + llist_for_each_safe(lh, lh2, comp_fields) { + llist_del(lh); + talloc_free(lh); + } +} + + +/* + * Helper for gprs_sndcp_dump_comp_fields(), + * dumps protocol compression parameters + */ +static void dump_pcomp_params(const struct gprs_sndcp_comp_field + *comp_field, unsigned int logl) +{ + int i; + switch (comp_field->algo) { + case RFC_1144: + LOGP(DSNDCP, LOGL_DEBUG, + " gprs_sndcp_hdrcomp_rfc1144_params {\n"); + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi_len=%i;\n", + comp_field->rfc1144_params->nsapi_len); + if (comp_field->rfc1144_params->nsapi_len == 0) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rfc1144_params->nsapi_len; i++) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[%i]=%i;\n", i, + comp_field->rfc1144_params->nsapi[i]); + LOGP(DSNDCP, logl, " s01=%i;\n", + comp_field->rfc1144_params->s01); + LOGP(DSNDCP, logl, " }\n"); + break; + case RFC_2507: + LOGP(DSNDCP, LOGL_DEBUG, + " gprs_sndcp_hdrcomp_rfc2507_params {\n"); + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi_len=%i;\n", + comp_field->rfc2507_params->nsapi_len); + if (comp_field->rfc2507_params->nsapi_len == 0) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rfc2507_params->nsapi_len; i++) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[%i]=%i;\n", i, + comp_field->rfc2507_params->nsapi[i]); + LOGP(DSNDCP, LOGL_DEBUG, + " f_max_period=%i;\n", + comp_field->rfc2507_params->f_max_period); + LOGP(DSNDCP, LOGL_DEBUG, + " f_max_time=%i;\n", + comp_field->rfc2507_params->f_max_time); + LOGP(DSNDCP, LOGL_DEBUG, + " max_header=%i;\n", + comp_field->rfc2507_params->max_header); + LOGP(DSNDCP, LOGL_DEBUG, + " tcp_space=%i;\n", + comp_field->rfc2507_params->tcp_space); + LOGP(DSNDCP, LOGL_DEBUG, + " non_tcp_space=%i;\n", + comp_field->rfc2507_params->non_tcp_space); + LOGP(DSNDCP, logl, " }\n"); + break; + case ROHC: + LOGP(DSNDCP, LOGL_DEBUG, + " gprs_sndcp_hdrcomp_rohc_params {\n"); + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi_len=%i;\n", + comp_field->rohc_params->nsapi_len); + if (comp_field->rohc_params->nsapi_len == 0) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rohc_params->nsapi_len; i++) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[%i]=%i;\n", i, + comp_field->rohc_params->nsapi[i]); + LOGP(DSNDCP, LOGL_DEBUG, + " max_cid=%i;\n", + comp_field->rohc_params->max_cid); + LOGP(DSNDCP, LOGL_DEBUG, + " max_header=%i;\n", + comp_field->rohc_params->max_header); + if (comp_field->rohc_params->profile_len == 0) + LOGP(DSNDCP, LOGL_DEBUG, + " profile[] = NULL;\n"); + for (i = 0; i < comp_field->rohc_params->profile_len; i++) + LOGP(DSNDCP, LOGL_DEBUG, + " profile[%i]=%04x;\n", + i, comp_field->rohc_params->profile[i]); + LOGP(DSNDCP, logl, " }\n"); + break; + } + + +} + + +/* + * Helper for gprs_sndcp_dump_comp_fields(), + * data protocol compression parameters + */ +static void dump_dcomp_params(const struct gprs_sndcp_comp_field + *comp_field, unsigned int logl) +{ + int i; + switch (comp_field->algo) { + case V42BIS: + LOGP(DSNDCP, LOGL_DEBUG, + " gprs_sndcp_datacomp_v42bis_params {\n"); + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi_len=%i;\n", + comp_field->v42bis_params->nsapi_len); + if (comp_field->v42bis_params->nsapi_len == 0) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->v42bis_params->nsapi_len; i++) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[%i]=%i;\n", i, + comp_field->v42bis_params->nsapi[i]); + LOGP(DSNDCP, logl, " p0=%i;\n", + comp_field->v42bis_params->p0); + LOGP(DSNDCP, logl, " p1=%i;\n", + comp_field->v42bis_params->p1); + LOGP(DSNDCP, logl, " p2=%i;\n", + comp_field->v42bis_params->p2); + LOGP(DSNDCP, logl, " }\n"); + break; + case V44: + LOGP(DSNDCP, LOGL_DEBUG, + " gprs_sndcp_datacomp_v44_params {\n"); + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi_len=%i;\n", + comp_field->v44_params->nsapi_len); + if (comp_field->v44_params->nsapi_len == 0) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->v44_params->nsapi_len; i++) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[%i]=%i;\n", i, + comp_field->v44_params->nsapi[i]); + LOGP(DSNDCP, logl, " c0=%i;\n", + comp_field->v44_params->c0); + LOGP(DSNDCP, logl, " p0=%i;\n", + comp_field->v44_params->p0); + LOGP(DSNDCP, logl, " p1t=%i;\n", + comp_field->v44_params->p1t); + LOGP(DSNDCP, logl, " p1r=%i;\n", + comp_field->v44_params->p1r); + LOGP(DSNDCP, logl, " p3t=%i;\n", + comp_field->v44_params->p3t); + LOGP(DSNDCP, logl, " p3r=%i;\n", + comp_field->v44_params->p3r); + LOGP(DSNDCP, logl, " }\n"); + break; + } +} + + +/* Dump a list with SNDCP-XID fields (Debug) */ +void gprs_sndcp_dump_comp_fields(const struct llist_head *comp_fields, + unsigned int logl) +{ + struct gprs_sndcp_comp_field *comp_field; + int i; + int compclass; + + llist_for_each_entry(comp_field, comp_fields, list) { + LOGP(DSNDCP, logl, "SNDCP-XID:\n"); + LOGP(DSNDCP, LOGL_DEBUG, + "struct gprs_sndcp_comp_field {\n"); + LOGP(DSNDCP, logl, " entity=%i;\n", comp_field->entity); + LOGP(DSNDCP, logl, " algo=%i;\n", comp_field->algo); + LOGP(DSNDCP, logl, " comp_len=%i;\n", + comp_field->comp_len); + if (comp_field->comp_len == 0) + LOGP(DSNDCP, logl, " comp[] = NULL;\n"); + for (i = 0; i < comp_field->comp_len; i++) + LOGP(DSNDCP, logl, " comp[%i]=%i;\n", i, + comp_field->comp[i]); + + compclass = gprs_sndcp_get_compression_class(comp_field); + + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + dump_pcomp_params(comp_field, logl); + } else if (compclass == SNDCP_XID_DATA_COMPRESSION) { + dump_dcomp_params(comp_field, logl); + } + + LOGP(DSNDCP, logl, "}\n"); + LOGP(DSNDCP, logl, "\n"); + } + +} -- To view, visit https://gerrit.osmocom.org/641 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e Gerrit-PatchSet: 5 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte From gerrit-no-reply at lists.osmocom.org Thu Aug 4 14:26:07 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 4 Aug 2016 14:26:07 +0000 Subject: osmo-bts[master]: osmo-bts-trx: Fix PCS1900 operation In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/650 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I637b76bc1fc749eed8e364412d76606589991c02 Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Harald Welte Gerrit-Reviewer: Harald Welte Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 4 14:26:13 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 4 Aug 2016 14:26:13 +0000 Subject: osmo-bts[master]: osmo-bts-trx: log decoder bit errors as DEBUG, not NOTICE In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/651 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ifd39c53ec22f57cdb5299e5d76ff6ff1482d3beb Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Harald Welte Gerrit-Reviewer: Harald Welte Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 4 14:50:35 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 4 Aug 2016 14:50:35 +0000 Subject: openbsc[master]: Added SNDCP-XID encoder / decoder In-Reply-To: References: Message-ID: Patch Set 5: Code-Review-1 (9 comments) https://gerrit.osmocom.org/#/c/641/5/openbsc/include/openbsc/gprs_sndcp_xid.h File openbsc/include/openbsc/gprs_sndcp_xid.h: PS5, Line 74: = 2 the compiler would just hand out the next number in the enum, no need for the '= 2' explicitly. same for rfc2507_pcomp below. Line 106: int max_cid; /* (default 15) */ can those values become negative? your patch v1 stated 'unsigned int' for many values, which now have become 'int'. https://gerrit.osmocom.org/#/c/641/5/openbsc/src/gprs/gprs_sndcp_xid.c File openbsc/src/gprs/gprs_sndcp_xid.c: Line 60: /* please avoid wasting two additioanl lines for the start and the end of comments '/*' and '*/'. Also, comments regarding function arguments are best placed above the function, where its purpose is described. And if you want to be super future-compatible, you might at the same time already use doxygen syntax, which we so far only use in libraries but not yet in applications. PS5, Line 94: ETSI TS 144 065 all other code references the 3GPP spec number, not the ETSI. Please follow existing style. Line 1494: /* Parse and add comp_field */ way too deep indenting, looses effective line length and makes code more complex to read than needed. Easy fix: early 'continue' like: if (tag != SNDCP_XID_PROTOCOL_COMPRESSION && tag != SNDCP_XID_DATA_COMPRESSION) continue; then you have saved already one level of indent. If there are no other optiosn like this, split the function in multiple functions. PS5, Line 1539: ( extra parenthsis. Where's the advantage over "if (!comp_fields)" ? Same in other if statements below. Line 1546: sizeof(struct gprs_sndcp_hdrcomp_entity_algo_table)); always use sizeof(*lt) here. Advantages: * statement fits on one line * less to type * if we ever change the type of 'lt', the memset/memcpy/etc. will continue to work without change. Line 1726: if ((!comp_fields_incomplete) || (!comp_fields)) again the extra paranthesis which I don't understand. PS5, Line 1822: LOGL_DEBUG 90% of your function still uses LOGL_DEBUG, not logl. -- To view, visit https://gerrit.osmocom.org/641 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e Gerrit-PatchSet: 5 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 4 15:00:27 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 4 Aug 2016 15:00:27 +0000 Subject: openbsc[master]: Added code to control GPRS TCP/IP header compression. In-Reply-To: References: Message-ID: Patch Set 7: Code-Review-1 (11 comments) https://gerrit.osmocom.org/#/c/642/7/openbsc/include/openbsc/gprs_llc.h File openbsc/include/openbsc/gprs_llc.h: PS7, Line 150: s if struct comp_ent is never used outside of gprs_llc_llme (Not sure if it is), then it might make sense to have it as anonymouse structure as part of gprs_llc_llme, i.e. struct gprs_llc_llme { ... struct { struct llist_head proto; struct llist_head data; } comp; Line 182: /* Copy of the XID fields we sent */ which XID fields? Of the latest XID exchange? https://gerrit.osmocom.org/#/c/642/7/openbsc/include/openbsc/gprs_sndcp_hdrcomp.h File openbsc/include/openbsc/gprs_sndcp_hdrcomp.h: Line 34: struct gprs_sndcp_hdrcomp_compression_entity { hdrcom_comrpression is long and redundant. I would prefer sndcp_hdrcomp_entity, but as you use the gprs_ prefix everywhere, you might keep that at the beginning (or remove it everywhere, like I suggested at some other place). https://gerrit.osmocom.org/#/c/642/7/openbsc/src/gprs/gprs_sndcp_comp_entity.c File openbsc/src/gprs/gprs_sndcp_comp_entity.c: Line 121: struct llist_head *lh, *lh2; not mandatory, but we typically call the list_head variables not after what they are, but after what they point to. So *ce for 'compression entity' might be more commonly seen in the code. But this is JFYI. Line 258: if (comp_entities) { please remove this kind of check, _unless_ there is a valid use case in the real world, where this function encounters a NULL argument as comp_entities. Also, normally the check would be inverse, i.e. 'if (!comp_entities) ... bail out' which makes sure the regular code path has one level less of indent Finally, if those checks only exist to catch programming errors, the general approach is OSMO_ASSERT(comp_entities) which would crash with a backtrace in case it ever was NULL. https://gerrit.osmocom.org/#/c/642/7/openbsc/src/gprs/gprs_sndcp_hdrcomp.c File openbsc/src/gprs/gprs_sndcp_hdrcomp.c: Line 155: // packet[0] &= 0x7F; extra whitespace at end of line PS7, Line 155: // avoid C++ style comments unless they are to be removed when implementation is ready to be merged. Line 162: packet[0] &= 0x4F; extra whitespace at end of line Line 240: gprs_sndcp_comp_entity_find_by_comp(comp_entities, pcomp); too long function names for my taste. sndcp_c_ent_by_comp() should be sifficient? Not mandatory, but I just think the code is much more readable if the function name dosen't occupy half of the line. Line 316: gprs_sndcp_comp_entity_find_comp_by_comp_index(comp_entity, sndcp_c_ent_by_c_index() ? Line 340: static uint16_t header_checksum(uint8_t * iph, unsigned int ihl) test code should be part of the autotest test suite in /tests/ -- To view, visit https://gerrit.osmocom.org/642 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 Gerrit-PatchSet: 7 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 4 15:02:22 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 4 Aug 2016 15:02:22 +0000 Subject: openbsc[master]: Added V42BIS implementation In-Reply-To: References: Message-ID: Patch Set 7: Code-Review-1 (2 comments) https://gerrit.osmocom.org/#/c/643/7//COMMIT_MSG Commit Message: PS7, Line 7: Added please don't use past tense. The commit message preceeds the comment, so the addition is currently happening or about to happen, but hasn't happened yet. PS7, Line 9: V42BIS V.42bis is the name of the spec, AFAIK. Of course that can't be used in #defines or for othe C language identifiers, but in human readable documentation the official name can be used. -- To view, visit https://gerrit.osmocom.org/643 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Iabedece9f97ca944a1e3f747bb073e532c4e9dca Gerrit-PatchSet: 7 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 4 15:05:10 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 4 Aug 2016 15:05:10 +0000 Subject: openbsc[master]: V42BIS integration In-Reply-To: References: Message-ID: Patch Set 9: Code-Review-1 (3 comments) https://gerrit.osmocom.org/#/c/644/9//COMMIT_MSG Commit Message: Line 10: edited to fit our needs a quick summary would be good. https://gerrit.osmocom.org/#/c/644/9/openbsc/include/openbsc/debug.h File openbsc/include/openbsc/debug.h: Line 39: DSNDCP, it moves DSNDCP, which is an unrelated change. https://gerrit.osmocom.org/#/c/644/9/openbsc/src/gprs/v42bis.c File openbsc/src/gprs/v42bis.c: Line 79: * without modification let's remove the Visual Studio and assembly related parts and keep the C language implementation. Also, if we don't have it yet, it might be a good candidate for libosmocore 'bits.c'. -- To view, visit https://gerrit.osmocom.org/644 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d Gerrit-PatchSet: 9 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 4 15:05:57 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 4 Aug 2016 15:05:57 +0000 Subject: [MERGED] libosmocore[master]: Extend L1SAP with Measurements In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: Extend L1SAP with Measurements ...................................................................... Extend L1SAP with Measurements We already have RSSI parameter in PH-DATA. Add other measurement information (BER, BTO, Link Quality). Change-Id: I2b127eb1856c4cd1bc46490a89592a595f1ee86b Related: OS#1616 --- M TODO-RELEASE M include/osmocom/gsm/l1sap.h 2 files changed, 5 insertions(+), 1 deletion(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/TODO-RELEASE b/TODO-RELEASE index ffdea4b..472b328 100644 --- a/TODO-RELEASE +++ b/TODO-RELEASE @@ -1,4 +1,5 @@ #library what description / commit summary line libosmogsm internal API update Internal API for GPRS cipher implementors updated to accommodate for arbitrary key lengths libosmocore change major external talloc dependency / internal talloc removal -libosmocore change major size of ph_data_param struct changed / Extend L1SAP PH-DATA with presence information \ No newline at end of file +libosmocore change major size of ph_data_param struct changed / Extend L1SAP PH-DATA with presence information +libosmocore change major size of ph_data_param struct changed / Extend L1SAP PH-DATA with measurement information \ No newline at end of file diff --git a/include/osmocom/gsm/l1sap.h b/include/osmocom/gsm/l1sap.h index 098e4f0..f0e9f6c 100644 --- a/include/osmocom/gsm/l1sap.h +++ b/include/osmocom/gsm/l1sap.h @@ -70,6 +70,9 @@ uint8_t chan_nr; /*!< \brief Channel Number (Like RSL) */ uint32_t fn; /*!< \brief GSM Frame Number */ int8_t rssi; /*!< \brief RSSI of receivedindication */ + uint16_t ber10k; /*!< \brief BER in units of 0.01% */ + int16_t ta_offs_qbits; /* !< \brief Burst TA Offset in quarter bits */ + int16_t lqual_cb; /* !< \brief Link quality in centiBel */ enum osmo_ph_pres_info_type pdch_presence_info; /*!< \brief Info regarding presence/validity of header and data parts */ }; -- To view, visit https://gerrit.osmocom.org/622 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I2b127eb1856c4cd1bc46490a89592a595f1ee86b Gerrit-PatchSet: 3 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max From gerrit-no-reply at lists.osmocom.org Thu Aug 4 15:06:12 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 4 Aug 2016 15:06:12 +0000 Subject: [MERGED] osmo-pcu[master]: Extend BTS <-> PCU protocol with measurement In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: Extend BTS <-> PCU protocol with measurement ...................................................................... Extend BTS <-> PCU protocol with measurement Note: this increases the version of BTS <-> PCU protocol and thus requires corresponding change in BTS. Change-Id: Ide0e29b668ee38516605c1763fda85e87e867813 Related: OS#1616 --- M src/pcu_l1_if.cpp M src/pcuif_proto.h 2 files changed, 13 insertions(+), 2 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp index 36cf9ad..1434213 100644 --- a/src/pcu_l1_if.cpp +++ b/src/pcu_l1_if.cpp @@ -214,7 +214,15 @@ int rc; pcu_l1_meas meas; meas.set_rssi(data_ind->rssi); - +#ifndef ENABLE_DIRECT_PHY + /* convert BER to % value */ + meas.set_ber(data_ind->ber10k / 100); + meas.set_bto(data_ind->ta_offs_qbits); + meas.set_link_qual(data_ind->lqual_cb / 10); + LOGP(DL1IF, LOGL_DEBUG, "Data indication with raw measurements " + "received: BER10k = %d, BTO = %d, Q = %d\n", data_ind->ber10k, + data_ind->ta_offs_qbits, data_ind->lqual_cb); +#endif LOGP(DL1IF, LOGL_DEBUG, "Data indication received: sapi=%d arfcn=%d " "block=%d data=%s\n", data_ind->sapi, data_ind->arfcn, data_ind->block_nr, diff --git a/src/pcuif_proto.h b/src/pcuif_proto.h index 9d740ac..d320380 100644 --- a/src/pcuif_proto.h +++ b/src/pcuif_proto.h @@ -1,7 +1,7 @@ #ifndef _PCUIF_PROTO_H #define _PCUIF_PROTO_H -#define PCU_IF_VERSION 0x05 +#define PCU_IF_VERSION 0x06 /* msg_type */ #define PCU_IF_MSG_DATA_REQ 0x00 /* send data to given channel */ @@ -50,6 +50,9 @@ uint8_t ts_nr; uint8_t block_nr; int8_t rssi; + uint16_t ber10k; /*!< \brief BER in units of 0.01% */ + int16_t ta_offs_qbits; /* !< \brief Burst TA Offset in quarter bits */ + int16_t lqual_cb; /* !< \brief Link quality in centiBel */ } __attribute__ ((packed)); struct gsm_pcu_if_rts_req { -- To view, visit https://gerrit.osmocom.org/624 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ide0e29b668ee38516605c1763fda85e87e867813 Gerrit-PatchSet: 3 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max From gerrit-no-reply at lists.osmocom.org Thu Aug 4 15:09:16 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 4 Aug 2016 15:09:16 +0000 Subject: [MERGED] openbsc[master]: Improve code re-use In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: Improve code re-use ...................................................................... Improve code re-use Introduce explicit __main__ function to facilitate re-use of defined python functions for ctrl interface. Change-Id: I9bad8f0dd1d69bd28816bf047d85840e3411bb9c Related: OS#1646 --- M openbsc/contrib/bsc_control.py 1 file changed, 47 insertions(+), 46 deletions(-) Approvals: daniel: Looks good to me, but someone else must approve Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/openbsc/contrib/bsc_control.py b/openbsc/contrib/bsc_control.py index 9dc01e3..26a421d 100755 --- a/openbsc/contrib/bsc_control.py +++ b/openbsc/contrib/bsc_control.py @@ -44,61 +44,62 @@ getmsg = "GET %s %s" %(options.id, var) send(sck, getmsg) -parser = OptionParser("Usage: %prog [options] var [value]") -parser.add_option("-d", "--host", dest="host", - help="connect to HOST", metavar="HOST") -parser.add_option("-p", "--port", dest="port", type="int", - help="use PORT", metavar="PORT", default=4249) -parser.add_option("-g", "--get", action="store_true", - dest="cmd_get", help="perform GET operation") -parser.add_option("-s", "--set", action="store_true", - dest="cmd_set", help="perform SET operation") -parser.add_option("-i", "--id", dest="id", default="1", - help="set id manually", metavar="ID") -parser.add_option("-v", "--verbose", action="store_true", - dest="verbose", help="be verbose", default=False) -parser.add_option("-m", "--monitor", action="store_true", - dest="monitor", help="monitor the connection for traps", default=False) +if __name__ == '__main__': + parser = OptionParser("Usage: %prog [options] var [value]") + parser.add_option("-d", "--host", dest="host", + help="connect to HOST", metavar="HOST") + parser.add_option("-p", "--port", dest="port", type="int", + help="use PORT", metavar="PORT", default=4249) + parser.add_option("-g", "--get", action="store_true", + dest="cmd_get", help="perform GET operation") + parser.add_option("-s", "--set", action="store_true", + dest="cmd_set", help="perform SET operation") + parser.add_option("-i", "--id", dest="id", default="1", + help="set id manually", metavar="ID") + parser.add_option("-v", "--verbose", action="store_true", + dest="verbose", help="be verbose", default=False) + parser.add_option("-m", "--monitor", action="store_true", + dest="monitor", help="monitor the connection for traps", default=False) -(options, args) = parser.parse_args() + (options, args) = parser.parse_args() -verbose = options.verbose + verbose = options.verbose -if options.cmd_set and options.cmd_get: - parser.error("Get and set options are mutually exclusive!") + if options.cmd_set and options.cmd_get: + parser.error("Get and set options are mutually exclusive!") -if not (options.cmd_get or options.cmd_set or options.monitor): - parser.error("One of -m, -g, or -s must be set") + if not (options.cmd_get or options.cmd_set or options.monitor): + parser.error("One of -m, -g, or -s must be set") -if not (options.host): - parser.error("Destination host and port required!") + if not (options.host): + parser.error("Destination host and port required!") -sock = connect(options.host, options.port) + sock = connect(options.host, options.port) -if options.cmd_set: - if len(args) < 2: - parser.error("Set requires var and value arguments") - do_set(args[0], ' '.join(args[1:]), options.id, sock) + if options.cmd_set: + if len(args) < 2: + parser.error("Set requires var and value arguments") + do_set(args[0], ' '.join(args[1:]), options.id, sock) -if options.cmd_get: - if len(args) != 1: - parser.error("Get requires the var argument") - do_get(args[0], options.id, sock) + if options.cmd_get: + if len(args) != 1: + parser.error("Get requires the var argument") + do_get(args[0], options.id, sock) -data = sock.recv(1024) -while (len(data)>0): - (answer, data) = remove_ipa_ctrl_header(data) - print "Got message:", answer + data = sock.recv(1024) + while (len(data)>0): + (answer, data) = remove_ipa_ctrl_header(data) + print "Got message:", answer -if options.monitor: - while (True): - data = sock.recv(1024) - if len(data) == 0: - print "Connection is gone." - break + if options.monitor: + while (True): + data = sock.recv(1024) + if len(data) == 0: + print "Connection is gone." + break - while (len(data)>0): - (answer, data) = remove_ipa_ctrl_header(data) - print "Got message:", answer + while (len(data)>0): + (answer, data) = remove_ipa_ctrl_header(data) + print "Got message:", answer -sock.close() + sock.close() -- To view, visit https://gerrit.osmocom.org/631 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I9bad8f0dd1d69bd28816bf047d85840e3411bb9c Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: daniel From gerrit-no-reply at lists.osmocom.org Thu Aug 4 15:30:13 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Thu, 4 Aug 2016 15:30:13 +0000 Subject: [PATCH] openbsc[master]: XID related modifications in LLC Message-ID: Review at https://gerrit.osmocom.org/652 XID related modifications in LLC With this commit the already existing XID mechanism has been modified to suit the needs for the upcomming SNDCP-XID patches. The SNDCP-XID related calls are currently disabled since the necessary patches for gprs_sndcp.c are not yet pushed. This commit should not break anything since it does not alter the current behaviour (incoming XID is still just echoed, on GMM-Reset a basic XID message is still echoed) Change-Id: I65b9d625e72d3d61c99abdc7041773701d694d52 --- M openbsc/src/gprs/gprs_llc.c M openbsc/tests/sgsn/Makefile.am 2 files changed, 353 insertions(+), 57 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/52/652/1 diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c index 7724ebb..8d29b70 100644 --- a/openbsc/src/gprs/gprs_llc.c +++ b/openbsc/src/gprs/gprs_llc.c @@ -38,8 +38,326 @@ #include #include #include +#include +#include +#include + +/* + * FIXME: Remove this switch as soon as the XID integration in + * gprs_sndcp.c h is done + */ +#define WITH_SNDCP_XID 0 static struct gprs_llc_llme *llme_alloc(uint32_t tlli); +static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg, + int command); +static int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi, + int command, enum gprs_llc_u_cmd u_cmd, int pf_bit); + +/* + * BEGIN XID RELATED + */ + +/* Generate XID message */ +static int gprs_llc_generate_xid(uint8_t * bytes, int bytes_len, + struct gprs_llc_xid_field *l3_xid_field, + struct gprs_llc_llme *llme) +{ + /* Note: Called by gprs_ll_xid_req() */ + + LLIST_HEAD(xid_fields); + + struct gprs_llc_xid_field xid_version; + struct gprs_llc_xid_field xid_n201u; + struct gprs_llc_xid_field xid_n201i; + + xid_version.type = GPRS_LLC_XID_T_VERSION; + xid_version.data = (uint8_t *) "\x00"; + xid_version.data_len = 1; + + xid_n201u.type = GPRS_LLC_XID_T_N201_U; + xid_n201u.data = (uint8_t *) "\x05\xf0"; + xid_n201u.data_len = 2; + + xid_n201i.type = GPRS_LLC_XID_T_N201_I; + xid_n201i.data = (uint8_t *) "\x05\xf0"; + xid_n201i.data_len = 2; + + /* Add layer 3 XID field (if present) */ + if (l3_xid_field) { + /* Enforce layer 3 XID type (just to be sure) */ + l3_xid_field->type = GPRS_LLC_XID_T_L3_PAR; + + /* Add Layer 3 XID field to the list */ + llist_add(&l3_xid_field->list, &xid_fields); + } + + /* Add locally managed XID Fields */ + llist_add(&xid_n201i.list, &xid_fields); + llist_add(&xid_n201u.list, &xid_fields); + llist_add(&xid_version.list, &xid_fields); + + gprs_llc_copy_xid(&llme->xid, &xid_fields); + + return gprs_llc_compile_xid(&xid_fields, bytes, bytes_len); +} + +/* Generate XID message that will cause the GMM to reset */ +static int gprs_llc_generate_xid_for_gmm_reset(uint8_t * bytes, + int bytes_len, int iov_ui, + struct gprs_llc_llme *llme) +{ + /* + * Called by gprs_llgmm_reset() and + * gprs_llgmm_reset_oldmsg() + */ + + LLIST_HEAD(xid_fields); + + struct gprs_llc_xid_field xid_reset; + struct gprs_llc_xid_field xid_iovui; + + /* First XID component must be RESET */ + xid_reset.type = GPRS_LLC_XID_T_RESET; + xid_reset.data = NULL; + xid_reset.data_len = 0; + + /* randomly select new IOV-UI */ + xid_iovui.type = GPRS_LLC_XID_T_IOV_UI; + xid_iovui.data = (uint8_t *) & iov_ui; + xid_iovui.data_len = 4; + + /* Add locally managed XID Fields */ + llist_add(&xid_iovui.list, &xid_fields); + llist_add(&xid_reset.list, &xid_fields); + + gprs_llc_copy_xid(&llme->xid, &xid_fields); + + return gprs_llc_compile_xid(&xid_fields, bytes, bytes_len); +} + +/* Process an incoming XID confirmation */ +static int gprs_llc_process_xid_conf(uint8_t * bytes, int bytes_len, + struct gprs_llc_lle *lle) +{ + /* + * Note: This function handles the response of a network originated + * XID-Request. There XID messages reflected by the phone are analyzed + * and processed here. The caller is called by rx_llc_xid(). + */ + + int rc; + LLIST_HEAD(xid_fields); + struct gprs_llc_xid_field *xid_field; + struct gprs_llc_xid_field *xid_field_request; + struct gprs_llc_xid_field *xid_field_request_l3 = NULL; + + /* Pick layer3 XID from the XID request we have sent last */ + llist_for_each_entry(xid_field_request, &lle->llme->xid, list) { + if (xid_field_request->type == GPRS_LLC_XID_T_L3_PAR) + xid_field_request_l3 = xid_field_request; + } + + /* Parse and analyze XID-Response */ + rc = gprs_llc_parse_xid(&xid_fields, bytes, bytes_len); + if (rc == 0) { + gprs_llc_dump_xid_fields(&xid_fields, LOGL_DEBUG); + + llist_for_each_entry(xid_field, &xid_fields, list) { + + /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { +#if WITH_SNDCP_XID == 1 + sndcp_sn_xid_conf(xid_field, + xid_field_request_l3, + lle); +#endif + } + + /* Process LLC-XID fields: */ + else { + + /* + * FIXME: Do something more useful with the + * echoed XID-Information. Currently we + * just ignore the response completely and + * by doing so we blindly accept any changes + * the MS might have done to the our XID + * inquiry. There is a remainig risk of + * malfunction! + */ + LOGP(DLLC, LOGL_NOTICE, + "Ignoring XID-Field: XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + xid_field->data); + + } + } + } + + /* Flush pending XID fields */ + gprs_llc_free_xid(&lle->llme->xid); + + return 0; +} + + +/* Process an incoming XID indication and generate an appropiate response */ +static int gprs_llc_process_xid_ind(uint8_t * bytes_request, + int bytes_request_len, + uint8_t * bytes_response, + int bytes_response_maxlen, + struct gprs_llc_lle *lle) +{ + /* + * Note: This function computes the response that is sent back to the + * phone when a phone originated XID is received. The function is + * called by rx_llc_xid() + */ + + int rc; + LLIST_HEAD(xid_fields); + LLIST_HEAD(xid_fields_response); + + struct gprs_llc_xid_field *xid_field; + struct gprs_llc_xid_field *xid_field_response; + + /* Flush eventually pending XID fields */ + gprs_llc_free_xid(&lle->llme->xid); + + /* Parse and analyze XID-Request */ + rc = gprs_llc_parse_xid(&xid_fields, bytes_request, + bytes_request_len); + if (rc == 0) { + gprs_llc_dump_xid_fields(&xid_fields, LOGL_DEBUG); + + llist_for_each_entry(xid_field, &xid_fields, list) { + /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { +#if WITH_SNDCP_XID == 1 + xid_field_response = + talloc_zero(NULL, + struct gprs_llc_xid_field); + rc = sndcp_sn_xid_ind(xid_field, + xid_field_response, + lle); + if (rc == 0) + llist_add(&xid_field_response-> + list, + &xid_fields_response); + else + talloc_free(xid_field_response); +#endif + } + + /* Process LLC-XID fields: */ + else { + /* FIXME: Check the incoming XID parameters for + * for validity. Currently we just blindly + * accept all XID fields by just echoing them. + * There is a remaining risk of malfunction + * when a phone submits values which defer from + * the default! + */ + LOGP(DLLC, LOGL_NOTICE, + "Echoing XID-Field: XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + osmo_hexdump_nospc(xid_field->data, + xid_field-> + data_len)); + xid_field_response = + gprs_llc_duplicate_xid_field + (xid_field); + llist_add(&xid_field_response->list, + &xid_fields_response); + } + } + + rc = gprs_llc_compile_xid(&xid_fields_response, + bytes_response, + bytes_response_maxlen); + gprs_llc_free_xid(&xid_fields_response); + } + gprs_llc_free_xid(&xid_fields); + + return rc; +} + +/* Dispatch XID indications and responses comming from the Phone */ +static void rx_llc_xid(struct gprs_llc_lle *lle, + struct gprs_llc_hdr_parsed *gph) +{ + uint8_t response[1024]; + int response_len; + + /* FIXME: 8.5.3.3: check if XID is invalid */ + if (gph->is_cmd) { + LOGP(DLLC, LOGL_NOTICE, + "Received XID indication from phone.\n"); + + struct msgb *resp; + uint8_t *xid; + resp = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + + response_len = + gprs_llc_process_xid_ind(gph->data, gph->data_len, + response, sizeof(response), + lle); + xid = msgb_put(resp, response_len); + memcpy(xid, response, response_len); + + gprs_llc_tx_xid(lle, resp, 0); + } else { + LOGP(DLLC, LOGL_NOTICE, + "Received XID confirmation from phone.\n"); + gprs_llc_process_xid_conf(gph->data, gph->data_len, lle); + /* FIXME: if we had sent a XID reset, send + * LLGMM-RESET.conf to GMM */ + } +} + + +/* Set of LL-XID negotiation (See also: TS 101 351, Section 7.2.2.4) */ +int gprs_ll_xid_req(struct gprs_llc_lle *lle, + struct gprs_llc_xid_field *l3_xid_field) +{ + /* Note: This functions is calle from gprs_sndcp.c */ + + uint8_t xid_bytes[1024];; + int xid_bytes_len; + uint8_t *xid; + struct msgb *msg; + + /* Generate XID */ + xid_bytes_len = + gprs_llc_generate_xid(xid_bytes, sizeof(xid_bytes), + l3_xid_field, lle->llme); + + + /* Only perform XID sending if the XID message contains something */ + if (xid_bytes_len > 0) { + /* Transmit XID bytes */ + msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); + LOGP(DLLC, LOGL_NOTICE, + "Sending XID request to phone...\n"); + gprs_llc_tx_xid(lle, msg, 1); + } else { + LOGP(DLLC, LOGL_ERROR, + "XID-Message generation failed, XID not sent!\n"); + return -EINVAL; + } + + return 0; +} + +/* + * END XID RELATED + */ + + + /* Entry function from upper level (LLC), asking us to transmit a BSSGP PDU * to a remote MS (identified by TLLI) at a BTS identified by its BVCI and NSEI */ @@ -246,11 +564,18 @@ llist_add(&llme->list, &gprs_llc_llmes); + INIT_LLIST_HEAD(&llme->comp.proto); + INIT_LLIST_HEAD(&llme->comp.data); + INIT_LLIST_HEAD(&llme->xid); + return llme; } static void llme_free(struct gprs_llc_llme *llme) { + gprs_sndcp_comp_entities_free(&llme->comp.proto); + gprs_sndcp_comp_entities_free(&llme->comp.data); + gprs_llc_free_xid(&llme->xid); llist_del(&llme->list); talloc_free(llme); } @@ -464,54 +789,6 @@ /* Send BSSGP-DL-UNITDATA.req */ return _bssgp_tx_dl_ud(msg, mmctx); -} - -/* According to 6.4.1.6 / Figure 11 */ -static int msgb_put_xid_par(struct msgb *msg, uint8_t type, uint8_t length, uint8_t *data) -{ - uint8_t header_len = 1; - uint8_t *cur; - - /* type is a 5-bit field... */ - if (type > 0x1f) - return -EINVAL; - - if (length > 3) - header_len = 2; - - cur = msgb_put(msg, length + header_len); - - /* build the header without or with XL bit */ - if (length <= 3) { - *cur++ = (type << 2) | (length & 3); - } else { - *cur++ = 0x80 | (type << 2) | (length >> 6); - *cur++ = (length << 2); - } - - /* copy over the payload of the parameter*/ - memcpy(cur, data, length); - - return length + header_len; -} - -static void rx_llc_xid(struct gprs_llc_lle *lle, - struct gprs_llc_hdr_parsed *gph) -{ - /* FIXME: 8.5.3.3: check if XID is invalid */ - if (gph->is_cmd) { - /* FIXME: implement XID negotiation using SNDCP */ - struct msgb *resp; - uint8_t *xid; - resp = msgb_alloc_headroom(4096, 1024, "LLC_XID"); - xid = msgb_put(resp, gph->data_len); - memcpy(xid, gph->data, gph->data_len); - gprs_llc_tx_xid(lle, resp, 0); - } else { - /* FIXME: if we had sent a XID reset, send - * LLGMM-RESET.conf to GMM */ - /* FIXME: implement XID negotiation using SNDCP */ - } } static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph, @@ -784,17 +1061,24 @@ { struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); struct gprs_llc_lle *lle = &llme->lle[1]; + uint8_t xid_bytes[1024]; + int xid_bytes_len; + uint8_t *xid; + LOGP(DLLC, LOGL_NOTICE, "LLGM Reset\n"); if (RAND_bytes((uint8_t *) &llme->iov_ui, 4) != 1) { LOGP(DLLC, LOGL_NOTICE, "RAND_bytes failed for LLC XID reset, " "falling back to rand()\n"); llme->iov_ui = rand(); } - /* First XID component must be RESET */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL); - /* randomly select new IOV-UI */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &llme->iov_ui); + /* Generate XID message */ + xid_bytes_len = gprs_llc_generate_xid_for_gmm_reset(xid_bytes, + sizeof(xid_bytes),llme->iov_ui,llme); + if(xid_bytes_len < 0) + return -EINVAL; + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); /* Reset some of the LLC parameters. See GSM 04.64, 8.5.3.1 */ lle->vu_recv = 0; @@ -810,17 +1094,24 @@ struct gprs_llc_llme *llme) { struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + uint8_t xid_bytes[1024]; + int xid_bytes_len; + uint8_t *xid; + LOGP(DLLC, LOGL_NOTICE, "LLGM Reset\n"); if (RAND_bytes((uint8_t *) &llme->iov_ui, 4) != 1) { LOGP(DLLC, LOGL_NOTICE, "RAND_bytes failed for LLC XID reset, " "falling back to rand()\n"); llme->iov_ui = rand(); } - /* First XID component must be RESET */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL); - /* randomly select new IOV-UI */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &llme->iov_ui); + /* Generate XID message */ + xid_bytes_len = gprs_llc_generate_xid_for_gmm_reset(xid_bytes, + sizeof(xid_bytes),llme->iov_ui,llme); + if(xid_bytes_len < 0) + return -EINVAL; + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); /* FIXME: Start T200, wait for XID response */ diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index b6036c7..3b34452 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -30,6 +30,11 @@ $(top_builddir)/src/gprs/gprs_gb_parse.o \ $(top_builddir)/src/gprs/oap.o \ $(top_builddir)/src/gprs/oap_messages.o \ + $(top_builddir)/src/gprs/gprs_llc_xid.o \ + $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ + $(top_builddir)/src/gprs/gprs_sndcp_comp_entity.o \ + $(top_builddir)/src/gprs/gprs_sndcp_hdrcomp.o \ + $(top_builddir)/src/gprs/slhc.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ @@ -37,5 +42,5 @@ $(LIBOSMOGB_LIBS) \ $(LIBCARES_LIBS) \ $(LIBCRYPTO_LIBS) \ - -lgtp -lrt + -lgtp -lrt -lm -- To view, visit https://gerrit.osmocom.org/652 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I65b9d625e72d3d61c99abdc7041773701d694d52 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter From gerrit-no-reply at lists.osmocom.org Thu Aug 4 15:40:35 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Thu, 4 Aug 2016 15:40:35 +0000 Subject: [PATCH] openbsc[master]: XID related modifications in LLC In-Reply-To: References: Message-ID: XID related modifications in LLC With this commit the already existing XID mechanism has been modified to suit the needs for the upcomming SNDCP-XID patches. The SNDCP-XID related calls are currently disabled since the necessary patches for gprs_sndcp.c are not yet pushed. This commit should not break anything since it does not alter the current behaviour (incoming XID is still just echoed, on GMM-Reset a basic XID message is still echoed) Change-Id: I65b9d625e72d3d61c99abdc7041773701d694d52 --- M openbsc/include/openbsc/gprs_llc.h M openbsc/src/gprs/gprs_llc.c M openbsc/tests/sgsn/Makefile.am 3 files changed, 358 insertions(+), 57 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/52/652/2 diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h index 39d17f4..ad2aa73 100644 --- a/openbsc/include/openbsc/gprs_llc.h +++ b/openbsc/include/openbsc/gprs_llc.h @@ -4,6 +4,7 @@ #include #include #include +#include /* Section 4.7 LLC Layer Structure */ enum gprs_llc_sapi { @@ -235,6 +236,10 @@ int gprs_llgmm_reset_oldmsg(struct msgb* oldmsg, uint8_t sapi, struct gprs_llc_llme *llme); +/* Set of LL-XID negotiation (See also: TS 101 351, Section 7.2.2.4) */ +int gprs_ll_xid_req(struct gprs_llc_lle *lle, + struct gprs_llc_xid_field *l3_xid_field); + /* 04.64 Chapter 7.2.1.1 LLGMM-ASSIGN */ int gprs_llgmm_assign(struct gprs_llc_llme *llme, uint32_t old_tlli, uint32_t new_tlli); diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c index 7724ebb..8d29b70 100644 --- a/openbsc/src/gprs/gprs_llc.c +++ b/openbsc/src/gprs/gprs_llc.c @@ -38,8 +38,326 @@ #include #include #include +#include +#include +#include + +/* + * FIXME: Remove this switch as soon as the XID integration in + * gprs_sndcp.c h is done + */ +#define WITH_SNDCP_XID 0 static struct gprs_llc_llme *llme_alloc(uint32_t tlli); +static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg, + int command); +static int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi, + int command, enum gprs_llc_u_cmd u_cmd, int pf_bit); + +/* + * BEGIN XID RELATED + */ + +/* Generate XID message */ +static int gprs_llc_generate_xid(uint8_t * bytes, int bytes_len, + struct gprs_llc_xid_field *l3_xid_field, + struct gprs_llc_llme *llme) +{ + /* Note: Called by gprs_ll_xid_req() */ + + LLIST_HEAD(xid_fields); + + struct gprs_llc_xid_field xid_version; + struct gprs_llc_xid_field xid_n201u; + struct gprs_llc_xid_field xid_n201i; + + xid_version.type = GPRS_LLC_XID_T_VERSION; + xid_version.data = (uint8_t *) "\x00"; + xid_version.data_len = 1; + + xid_n201u.type = GPRS_LLC_XID_T_N201_U; + xid_n201u.data = (uint8_t *) "\x05\xf0"; + xid_n201u.data_len = 2; + + xid_n201i.type = GPRS_LLC_XID_T_N201_I; + xid_n201i.data = (uint8_t *) "\x05\xf0"; + xid_n201i.data_len = 2; + + /* Add layer 3 XID field (if present) */ + if (l3_xid_field) { + /* Enforce layer 3 XID type (just to be sure) */ + l3_xid_field->type = GPRS_LLC_XID_T_L3_PAR; + + /* Add Layer 3 XID field to the list */ + llist_add(&l3_xid_field->list, &xid_fields); + } + + /* Add locally managed XID Fields */ + llist_add(&xid_n201i.list, &xid_fields); + llist_add(&xid_n201u.list, &xid_fields); + llist_add(&xid_version.list, &xid_fields); + + gprs_llc_copy_xid(&llme->xid, &xid_fields); + + return gprs_llc_compile_xid(&xid_fields, bytes, bytes_len); +} + +/* Generate XID message that will cause the GMM to reset */ +static int gprs_llc_generate_xid_for_gmm_reset(uint8_t * bytes, + int bytes_len, int iov_ui, + struct gprs_llc_llme *llme) +{ + /* + * Called by gprs_llgmm_reset() and + * gprs_llgmm_reset_oldmsg() + */ + + LLIST_HEAD(xid_fields); + + struct gprs_llc_xid_field xid_reset; + struct gprs_llc_xid_field xid_iovui; + + /* First XID component must be RESET */ + xid_reset.type = GPRS_LLC_XID_T_RESET; + xid_reset.data = NULL; + xid_reset.data_len = 0; + + /* randomly select new IOV-UI */ + xid_iovui.type = GPRS_LLC_XID_T_IOV_UI; + xid_iovui.data = (uint8_t *) & iov_ui; + xid_iovui.data_len = 4; + + /* Add locally managed XID Fields */ + llist_add(&xid_iovui.list, &xid_fields); + llist_add(&xid_reset.list, &xid_fields); + + gprs_llc_copy_xid(&llme->xid, &xid_fields); + + return gprs_llc_compile_xid(&xid_fields, bytes, bytes_len); +} + +/* Process an incoming XID confirmation */ +static int gprs_llc_process_xid_conf(uint8_t * bytes, int bytes_len, + struct gprs_llc_lle *lle) +{ + /* + * Note: This function handles the response of a network originated + * XID-Request. There XID messages reflected by the phone are analyzed + * and processed here. The caller is called by rx_llc_xid(). + */ + + int rc; + LLIST_HEAD(xid_fields); + struct gprs_llc_xid_field *xid_field; + struct gprs_llc_xid_field *xid_field_request; + struct gprs_llc_xid_field *xid_field_request_l3 = NULL; + + /* Pick layer3 XID from the XID request we have sent last */ + llist_for_each_entry(xid_field_request, &lle->llme->xid, list) { + if (xid_field_request->type == GPRS_LLC_XID_T_L3_PAR) + xid_field_request_l3 = xid_field_request; + } + + /* Parse and analyze XID-Response */ + rc = gprs_llc_parse_xid(&xid_fields, bytes, bytes_len); + if (rc == 0) { + gprs_llc_dump_xid_fields(&xid_fields, LOGL_DEBUG); + + llist_for_each_entry(xid_field, &xid_fields, list) { + + /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { +#if WITH_SNDCP_XID == 1 + sndcp_sn_xid_conf(xid_field, + xid_field_request_l3, + lle); +#endif + } + + /* Process LLC-XID fields: */ + else { + + /* + * FIXME: Do something more useful with the + * echoed XID-Information. Currently we + * just ignore the response completely and + * by doing so we blindly accept any changes + * the MS might have done to the our XID + * inquiry. There is a remainig risk of + * malfunction! + */ + LOGP(DLLC, LOGL_NOTICE, + "Ignoring XID-Field: XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + xid_field->data); + + } + } + } + + /* Flush pending XID fields */ + gprs_llc_free_xid(&lle->llme->xid); + + return 0; +} + + +/* Process an incoming XID indication and generate an appropiate response */ +static int gprs_llc_process_xid_ind(uint8_t * bytes_request, + int bytes_request_len, + uint8_t * bytes_response, + int bytes_response_maxlen, + struct gprs_llc_lle *lle) +{ + /* + * Note: This function computes the response that is sent back to the + * phone when a phone originated XID is received. The function is + * called by rx_llc_xid() + */ + + int rc; + LLIST_HEAD(xid_fields); + LLIST_HEAD(xid_fields_response); + + struct gprs_llc_xid_field *xid_field; + struct gprs_llc_xid_field *xid_field_response; + + /* Flush eventually pending XID fields */ + gprs_llc_free_xid(&lle->llme->xid); + + /* Parse and analyze XID-Request */ + rc = gprs_llc_parse_xid(&xid_fields, bytes_request, + bytes_request_len); + if (rc == 0) { + gprs_llc_dump_xid_fields(&xid_fields, LOGL_DEBUG); + + llist_for_each_entry(xid_field, &xid_fields, list) { + /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { +#if WITH_SNDCP_XID == 1 + xid_field_response = + talloc_zero(NULL, + struct gprs_llc_xid_field); + rc = sndcp_sn_xid_ind(xid_field, + xid_field_response, + lle); + if (rc == 0) + llist_add(&xid_field_response-> + list, + &xid_fields_response); + else + talloc_free(xid_field_response); +#endif + } + + /* Process LLC-XID fields: */ + else { + /* FIXME: Check the incoming XID parameters for + * for validity. Currently we just blindly + * accept all XID fields by just echoing them. + * There is a remaining risk of malfunction + * when a phone submits values which defer from + * the default! + */ + LOGP(DLLC, LOGL_NOTICE, + "Echoing XID-Field: XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + osmo_hexdump_nospc(xid_field->data, + xid_field-> + data_len)); + xid_field_response = + gprs_llc_duplicate_xid_field + (xid_field); + llist_add(&xid_field_response->list, + &xid_fields_response); + } + } + + rc = gprs_llc_compile_xid(&xid_fields_response, + bytes_response, + bytes_response_maxlen); + gprs_llc_free_xid(&xid_fields_response); + } + gprs_llc_free_xid(&xid_fields); + + return rc; +} + +/* Dispatch XID indications and responses comming from the Phone */ +static void rx_llc_xid(struct gprs_llc_lle *lle, + struct gprs_llc_hdr_parsed *gph) +{ + uint8_t response[1024]; + int response_len; + + /* FIXME: 8.5.3.3: check if XID is invalid */ + if (gph->is_cmd) { + LOGP(DLLC, LOGL_NOTICE, + "Received XID indication from phone.\n"); + + struct msgb *resp; + uint8_t *xid; + resp = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + + response_len = + gprs_llc_process_xid_ind(gph->data, gph->data_len, + response, sizeof(response), + lle); + xid = msgb_put(resp, response_len); + memcpy(xid, response, response_len); + + gprs_llc_tx_xid(lle, resp, 0); + } else { + LOGP(DLLC, LOGL_NOTICE, + "Received XID confirmation from phone.\n"); + gprs_llc_process_xid_conf(gph->data, gph->data_len, lle); + /* FIXME: if we had sent a XID reset, send + * LLGMM-RESET.conf to GMM */ + } +} + + +/* Set of LL-XID negotiation (See also: TS 101 351, Section 7.2.2.4) */ +int gprs_ll_xid_req(struct gprs_llc_lle *lle, + struct gprs_llc_xid_field *l3_xid_field) +{ + /* Note: This functions is calle from gprs_sndcp.c */ + + uint8_t xid_bytes[1024];; + int xid_bytes_len; + uint8_t *xid; + struct msgb *msg; + + /* Generate XID */ + xid_bytes_len = + gprs_llc_generate_xid(xid_bytes, sizeof(xid_bytes), + l3_xid_field, lle->llme); + + + /* Only perform XID sending if the XID message contains something */ + if (xid_bytes_len > 0) { + /* Transmit XID bytes */ + msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); + LOGP(DLLC, LOGL_NOTICE, + "Sending XID request to phone...\n"); + gprs_llc_tx_xid(lle, msg, 1); + } else { + LOGP(DLLC, LOGL_ERROR, + "XID-Message generation failed, XID not sent!\n"); + return -EINVAL; + } + + return 0; +} + +/* + * END XID RELATED + */ + + + /* Entry function from upper level (LLC), asking us to transmit a BSSGP PDU * to a remote MS (identified by TLLI) at a BTS identified by its BVCI and NSEI */ @@ -246,11 +564,18 @@ llist_add(&llme->list, &gprs_llc_llmes); + INIT_LLIST_HEAD(&llme->comp.proto); + INIT_LLIST_HEAD(&llme->comp.data); + INIT_LLIST_HEAD(&llme->xid); + return llme; } static void llme_free(struct gprs_llc_llme *llme) { + gprs_sndcp_comp_entities_free(&llme->comp.proto); + gprs_sndcp_comp_entities_free(&llme->comp.data); + gprs_llc_free_xid(&llme->xid); llist_del(&llme->list); talloc_free(llme); } @@ -464,54 +789,6 @@ /* Send BSSGP-DL-UNITDATA.req */ return _bssgp_tx_dl_ud(msg, mmctx); -} - -/* According to 6.4.1.6 / Figure 11 */ -static int msgb_put_xid_par(struct msgb *msg, uint8_t type, uint8_t length, uint8_t *data) -{ - uint8_t header_len = 1; - uint8_t *cur; - - /* type is a 5-bit field... */ - if (type > 0x1f) - return -EINVAL; - - if (length > 3) - header_len = 2; - - cur = msgb_put(msg, length + header_len); - - /* build the header without or with XL bit */ - if (length <= 3) { - *cur++ = (type << 2) | (length & 3); - } else { - *cur++ = 0x80 | (type << 2) | (length >> 6); - *cur++ = (length << 2); - } - - /* copy over the payload of the parameter*/ - memcpy(cur, data, length); - - return length + header_len; -} - -static void rx_llc_xid(struct gprs_llc_lle *lle, - struct gprs_llc_hdr_parsed *gph) -{ - /* FIXME: 8.5.3.3: check if XID is invalid */ - if (gph->is_cmd) { - /* FIXME: implement XID negotiation using SNDCP */ - struct msgb *resp; - uint8_t *xid; - resp = msgb_alloc_headroom(4096, 1024, "LLC_XID"); - xid = msgb_put(resp, gph->data_len); - memcpy(xid, gph->data, gph->data_len); - gprs_llc_tx_xid(lle, resp, 0); - } else { - /* FIXME: if we had sent a XID reset, send - * LLGMM-RESET.conf to GMM */ - /* FIXME: implement XID negotiation using SNDCP */ - } } static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph, @@ -784,17 +1061,24 @@ { struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); struct gprs_llc_lle *lle = &llme->lle[1]; + uint8_t xid_bytes[1024]; + int xid_bytes_len; + uint8_t *xid; + LOGP(DLLC, LOGL_NOTICE, "LLGM Reset\n"); if (RAND_bytes((uint8_t *) &llme->iov_ui, 4) != 1) { LOGP(DLLC, LOGL_NOTICE, "RAND_bytes failed for LLC XID reset, " "falling back to rand()\n"); llme->iov_ui = rand(); } - /* First XID component must be RESET */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL); - /* randomly select new IOV-UI */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &llme->iov_ui); + /* Generate XID message */ + xid_bytes_len = gprs_llc_generate_xid_for_gmm_reset(xid_bytes, + sizeof(xid_bytes),llme->iov_ui,llme); + if(xid_bytes_len < 0) + return -EINVAL; + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); /* Reset some of the LLC parameters. See GSM 04.64, 8.5.3.1 */ lle->vu_recv = 0; @@ -810,17 +1094,24 @@ struct gprs_llc_llme *llme) { struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + uint8_t xid_bytes[1024]; + int xid_bytes_len; + uint8_t *xid; + LOGP(DLLC, LOGL_NOTICE, "LLGM Reset\n"); if (RAND_bytes((uint8_t *) &llme->iov_ui, 4) != 1) { LOGP(DLLC, LOGL_NOTICE, "RAND_bytes failed for LLC XID reset, " "falling back to rand()\n"); llme->iov_ui = rand(); } - /* First XID component must be RESET */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL); - /* randomly select new IOV-UI */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &llme->iov_ui); + /* Generate XID message */ + xid_bytes_len = gprs_llc_generate_xid_for_gmm_reset(xid_bytes, + sizeof(xid_bytes),llme->iov_ui,llme); + if(xid_bytes_len < 0) + return -EINVAL; + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); /* FIXME: Start T200, wait for XID response */ diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index b6036c7..3b34452 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -30,6 +30,11 @@ $(top_builddir)/src/gprs/gprs_gb_parse.o \ $(top_builddir)/src/gprs/oap.o \ $(top_builddir)/src/gprs/oap_messages.o \ + $(top_builddir)/src/gprs/gprs_llc_xid.o \ + $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ + $(top_builddir)/src/gprs/gprs_sndcp_comp_entity.o \ + $(top_builddir)/src/gprs/gprs_sndcp_hdrcomp.o \ + $(top_builddir)/src/gprs/slhc.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ @@ -37,5 +42,5 @@ $(LIBOSMOGB_LIBS) \ $(LIBCARES_LIBS) \ $(LIBCRYPTO_LIBS) \ - -lgtp -lrt + -lgtp -lrt -lm -- To view, visit https://gerrit.osmocom.org/652 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I65b9d625e72d3d61c99abdc7041773701d694d52 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter From gerrit-no-reply at lists.osmocom.org Thu Aug 4 16:16:29 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Thu, 4 Aug 2016 16:16:29 +0000 Subject: [PATCH] osmo-bts[master]: Fill measurements data for L1SAP In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/623 to look at the new patch set (#5). Fill measurements data for L1SAP Fill in values for BER, BTO, Link quality in L1SAP and send them to PCU. Note: this increases the version of BTS <-> PCU protocol. It also requires corresponding changes in libosmocore. All BTS models provide measurements data unless direct DSP access for PCU is enabled. For BTS-specific notes see below. Octphy: conversion from sSNRDb to Link Quality uses formulae which works in practice instead of what's documented for sSNRDb value. Subject to change in future revisions. TRX: C / I link quality estimator is not computed. Change-Id: Ic9693a044756fb1c7bd2ff3cfa0db042c3c4e01c Related: OS#1616 --- M include/osmo-bts/pcu_if.h M include/osmo-bts/pcuif_proto.h M include/osmo-bts/scheduler_backend.h M src/common/l1sap.c M src/common/pcu_sock.c M src/common/scheduler.c M src/osmo-bts-litecell15/l1_if.c M src/osmo-bts-octphy/l1_if.c M src/osmo-bts-sysmo/l1_if.c M src/osmo-bts-trx/scheduler_trx.c 10 files changed, 71 insertions(+), 18 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/23/623/5 diff --git a/include/osmo-bts/pcu_if.h b/include/osmo-bts/pcu_if.h index 3ce4d0b..efad0c5 100644 --- a/include/osmo-bts/pcu_if.h +++ b/include/osmo-bts/pcu_if.h @@ -10,7 +10,7 @@ uint16_t arfcn, uint8_t block_nr); int pcu_tx_data_ind(struct gsm_bts_trx_ts *ts, uint8_t is_ptcch, uint32_t fn, uint16_t arfcn, uint8_t block_nr, uint8_t *data, uint8_t len, - int8_t rssi); + int8_t rssi, uint16_t ber10k, int16_t bto, int16_t lqual); int pcu_tx_rach_ind(struct gsm_bts *bts, int16_t qta, uint8_t ra, uint32_t fn); int pcu_tx_time_ind(uint32_t fn); int pcu_tx_pag_req(const uint8_t *identity_lv, uint8_t chan_needed); diff --git a/include/osmo-bts/pcuif_proto.h b/include/osmo-bts/pcuif_proto.h index 9d740ac..07d35f8 100644 --- a/include/osmo-bts/pcuif_proto.h +++ b/include/osmo-bts/pcuif_proto.h @@ -1,7 +1,7 @@ #ifndef _PCUIF_PROTO_H #define _PCUIF_PROTO_H -#define PCU_IF_VERSION 0x05 +#define PCU_IF_VERSION 0x06 /* msg_type */ #define PCU_IF_MSG_DATA_REQ 0x00 /* send data to given channel */ @@ -50,6 +50,9 @@ uint8_t ts_nr; uint8_t block_nr; int8_t rssi; + uint16_t ber10k; /*!< \brief BER in units of 0.01% */ + int16_t ta_offs_qbits; /* !< \brief Burst TA Offset in quarter bits */ + int16_t lqual_cb; /* !< \brief Link quality in centiBel */ } __attribute__ ((packed)); struct gsm_pcu_if_rts_req { diff --git a/include/osmo-bts/scheduler_backend.h b/include/osmo-bts/scheduler_backend.h index 68f0c60..e63b961 100644 --- a/include/osmo-bts/scheduler_backend.h +++ b/include/osmo-bts/scheduler_backend.h @@ -43,7 +43,11 @@ enum trx_chan_type chan); int _sched_compose_ph_data_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t *l2, uint8_t l2_len, float rssi, enum osmo_ph_pres_info_type presence_info); + enum trx_chan_type chan, uint8_t *l2, + uint8_t l2_len, float rssi, + int16_t ta_offs_qbits, int16_t link_qual_cb, + uint16_t ber10k, + enum osmo_ph_pres_info_type presence_info); int _sched_compose_tch_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t *tch, uint8_t tch_len); diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 7f73e3f..4fc7801 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -812,7 +812,9 @@ if (L1SAP_IS_PTCCH(fn)) { pcu_tx_data_ind(&trx->ts[tn], 1, fn, 0 /* ARFCN */, L1SAP_FN2PTCCHBLOCK(fn), - data, len, rssi); + data, len, rssi, data_ind->ber10k, + data_ind->ta_offs_qbits, + data_ind->lqual_cb); return 0; } @@ -821,7 +823,8 @@ return 0; /* PDTCH / PACCH frame handling */ pcu_tx_data_ind(&trx->ts[tn], 0, fn, 0 /* ARFCN */, - L1SAP_FN2MACBLOCK(fn), data, len, rssi); + L1SAP_FN2MACBLOCK(fn), data, len, rssi, data_ind->ber10k, + data_ind->ta_offs_qbits, data_ind->lqual_cb); return 0; } diff --git a/src/common/pcu_sock.c b/src/common/pcu_sock.c index 22b6fab..fed464f 100644 --- a/src/common/pcu_sock.c +++ b/src/common/pcu_sock.c @@ -337,7 +337,7 @@ int pcu_tx_data_ind(struct gsm_bts_trx_ts *ts, uint8_t is_ptcch, uint32_t fn, uint16_t arfcn, uint8_t block_nr, uint8_t *data, uint8_t len, - int8_t rssi) + int8_t rssi, uint16_t ber10k, int16_t bto, int16_t lqual) { struct msgb *msg; struct gsm_pcu_if *pcu_prim; @@ -362,6 +362,9 @@ data_ind->ts_nr = ts->nr; data_ind->block_nr = block_nr; data_ind->rssi = rssi; + data_ind->ber10k = ber10k; + data_ind->ta_offs_qbits = bto; + data_ind->lqual_cb = lqual; memcpy(data_ind->data, data, len); data_ind->len = len; diff --git a/src/common/scheduler.c b/src/common/scheduler.c index eeaf2c1..ec66cfc 100644 --- a/src/common/scheduler.c +++ b/src/common/scheduler.c @@ -295,7 +295,11 @@ } int _sched_compose_ph_data_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t *l2, uint8_t l2_len, float rssi, enum osmo_ph_pres_info_type presence_info) + enum trx_chan_type chan, uint8_t *l2, + uint8_t l2_len, float rssi, + int16_t ta_offs_qbits, int16_t link_qual_cb, + uint16_t ber10k, + enum osmo_ph_pres_info_type presence_info) { struct msgb *msg; struct osmo_phsap_prim *l1sap; @@ -311,6 +315,9 @@ l1sap->u.data.link_id = trx_chan_desc[chan].link_id; l1sap->u.data.fn = fn; l1sap->u.data.rssi = (int8_t) (rssi); + l1sap->u.data.ber10k = ber10k; + l1sap->u.data.ta_offs_qbits = ta_offs_qbits; + l1sap->u.data.lqual_cb = link_qual_cb; l1sap->u.data.pdch_presence_info = presence_info; msg->l2h = msgb_put(msg, l2_len); if (l2_len) diff --git a/src/osmo-bts-litecell15/l1_if.c b/src/osmo-bts-litecell15/l1_if.c index a979bd7..dcd25ee 100644 --- a/src/osmo-bts-litecell15/l1_if.c +++ b/src/osmo-bts-litecell15/l1_if.c @@ -916,7 +916,11 @@ l1sap->u.data.chan_nr = chan_nr; l1sap->u.data.fn = fn; l1sap->u.data.rssi = rssi; - + if (!pcu_direct) { + l1sap->u.data.ber10k = data_ind->measParam.fBer * 10000; + l1sap->u.data.ta_offs_qbits = data_ind->measParam.i16BurstTiming; + l1sap->u.data.lqual_cb = data_ind->measParam.fLinkQuality * 10; + } return l1sap_up(trx, l1sap); } diff --git a/src/osmo-bts-octphy/l1_if.c b/src/osmo-bts-octphy/l1_if.c index 760c988..d621bcf 100644 --- a/src/osmo-bts-octphy/l1_if.c +++ b/src/osmo-bts-octphy/l1_if.c @@ -961,7 +961,8 @@ struct osmo_phsap_prim *l1sap; uint32_t fn; uint8_t *data; - uint16_t len; + uint16_t len, b_total, b_error; + int16_t snr; int8_t rssi; int rc; @@ -1029,6 +1030,16 @@ l1sap->u.data.chan_nr = chan_nr; l1sap->u.data.fn = fn; l1sap->u.data.rssi = rssi; + b_total = data_ind->MeasurementInfo.usBERTotalBitCnt; + b_error =data_ind->MeasurementInfo.usBERCnt; + l1sap->u.data.ber10k = b_total ? 10000 * b_error / b_total : 0; + l1sap->u.data.ta_offs_qbits = data_ind->MeasurementInfo.sBurstTiming4x; + snr = data_ind->MeasurementInfo.sSNRDb; + /* FIXME: better converion formulae for SnR -> C / I? + l1sap->u.data.lqual_cb = (snr ? snr : (snr - 65536)) * 10 / 256; + LOGP(DL1C, LOGL_ERROR, "SnR: raw %d, computed %d\n", snr, l1sap->u.data.lqual_cb); + */ + l1sap->u.data.lqual_cb = (snr ? snr : (snr - 65536)) * 100; l1sap->u.data.pdch_presence_info = PRES_INFO_BOTH; /* FIXME: consider EDGE support */ l1sap_up(trx, l1sap); diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index 45de199..f70ccf5 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -904,7 +904,11 @@ l1sap->u.data.chan_nr = chan_nr; l1sap->u.data.fn = fn; l1sap->u.data.rssi = (int8_t) (data_ind->measParam.fRssi); - + if (!pcu_direct) { + l1sap->u.data.ber10k = data_ind->measParam.fBer * 10000; + l1sap->u.data.ta_offs_qbits = data_ind->measParam.i16BurstTiming; + l1sap->u.data.lqual_cb = data_ind->measParam.fLinkQuality * 10; + } /* copy data from L1 primitive to L1SAP primitive */ sap_msg->l2h = msgb_put(sap_msg, data_ind->msgUnitParam.u8Size); memcpy(sap_msg->l2h, data_ind->msgUnitParam.u8Buffer, diff --git a/src/osmo-bts-trx/scheduler_trx.c b/src/osmo-bts-trx/scheduler_trx.c index 3a6ede3..e02232b 100644 --- a/src/osmo-bts-trx/scheduler_trx.c +++ b/src/osmo-bts-trx/scheduler_trx.c @@ -200,8 +200,10 @@ /* Send uplnk measurement information to L2 */ l1if_process_meas_res(l1t->trx, tn, fn, trx_chan_desc[chan].chan_nr | tn, 456, 456, -110, 0); - - _sched_compose_ph_data_ind(l1t, tn, 0, chan, NULL, 0, -110, PRES_INFO_INVALID); + /* FIXME: use actual values for BER etc */ + _sched_compose_ph_data_ind(l1t, tn, 0, chan, NULL, 0, + -110, 0, 0, 10000, + PRES_INFO_INVALID); } } @@ -886,8 +888,12 @@ /* Send uplnk measurement information to L2 */ l1if_process_meas_res(l1t->trx, tn, fn, trx_chan_desc[chan].chan_nr | tn, n_errors, n_bits_total, *rssi_sum / *rssi_num, *toa_sum / *toa_num); - - return _sched_compose_ph_data_ind(l1t, tn, *first_fn, chan, l2, l2_len, *rssi_sum / *rssi_num, PRES_INFO_UNKNOWN); + uint16_t ber10k = + (n_bits_total == 0) ? 10000 : 10000 * n_errors / n_bits_total; + return _sched_compose_ph_data_ind(l1t, tn, *first_fn, chan, l2, l2_len, + *rssi_sum / *rssi_num, + 4 * (*toa_sum) / *toa_num, 0, ber10k, + PRES_INFO_UNKNOWN); } int rx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, @@ -985,9 +991,11 @@ l1ts->mf_period, trx_chan_desc[chan].name); return 0; } - + uint16_t ber10k = + (n_bits_total == 0) ? 10000 : 10000 * n_errors / n_bits_total; return _sched_compose_ph_data_ind(l1t, tn, (fn + GSM_HYPERFRAME - 3) % GSM_HYPERFRAME, chan, - l2, rc, *rssi_sum / *rssi_num, PRES_INFO_BOTH); + l2, rc, *rssi_sum / *rssi_num, 4 * (*toa_sum) / *toa_num, 0, + ber10k, PRES_INFO_BOTH); } int rx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, @@ -1105,8 +1113,11 @@ /* FACCH */ if (rc == GSM_MACBLOCK_LEN) { + uint16_t ber10k = (n_bits_total == 0) ? 10000 : + 10000 * n_errors / n_bits_total; _sched_compose_ph_data_ind(l1t, tn, (fn + GSM_HYPERFRAME - 7) % GSM_HYPERFRAME, chan, - tch_data + amr, GSM_MACBLOCK_LEN, rssi, PRES_INFO_UNKNOWN); + tch_data + amr, GSM_MACBLOCK_LEN, rssi, 4 * toa, 0, + ber10k, PRES_INFO_UNKNOWN); bfi: if (rsl_cmode == RSL_CMOD_SPD_SPEECH) { /* indicate bad frame */ @@ -1275,9 +1286,12 @@ /* FACCH */ if (rc == GSM_MACBLOCK_LEN) { chan_state->ul_ongoing_facch = 1; + uint16_t ber10k = + (n_bits_total == 0) ? 10000 : 10000 * n_errors / n_bits_total; _sched_compose_ph_data_ind(l1t, tn, (fn + GSM_HYPERFRAME - 10 - ((fn % 26) >= 19)) % GSM_HYPERFRAME, chan, - tch_data + amr, GSM_MACBLOCK_LEN, rssi, PRES_INFO_UNKNOWN); + tch_data + amr, GSM_MACBLOCK_LEN, rssi, 4 * toa, 0, + ber10k, PRES_INFO_UNKNOWN); bfi: if (rsl_cmode == RSL_CMOD_SPD_SPEECH) { /* indicate bad frame */ -- To view, visit https://gerrit.osmocom.org/623 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ic9693a044756fb1c7bd2ff3cfa0db042c3c4e01c Gerrit-PatchSet: 5 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max From gerrit-no-reply at lists.osmocom.org Thu Aug 4 16:35:18 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 4 Aug 2016 16:35:18 +0000 Subject: osmo-bts[master]: Fill measurements data for L1SAP In-Reply-To: References: Message-ID: Patch Set 5: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/623 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ic9693a044756fb1c7bd2ff3cfa0db042c3c4e01c Gerrit-PatchSet: 5 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 4 16:40:14 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 4 Aug 2016 16:40:14 +0000 Subject: openbsc[master]: XID related modifications in LLC In-Reply-To: References: Message-ID: Patch Set 2: Code-Review-1 (4 comments) https://gerrit.osmocom.org/#/c/652/2/openbsc/src/gprs/gprs_llc.c File openbsc/src/gprs/gprs_llc.c: Line 46: * FIXME: Remove this switch as soon as the XID integration in white space at end of line. Even marked in dark red in gerrit to make you aware of it. Thre are plenty of them, not only in this file / patch. Please try to pay attention to that. PS2, Line 107: int iov_ui why is iov_ui a signed integer? Are you sure that's what llme->iov_ui currently is? Line 110: /* see my other comment on wasting lines for comment start/end PS2, Line 125: randomly select there is no random selection, the entire comment can be removed. -- To view, visit https://gerrit.osmocom.org/652 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I65b9d625e72d3d61c99abdc7041773701d694d52 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Fri Aug 5 06:31:47 2016 From: gerrit-no-reply at lists.osmocom.org (bhargava_abhyankar) Date: Fri, 5 Aug 2016 06:31:47 +0000 Subject: osmo-pcu[master]: Change interface in osmo-pcu for 11 bit RACH In-Reply-To: References: Message-ID: Patch Set 3: As I have addressed all the comments, would like to know the status of the patches. -- To view, visit https://gerrit.osmocom.org/429 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I265c2d92d36d6cbcbeee60cdd8407dafe1da06a4 Gerrit-PatchSet: 3 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: bhargava_abhyankar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Fri Aug 5 06:32:12 2016 From: gerrit-no-reply at lists.osmocom.org (bhargava_abhyankar) Date: Fri, 5 Aug 2016 06:32:12 +0000 Subject: osmo-pcu[master]: Handle EGPRS 11 bit RACH in osmo-pcu In-Reply-To: References: Message-ID: Patch Set 2: As I have addressed all the comments, would like to know the status of the patches. -- To view, visit https://gerrit.osmocom.org/430 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I61d74a32f7764644ed86f7fdf97fa3c2f61503f7 Gerrit-PatchSet: 2 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: bhargava_abhyankar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Fri Aug 5 06:32:19 2016 From: gerrit-no-reply at lists.osmocom.org (bhargava_abhyankar) Date: Fri, 5 Aug 2016 06:32:19 +0000 Subject: osmo-pcu[master]: Update the function immediate assignment for EGPRS In-Reply-To: References: Message-ID: Patch Set 2: As I have addressed all the comments, would like to know the status of the patches. -- To view, visit https://gerrit.osmocom.org/431 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ie5e309156e5dbbb6add74a1b4d257c4ee2332e52 Gerrit-PatchSet: 2 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: bhargava_abhyankar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Fri Aug 5 06:32:34 2016 From: gerrit-no-reply at lists.osmocom.org (bhargava_abhyankar) Date: Fri, 5 Aug 2016 06:32:34 +0000 Subject: osmo-bts[master]: Change interface in osmo-bts for 11 bit RACH In-Reply-To: References: Message-ID: Patch Set 4: As I have addressed all the comments, would like to know the status of the patches. -- To view, visit https://gerrit.osmocom.org/433 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I4f4c501b2d86d77c78de32a84b1804172ffb6f4d Gerrit-PatchSet: 4 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: bhargava_abhyankar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Fri Aug 5 06:32:40 2016 From: gerrit-no-reply at lists.osmocom.org (bhargava_abhyankar) Date: Fri, 5 Aug 2016 06:32:40 +0000 Subject: osmo-bts[master]: Update parameters in osmo-bts-sysmo for 11bit RACH In-Reply-To: References: Message-ID: Patch Set 3: As I have addressed all the comments, would like to know the status of the patches. -- To view, visit https://gerrit.osmocom.org/434 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I93831ddfb3f31b637e6a576f23a9bb4557758582 Gerrit-PatchSet: 3 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: bhargava_abhyankar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Fri Aug 5 08:38:42 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Fri, 5 Aug 2016 08:38:42 +0000 Subject: [PATCH] openbsc[master]: XID related modifications in LLC In-Reply-To: References: Message-ID: Hello Harald Welte, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/652 to look at the new patch set (#3). XID related modifications in LLC With this commit the already existing XID mechanism has been modified to suit the needs for the upcomming SNDCP-XID patches. The SNDCP-XID related calls are currently disabled since the necessary patches for gprs_sndcp.c are not yet pushed. This commit should not break anything since it does not alter the current behaviour (incoming XID is still just echoed, on GMM-Reset a basic XID message is still echoed) Change-Id: I65b9d625e72d3d61c99abdc7041773701d694d52 --- M openbsc/include/openbsc/gprs_llc.h M openbsc/src/gprs/gprs_llc.c M openbsc/tests/sgsn/Makefile.am 3 files changed, 345 insertions(+), 58 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/52/652/3 diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h index 39d17f4..067c114 100644 --- a/openbsc/include/openbsc/gprs_llc.h +++ b/openbsc/include/openbsc/gprs_llc.h @@ -4,6 +4,7 @@ #include #include #include +#include /* Section 4.7 LLC Layer Structure */ enum gprs_llc_sapi { @@ -235,6 +236,10 @@ int gprs_llgmm_reset_oldmsg(struct msgb* oldmsg, uint8_t sapi, struct gprs_llc_llme *llme); +/* Set of LL-XID negotiation (See also: TS 101 351, Section 7.2.2.4) */ +int gprs_ll_xid_req(struct gprs_llc_lle *lle, + struct gprs_llc_xid_field *l3_xid_field); + /* 04.64 Chapter 7.2.1.1 LLGMM-ASSIGN */ int gprs_llgmm_assign(struct gprs_llc_llme *llme, uint32_t old_tlli, uint32_t new_tlli); diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c index 7724ebb..9e85f63 100644 --- a/openbsc/src/gprs/gprs_llc.c +++ b/openbsc/src/gprs/gprs_llc.c @@ -38,8 +38,312 @@ #include #include #include +#include +#include +#include + + +/* FIXME: Remove this switch as soon as the XID integration in + * gprs_sndcp.c h is done */ +#define WITH_SNDCP_XID 1 static struct gprs_llc_llme *llme_alloc(uint32_t tlli); +static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg, + int command); +static int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi, + int command, enum gprs_llc_u_cmd u_cmd, int pf_bit); + +/* BEGIN XID RELATED */ + +/* Generate XID message */ +static int gprs_llc_generate_xid(uint8_t *bytes, int bytes_len, + struct gprs_llc_xid_field *l3_xid_field, + struct gprs_llc_llme *llme) +{ + /* Note: Called by gprs_ll_xid_req() */ + + LLIST_HEAD(xid_fields); + + struct gprs_llc_xid_field xid_version; + struct gprs_llc_xid_field xid_n201u; + struct gprs_llc_xid_field xid_n201i; + + xid_version.type = GPRS_LLC_XID_T_VERSION; + xid_version.data = (uint8_t *) "\x00"; + xid_version.data_len = 1; + + xid_n201u.type = GPRS_LLC_XID_T_N201_U; + xid_n201u.data = (uint8_t *) "\x05\xf0"; + xid_n201u.data_len = 2; + + xid_n201i.type = GPRS_LLC_XID_T_N201_I; + xid_n201i.data = (uint8_t *) "\x05\xf0"; + xid_n201i.data_len = 2; + + /* Add layer 3 XID field (if present) */ + if (l3_xid_field) { + /* Enforce layer 3 XID type (just to be sure) */ + l3_xid_field->type = GPRS_LLC_XID_T_L3_PAR; + + /* Add Layer 3 XID field to the list */ + llist_add(&l3_xid_field->list, &xid_fields); + } + + /* Add locally managed XID Fields */ + llist_add(&xid_n201i.list, &xid_fields); + llist_add(&xid_n201u.list, &xid_fields); + llist_add(&xid_version.list, &xid_fields); + + gprs_llc_copy_xid(&llme->xid, &xid_fields); + + return gprs_llc_compile_xid(&xid_fields, bytes, bytes_len); +} + +/* Generate XID message that will cause the GMM to reset */ +static int gprs_llc_generate_xid_for_gmm_reset(uint8_t *bytes, + int bytes_len, uint32_t iov_ui, + struct gprs_llc_llme *llme) +{ + /* Called by gprs_llgmm_reset() and + * gprs_llgmm_reset_oldmsg() */ + + LLIST_HEAD(xid_fields); + + struct gprs_llc_xid_field xid_reset; + struct gprs_llc_xid_field xid_iovui; + + /* First XID component must be RESET */ + xid_reset.type = GPRS_LLC_XID_T_RESET; + xid_reset.data = NULL; + xid_reset.data_len = 0; + + /* Add new IOV-UI */ + xid_iovui.type = GPRS_LLC_XID_T_IOV_UI; + xid_iovui.data = (uint8_t *) & iov_ui; + xid_iovui.data_len = 4; + + /* Add locally managed XID Fields */ + llist_add(&xid_iovui.list, &xid_fields); + llist_add(&xid_reset.list, &xid_fields); + + gprs_llc_copy_xid(&llme->xid, &xid_fields); + + return gprs_llc_compile_xid(&xid_fields, bytes, bytes_len); +} + +/* Process an incoming XID confirmation */ +static int gprs_llc_process_xid_conf(uint8_t *bytes, int bytes_len, + struct gprs_llc_lle *lle) +{ + /* Note: This function handles the response of a network originated + * XID-Request. There XID messages reflected by the phone are analyzed + * and processed here. The caller is called by rx_llc_xid(). */ + + int rc; + LLIST_HEAD(xid_fields); + struct gprs_llc_xid_field *xid_field; + struct gprs_llc_xid_field *xid_field_request; + struct gprs_llc_xid_field *xid_field_request_l3 = NULL; + + /* Pick layer3 XID from the XID request we have sent last */ + llist_for_each_entry(xid_field_request, &lle->llme->xid, list) { + if (xid_field_request->type == GPRS_LLC_XID_T_L3_PAR) + xid_field_request_l3 = xid_field_request; + } + + /* Parse and analyze XID-Response */ + rc = gprs_llc_parse_xid(&xid_fields, bytes, bytes_len); + if (rc == 0) { + gprs_llc_dump_xid_fields(&xid_fields, LOGL_DEBUG); + + llist_for_each_entry(xid_field, &xid_fields, list) { + + /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { +#if WITH_SNDCP_XID == 1 + sndcp_sn_xid_conf(xid_field, + xid_field_request_l3, + lle); +#endif + } + + /* Process LLC-XID fields: */ + else { + + /* FIXME: Do something more useful with the + * echoed XID-Information. Currently we + * just ignore the response completely and + * by doing so we blindly accept any changes + * the MS might have done to the our XID + * inquiry. There is a remainig risk of + * malfunction! */ + LOGP(DLLC, LOGL_NOTICE, + "Ignoring XID-Field: XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + xid_field->data); + + } + } + } + + /* Flush pending XID fields */ + gprs_llc_free_xid(&lle->llme->xid); + + return 0; +} + + +/* Process an incoming XID indication and generate an appropiate response */ +static int gprs_llc_process_xid_ind(uint8_t *bytes_request, + int bytes_request_len, + uint8_t *bytes_response, + int bytes_response_maxlen, + struct gprs_llc_lle *lle) +{ + /* Note: This function computes the response that is sent back to the + * phone when a phone originated XID is received. The function is + * called by rx_llc_xid() */ + + int rc; + LLIST_HEAD(xid_fields); + LLIST_HEAD(xid_fields_response); + + struct gprs_llc_xid_field *xid_field; + struct gprs_llc_xid_field *xid_field_response; + + /* Flush eventually pending XID fields */ + gprs_llc_free_xid(&lle->llme->xid); + + /* Parse and analyze XID-Request */ + rc = gprs_llc_parse_xid(&xid_fields, bytes_request, + bytes_request_len); + if (rc == 0) { + gprs_llc_dump_xid_fields(&xid_fields, LOGL_DEBUG); + + llist_for_each_entry(xid_field, &xid_fields, list) { + /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { +#if WITH_SNDCP_XID == 1 + xid_field_response = + talloc_zero(NULL, + struct gprs_llc_xid_field); + rc = sndcp_sn_xid_ind(xid_field, + xid_field_response, + lle); + if (rc == 0) + llist_add(&xid_field_response-> + list, + &xid_fields_response); + else + talloc_free(xid_field_response); +#endif + } + + /* Process LLC-XID fields: */ + else { + /* FIXME: Check the incoming XID parameters for + * for validity. Currently we just blindly + * accept all XID fields by just echoing them. + * There is a remaining risk of malfunction + * when a phone submits values which defer from + * the default! */ + LOGP(DLLC, LOGL_NOTICE, + "Echoing XID-Field: XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + osmo_hexdump_nospc(xid_field->data, + xid_field-> + data_len)); + xid_field_response = + gprs_llc_duplicate_xid_field + (xid_field); + llist_add(&xid_field_response->list, + &xid_fields_response); + } + } + + rc = gprs_llc_compile_xid(&xid_fields_response, + bytes_response, + bytes_response_maxlen); + gprs_llc_free_xid(&xid_fields_response); + } + gprs_llc_free_xid(&xid_fields); + + return rc; +} + +/* Dispatch XID indications and responses comming from the Phone */ +static void rx_llc_xid(struct gprs_llc_lle *lle, + struct gprs_llc_hdr_parsed *gph) +{ + uint8_t response[1024]; + int response_len; + + /* FIXME: 8.5.3.3: check if XID is invalid */ + if (gph->is_cmd) { + LOGP(DLLC, LOGL_NOTICE, + "Received XID indication from phone.\n"); + + struct msgb *resp; + uint8_t *xid; + resp = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + + response_len = + gprs_llc_process_xid_ind(gph->data, gph->data_len, + response, sizeof(response), + lle); + xid = msgb_put(resp, response_len); + memcpy(xid, response, response_len); + + gprs_llc_tx_xid(lle, resp, 0); + } else { + LOGP(DLLC, LOGL_NOTICE, + "Received XID confirmation from phone.\n"); + gprs_llc_process_xid_conf(gph->data, gph->data_len, lle); + /* FIXME: if we had sent a XID reset, send + * LLGMM-RESET.conf to GMM */ + } +} + + +/* Set of LL-XID negotiation (See also: TS 101 351, Section 7.2.2.4) */ +int gprs_ll_xid_req(struct gprs_llc_lle *lle, + struct gprs_llc_xid_field *l3_xid_field) +{ + /* Note: This functions is calle from gprs_sndcp.c */ + + uint8_t xid_bytes[1024];; + int xid_bytes_len; + uint8_t *xid; + struct msgb *msg; + + /* Generate XID */ + xid_bytes_len = + gprs_llc_generate_xid(xid_bytes, sizeof(xid_bytes), + l3_xid_field, lle->llme); + + + /* Only perform XID sending if the XID message contains something */ + if (xid_bytes_len > 0) { + /* Transmit XID bytes */ + msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); + LOGP(DLLC, LOGL_NOTICE, + "Sending XID request to phone...\n"); + gprs_llc_tx_xid(lle, msg, 1); + } else { + LOGP(DLLC, LOGL_ERROR, + "XID-Message generation failed, XID not sent!\n"); + return -EINVAL; + } + + return 0; +} + +/* END XID RELATED */ + + + /* Entry function from upper level (LLC), asking us to transmit a BSSGP PDU * to a remote MS (identified by TLLI) at a BTS identified by its BVCI and NSEI */ @@ -51,7 +355,7 @@ memset(&dup, 0, sizeof(dup)); /* before we have received some identity from the MS, we might * not yet have a MMC context (e.g. XID negotiation of primarly - * LLC connection fro GMM sapi). */ + * LLC connection from GMM sapi). */ if (mmctx) { dup.imsi = mmctx->imsi; dup.drx_parms = mmctx->drx_parms; @@ -246,11 +550,18 @@ llist_add(&llme->list, &gprs_llc_llmes); + INIT_LLIST_HEAD(&llme->comp.proto); + INIT_LLIST_HEAD(&llme->comp.data); + INIT_LLIST_HEAD(&llme->xid); + return llme; } static void llme_free(struct gprs_llc_llme *llme) { + gprs_sndcp_comp_entities_free(&llme->comp.proto); + gprs_sndcp_comp_entities_free(&llme->comp.data); + gprs_llc_free_xid(&llme->xid); llist_del(&llme->list); talloc_free(llme); } @@ -464,54 +775,6 @@ /* Send BSSGP-DL-UNITDATA.req */ return _bssgp_tx_dl_ud(msg, mmctx); -} - -/* According to 6.4.1.6 / Figure 11 */ -static int msgb_put_xid_par(struct msgb *msg, uint8_t type, uint8_t length, uint8_t *data) -{ - uint8_t header_len = 1; - uint8_t *cur; - - /* type is a 5-bit field... */ - if (type > 0x1f) - return -EINVAL; - - if (length > 3) - header_len = 2; - - cur = msgb_put(msg, length + header_len); - - /* build the header without or with XL bit */ - if (length <= 3) { - *cur++ = (type << 2) | (length & 3); - } else { - *cur++ = 0x80 | (type << 2) | (length >> 6); - *cur++ = (length << 2); - } - - /* copy over the payload of the parameter*/ - memcpy(cur, data, length); - - return length + header_len; -} - -static void rx_llc_xid(struct gprs_llc_lle *lle, - struct gprs_llc_hdr_parsed *gph) -{ - /* FIXME: 8.5.3.3: check if XID is invalid */ - if (gph->is_cmd) { - /* FIXME: implement XID negotiation using SNDCP */ - struct msgb *resp; - uint8_t *xid; - resp = msgb_alloc_headroom(4096, 1024, "LLC_XID"); - xid = msgb_put(resp, gph->data_len); - memcpy(xid, gph->data, gph->data_len); - gprs_llc_tx_xid(lle, resp, 0); - } else { - /* FIXME: if we had sent a XID reset, send - * LLGMM-RESET.conf to GMM */ - /* FIXME: implement XID negotiation using SNDCP */ - } } static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph, @@ -784,17 +1047,24 @@ { struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); struct gprs_llc_lle *lle = &llme->lle[1]; + uint8_t xid_bytes[1024]; + int xid_bytes_len; + uint8_t *xid; + LOGP(DLLC, LOGL_NOTICE, "LLGM Reset\n"); if (RAND_bytes((uint8_t *) &llme->iov_ui, 4) != 1) { LOGP(DLLC, LOGL_NOTICE, "RAND_bytes failed for LLC XID reset, " "falling back to rand()\n"); llme->iov_ui = rand(); } - /* First XID component must be RESET */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL); - /* randomly select new IOV-UI */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &llme->iov_ui); + /* Generate XID message */ + xid_bytes_len = gprs_llc_generate_xid_for_gmm_reset(xid_bytes, + sizeof(xid_bytes),llme->iov_ui,llme); + if(xid_bytes_len < 0) + return -EINVAL; + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); /* Reset some of the LLC parameters. See GSM 04.64, 8.5.3.1 */ lle->vu_recv = 0; @@ -810,17 +1080,24 @@ struct gprs_llc_llme *llme) { struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + uint8_t xid_bytes[1024]; + int xid_bytes_len; + uint8_t *xid; + LOGP(DLLC, LOGL_NOTICE, "LLGM Reset\n"); if (RAND_bytes((uint8_t *) &llme->iov_ui, 4) != 1) { LOGP(DLLC, LOGL_NOTICE, "RAND_bytes failed for LLC XID reset, " "falling back to rand()\n"); llme->iov_ui = rand(); } - /* First XID component must be RESET */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL); - /* randomly select new IOV-UI */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &llme->iov_ui); + /* Generate XID message */ + xid_bytes_len = gprs_llc_generate_xid_for_gmm_reset(xid_bytes, + sizeof(xid_bytes),llme->iov_ui,llme); + if(xid_bytes_len < 0) + return -EINVAL; + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); /* FIXME: Start T200, wait for XID response */ diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index b6036c7..3b34452 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -30,6 +30,11 @@ $(top_builddir)/src/gprs/gprs_gb_parse.o \ $(top_builddir)/src/gprs/oap.o \ $(top_builddir)/src/gprs/oap_messages.o \ + $(top_builddir)/src/gprs/gprs_llc_xid.o \ + $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ + $(top_builddir)/src/gprs/gprs_sndcp_comp_entity.o \ + $(top_builddir)/src/gprs/gprs_sndcp_hdrcomp.o \ + $(top_builddir)/src/gprs/slhc.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ @@ -37,5 +42,5 @@ $(LIBOSMOGB_LIBS) \ $(LIBCARES_LIBS) \ $(LIBCRYPTO_LIBS) \ - -lgtp -lrt + -lgtp -lrt -lm -- To view, visit https://gerrit.osmocom.org/652 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I65b9d625e72d3d61c99abdc7041773701d694d52 Gerrit-PatchSet: 3 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte From gerrit-no-reply at lists.osmocom.org Fri Aug 5 08:42:58 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Fri, 5 Aug 2016 08:42:58 +0000 Subject: [PATCH] openbsc[master]: XID related modifications in LLC In-Reply-To: References: Message-ID: Hello Harald Welte, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/652 to look at the new patch set (#4). XID related modifications in LLC With this commit the already existing XID mechanism has been modified to suit the needs for the upcomming SNDCP-XID patches. The SNDCP-XID related calls are currently disabled since the necessary patches for gprs_sndcp.c are not yet pushed. This commit should not break anything since it does not alter the current behaviour (incoming XID is still just echoed, on GMM-Reset a basic XID message is still echoed) Change-Id: I65b9d625e72d3d61c99abdc7041773701d694d52 --- M openbsc/include/openbsc/gprs_llc.h M openbsc/src/gprs/gprs_llc.c M openbsc/tests/sgsn/Makefile.am 3 files changed, 347 insertions(+), 62 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/52/652/4 diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h index 39d17f4..8b93784 100644 --- a/openbsc/include/openbsc/gprs_llc.h +++ b/openbsc/include/openbsc/gprs_llc.h @@ -4,6 +4,7 @@ #include #include #include +#include /* Section 4.7 LLC Layer Structure */ enum gprs_llc_sapi { @@ -148,10 +149,8 @@ /* Lists holding the compression entities */ struct comp_ent { - /* - * In this two list_heads we will store the data and protocol - * compression entities, together with their compression states - */ + /* In this two list_heads we will store the data and protocol + * compression entities, together with their compression states */ struct llist_head proto; struct llist_head data; }; @@ -235,6 +234,10 @@ int gprs_llgmm_reset_oldmsg(struct msgb* oldmsg, uint8_t sapi, struct gprs_llc_llme *llme); +/* Set of LL-XID negotiation (See also: TS 101 351, Section 7.2.2.4) */ +int gprs_ll_xid_req(struct gprs_llc_lle *lle, + struct gprs_llc_xid_field *l3_xid_field); + /* 04.64 Chapter 7.2.1.1 LLGMM-ASSIGN */ int gprs_llgmm_assign(struct gprs_llc_llme *llme, uint32_t old_tlli, uint32_t new_tlli); diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c index 7724ebb..9e85f63 100644 --- a/openbsc/src/gprs/gprs_llc.c +++ b/openbsc/src/gprs/gprs_llc.c @@ -38,8 +38,312 @@ #include #include #include +#include +#include +#include + + +/* FIXME: Remove this switch as soon as the XID integration in + * gprs_sndcp.c h is done */ +#define WITH_SNDCP_XID 1 static struct gprs_llc_llme *llme_alloc(uint32_t tlli); +static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg, + int command); +static int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi, + int command, enum gprs_llc_u_cmd u_cmd, int pf_bit); + +/* BEGIN XID RELATED */ + +/* Generate XID message */ +static int gprs_llc_generate_xid(uint8_t *bytes, int bytes_len, + struct gprs_llc_xid_field *l3_xid_field, + struct gprs_llc_llme *llme) +{ + /* Note: Called by gprs_ll_xid_req() */ + + LLIST_HEAD(xid_fields); + + struct gprs_llc_xid_field xid_version; + struct gprs_llc_xid_field xid_n201u; + struct gprs_llc_xid_field xid_n201i; + + xid_version.type = GPRS_LLC_XID_T_VERSION; + xid_version.data = (uint8_t *) "\x00"; + xid_version.data_len = 1; + + xid_n201u.type = GPRS_LLC_XID_T_N201_U; + xid_n201u.data = (uint8_t *) "\x05\xf0"; + xid_n201u.data_len = 2; + + xid_n201i.type = GPRS_LLC_XID_T_N201_I; + xid_n201i.data = (uint8_t *) "\x05\xf0"; + xid_n201i.data_len = 2; + + /* Add layer 3 XID field (if present) */ + if (l3_xid_field) { + /* Enforce layer 3 XID type (just to be sure) */ + l3_xid_field->type = GPRS_LLC_XID_T_L3_PAR; + + /* Add Layer 3 XID field to the list */ + llist_add(&l3_xid_field->list, &xid_fields); + } + + /* Add locally managed XID Fields */ + llist_add(&xid_n201i.list, &xid_fields); + llist_add(&xid_n201u.list, &xid_fields); + llist_add(&xid_version.list, &xid_fields); + + gprs_llc_copy_xid(&llme->xid, &xid_fields); + + return gprs_llc_compile_xid(&xid_fields, bytes, bytes_len); +} + +/* Generate XID message that will cause the GMM to reset */ +static int gprs_llc_generate_xid_for_gmm_reset(uint8_t *bytes, + int bytes_len, uint32_t iov_ui, + struct gprs_llc_llme *llme) +{ + /* Called by gprs_llgmm_reset() and + * gprs_llgmm_reset_oldmsg() */ + + LLIST_HEAD(xid_fields); + + struct gprs_llc_xid_field xid_reset; + struct gprs_llc_xid_field xid_iovui; + + /* First XID component must be RESET */ + xid_reset.type = GPRS_LLC_XID_T_RESET; + xid_reset.data = NULL; + xid_reset.data_len = 0; + + /* Add new IOV-UI */ + xid_iovui.type = GPRS_LLC_XID_T_IOV_UI; + xid_iovui.data = (uint8_t *) & iov_ui; + xid_iovui.data_len = 4; + + /* Add locally managed XID Fields */ + llist_add(&xid_iovui.list, &xid_fields); + llist_add(&xid_reset.list, &xid_fields); + + gprs_llc_copy_xid(&llme->xid, &xid_fields); + + return gprs_llc_compile_xid(&xid_fields, bytes, bytes_len); +} + +/* Process an incoming XID confirmation */ +static int gprs_llc_process_xid_conf(uint8_t *bytes, int bytes_len, + struct gprs_llc_lle *lle) +{ + /* Note: This function handles the response of a network originated + * XID-Request. There XID messages reflected by the phone are analyzed + * and processed here. The caller is called by rx_llc_xid(). */ + + int rc; + LLIST_HEAD(xid_fields); + struct gprs_llc_xid_field *xid_field; + struct gprs_llc_xid_field *xid_field_request; + struct gprs_llc_xid_field *xid_field_request_l3 = NULL; + + /* Pick layer3 XID from the XID request we have sent last */ + llist_for_each_entry(xid_field_request, &lle->llme->xid, list) { + if (xid_field_request->type == GPRS_LLC_XID_T_L3_PAR) + xid_field_request_l3 = xid_field_request; + } + + /* Parse and analyze XID-Response */ + rc = gprs_llc_parse_xid(&xid_fields, bytes, bytes_len); + if (rc == 0) { + gprs_llc_dump_xid_fields(&xid_fields, LOGL_DEBUG); + + llist_for_each_entry(xid_field, &xid_fields, list) { + + /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { +#if WITH_SNDCP_XID == 1 + sndcp_sn_xid_conf(xid_field, + xid_field_request_l3, + lle); +#endif + } + + /* Process LLC-XID fields: */ + else { + + /* FIXME: Do something more useful with the + * echoed XID-Information. Currently we + * just ignore the response completely and + * by doing so we blindly accept any changes + * the MS might have done to the our XID + * inquiry. There is a remainig risk of + * malfunction! */ + LOGP(DLLC, LOGL_NOTICE, + "Ignoring XID-Field: XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + xid_field->data); + + } + } + } + + /* Flush pending XID fields */ + gprs_llc_free_xid(&lle->llme->xid); + + return 0; +} + + +/* Process an incoming XID indication and generate an appropiate response */ +static int gprs_llc_process_xid_ind(uint8_t *bytes_request, + int bytes_request_len, + uint8_t *bytes_response, + int bytes_response_maxlen, + struct gprs_llc_lle *lle) +{ + /* Note: This function computes the response that is sent back to the + * phone when a phone originated XID is received. The function is + * called by rx_llc_xid() */ + + int rc; + LLIST_HEAD(xid_fields); + LLIST_HEAD(xid_fields_response); + + struct gprs_llc_xid_field *xid_field; + struct gprs_llc_xid_field *xid_field_response; + + /* Flush eventually pending XID fields */ + gprs_llc_free_xid(&lle->llme->xid); + + /* Parse and analyze XID-Request */ + rc = gprs_llc_parse_xid(&xid_fields, bytes_request, + bytes_request_len); + if (rc == 0) { + gprs_llc_dump_xid_fields(&xid_fields, LOGL_DEBUG); + + llist_for_each_entry(xid_field, &xid_fields, list) { + /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { +#if WITH_SNDCP_XID == 1 + xid_field_response = + talloc_zero(NULL, + struct gprs_llc_xid_field); + rc = sndcp_sn_xid_ind(xid_field, + xid_field_response, + lle); + if (rc == 0) + llist_add(&xid_field_response-> + list, + &xid_fields_response); + else + talloc_free(xid_field_response); +#endif + } + + /* Process LLC-XID fields: */ + else { + /* FIXME: Check the incoming XID parameters for + * for validity. Currently we just blindly + * accept all XID fields by just echoing them. + * There is a remaining risk of malfunction + * when a phone submits values which defer from + * the default! */ + LOGP(DLLC, LOGL_NOTICE, + "Echoing XID-Field: XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + osmo_hexdump_nospc(xid_field->data, + xid_field-> + data_len)); + xid_field_response = + gprs_llc_duplicate_xid_field + (xid_field); + llist_add(&xid_field_response->list, + &xid_fields_response); + } + } + + rc = gprs_llc_compile_xid(&xid_fields_response, + bytes_response, + bytes_response_maxlen); + gprs_llc_free_xid(&xid_fields_response); + } + gprs_llc_free_xid(&xid_fields); + + return rc; +} + +/* Dispatch XID indications and responses comming from the Phone */ +static void rx_llc_xid(struct gprs_llc_lle *lle, + struct gprs_llc_hdr_parsed *gph) +{ + uint8_t response[1024]; + int response_len; + + /* FIXME: 8.5.3.3: check if XID is invalid */ + if (gph->is_cmd) { + LOGP(DLLC, LOGL_NOTICE, + "Received XID indication from phone.\n"); + + struct msgb *resp; + uint8_t *xid; + resp = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + + response_len = + gprs_llc_process_xid_ind(gph->data, gph->data_len, + response, sizeof(response), + lle); + xid = msgb_put(resp, response_len); + memcpy(xid, response, response_len); + + gprs_llc_tx_xid(lle, resp, 0); + } else { + LOGP(DLLC, LOGL_NOTICE, + "Received XID confirmation from phone.\n"); + gprs_llc_process_xid_conf(gph->data, gph->data_len, lle); + /* FIXME: if we had sent a XID reset, send + * LLGMM-RESET.conf to GMM */ + } +} + + +/* Set of LL-XID negotiation (See also: TS 101 351, Section 7.2.2.4) */ +int gprs_ll_xid_req(struct gprs_llc_lle *lle, + struct gprs_llc_xid_field *l3_xid_field) +{ + /* Note: This functions is calle from gprs_sndcp.c */ + + uint8_t xid_bytes[1024];; + int xid_bytes_len; + uint8_t *xid; + struct msgb *msg; + + /* Generate XID */ + xid_bytes_len = + gprs_llc_generate_xid(xid_bytes, sizeof(xid_bytes), + l3_xid_field, lle->llme); + + + /* Only perform XID sending if the XID message contains something */ + if (xid_bytes_len > 0) { + /* Transmit XID bytes */ + msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); + LOGP(DLLC, LOGL_NOTICE, + "Sending XID request to phone...\n"); + gprs_llc_tx_xid(lle, msg, 1); + } else { + LOGP(DLLC, LOGL_ERROR, + "XID-Message generation failed, XID not sent!\n"); + return -EINVAL; + } + + return 0; +} + +/* END XID RELATED */ + + + /* Entry function from upper level (LLC), asking us to transmit a BSSGP PDU * to a remote MS (identified by TLLI) at a BTS identified by its BVCI and NSEI */ @@ -51,7 +355,7 @@ memset(&dup, 0, sizeof(dup)); /* before we have received some identity from the MS, we might * not yet have a MMC context (e.g. XID negotiation of primarly - * LLC connection fro GMM sapi). */ + * LLC connection from GMM sapi). */ if (mmctx) { dup.imsi = mmctx->imsi; dup.drx_parms = mmctx->drx_parms; @@ -246,11 +550,18 @@ llist_add(&llme->list, &gprs_llc_llmes); + INIT_LLIST_HEAD(&llme->comp.proto); + INIT_LLIST_HEAD(&llme->comp.data); + INIT_LLIST_HEAD(&llme->xid); + return llme; } static void llme_free(struct gprs_llc_llme *llme) { + gprs_sndcp_comp_entities_free(&llme->comp.proto); + gprs_sndcp_comp_entities_free(&llme->comp.data); + gprs_llc_free_xid(&llme->xid); llist_del(&llme->list); talloc_free(llme); } @@ -464,54 +775,6 @@ /* Send BSSGP-DL-UNITDATA.req */ return _bssgp_tx_dl_ud(msg, mmctx); -} - -/* According to 6.4.1.6 / Figure 11 */ -static int msgb_put_xid_par(struct msgb *msg, uint8_t type, uint8_t length, uint8_t *data) -{ - uint8_t header_len = 1; - uint8_t *cur; - - /* type is a 5-bit field... */ - if (type > 0x1f) - return -EINVAL; - - if (length > 3) - header_len = 2; - - cur = msgb_put(msg, length + header_len); - - /* build the header without or with XL bit */ - if (length <= 3) { - *cur++ = (type << 2) | (length & 3); - } else { - *cur++ = 0x80 | (type << 2) | (length >> 6); - *cur++ = (length << 2); - } - - /* copy over the payload of the parameter*/ - memcpy(cur, data, length); - - return length + header_len; -} - -static void rx_llc_xid(struct gprs_llc_lle *lle, - struct gprs_llc_hdr_parsed *gph) -{ - /* FIXME: 8.5.3.3: check if XID is invalid */ - if (gph->is_cmd) { - /* FIXME: implement XID negotiation using SNDCP */ - struct msgb *resp; - uint8_t *xid; - resp = msgb_alloc_headroom(4096, 1024, "LLC_XID"); - xid = msgb_put(resp, gph->data_len); - memcpy(xid, gph->data, gph->data_len); - gprs_llc_tx_xid(lle, resp, 0); - } else { - /* FIXME: if we had sent a XID reset, send - * LLGMM-RESET.conf to GMM */ - /* FIXME: implement XID negotiation using SNDCP */ - } } static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph, @@ -784,17 +1047,24 @@ { struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); struct gprs_llc_lle *lle = &llme->lle[1]; + uint8_t xid_bytes[1024]; + int xid_bytes_len; + uint8_t *xid; + LOGP(DLLC, LOGL_NOTICE, "LLGM Reset\n"); if (RAND_bytes((uint8_t *) &llme->iov_ui, 4) != 1) { LOGP(DLLC, LOGL_NOTICE, "RAND_bytes failed for LLC XID reset, " "falling back to rand()\n"); llme->iov_ui = rand(); } - /* First XID component must be RESET */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL); - /* randomly select new IOV-UI */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &llme->iov_ui); + /* Generate XID message */ + xid_bytes_len = gprs_llc_generate_xid_for_gmm_reset(xid_bytes, + sizeof(xid_bytes),llme->iov_ui,llme); + if(xid_bytes_len < 0) + return -EINVAL; + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); /* Reset some of the LLC parameters. See GSM 04.64, 8.5.3.1 */ lle->vu_recv = 0; @@ -810,17 +1080,24 @@ struct gprs_llc_llme *llme) { struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + uint8_t xid_bytes[1024]; + int xid_bytes_len; + uint8_t *xid; + LOGP(DLLC, LOGL_NOTICE, "LLGM Reset\n"); if (RAND_bytes((uint8_t *) &llme->iov_ui, 4) != 1) { LOGP(DLLC, LOGL_NOTICE, "RAND_bytes failed for LLC XID reset, " "falling back to rand()\n"); llme->iov_ui = rand(); } - /* First XID component must be RESET */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL); - /* randomly select new IOV-UI */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &llme->iov_ui); + /* Generate XID message */ + xid_bytes_len = gprs_llc_generate_xid_for_gmm_reset(xid_bytes, + sizeof(xid_bytes),llme->iov_ui,llme); + if(xid_bytes_len < 0) + return -EINVAL; + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); /* FIXME: Start T200, wait for XID response */ diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index b6036c7..3b34452 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -30,6 +30,11 @@ $(top_builddir)/src/gprs/gprs_gb_parse.o \ $(top_builddir)/src/gprs/oap.o \ $(top_builddir)/src/gprs/oap_messages.o \ + $(top_builddir)/src/gprs/gprs_llc_xid.o \ + $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ + $(top_builddir)/src/gprs/gprs_sndcp_comp_entity.o \ + $(top_builddir)/src/gprs/gprs_sndcp_hdrcomp.o \ + $(top_builddir)/src/gprs/slhc.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ @@ -37,5 +42,5 @@ $(LIBOSMOGB_LIBS) \ $(LIBCARES_LIBS) \ $(LIBCRYPTO_LIBS) \ - -lgtp -lrt + -lgtp -lrt -lm -- To view, visit https://gerrit.osmocom.org/652 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I65b9d625e72d3d61c99abdc7041773701d694d52 Gerrit-PatchSet: 4 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte From gerrit-no-reply at lists.osmocom.org Fri Aug 5 08:49:26 2016 From: gerrit-no-reply at lists.osmocom.org (prasadkg) Date: Fri, 5 Aug 2016 08:49:26 +0000 Subject: osmo-pcu[master]: Add test case for testing PUAN In-Reply-To: References: Message-ID: Patch Set 1: I see that acceptance of t4 decoding is taking longer time. I think PUAN bugfixes and test can be taken independently. Let me know if I can re-submit these patches with comments fixed for review and merger. -- To view, visit https://gerrit.osmocom.org/414 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I18e6d4a9e90fd6453fe14187beab27dfeae8dbe9 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: prasadkg Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: prasadkg Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Fri Aug 5 09:35:03 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Fri, 5 Aug 2016 09:35:03 +0000 Subject: [PATCH] openbsc[master]: Added V42BIS implementation In-Reply-To: References: Message-ID: Hello Harald Welte, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/643 to look at the new patch set (#8). Added V42BIS implementation V42BIS is a data compression method found in modems. It has also been specified for GPRS as data compression algorithm. The implementation has been taken from SPANDSP. There are several sources around. Asterisk and Freeswitch are using SPANDSP and its also available separately. The implementation in this commit has been taken from: https://github.com/jart/spandsp.git commit 6de1983b251806d59bb3149b7a2d7ebc99ace5aa Change-Id: Iabedece9f97ca944a1e3f747bb073e532c4e9dca --- A openbsc/include/openbsc/private_v42bis.h A openbsc/include/openbsc/v42bis.h A openbsc/src/gprs/v42bis.c 3 files changed, 1,036 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/43/643/8 diff --git a/openbsc/include/openbsc/private_v42bis.h b/openbsc/include/openbsc/private_v42bis.h new file mode 100644 index 0000000..96538f2 --- /dev/null +++ b/openbsc/include/openbsc/private_v42bis.h @@ -0,0 +1,151 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * private/v42bis.h + * + * Written by Steve Underwood + * + * Copyright (C) 2005 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: v42bis.h,v 1.1 2008/11/15 14:43:08 steveu Exp $ + */ + +#if !defined(_SPANDSP_PRIVATE_V42BIS_H_) +#define _SPANDSP_PRIVATE_V42BIS_H_ + +/*! + V.42bis dictionary node. +*/ +typedef struct +{ + /*! \brief The prior code for each defined code. */ + uint16_t parent_code; + /*! \brief The number of leaf nodes this node has */ + int16_t leaves; + /*! \brief This leaf octet for each defined code. */ + uint8_t node_octet; + /*! \brief Bit map of the children which exist */ + uint32_t children[8]; +} v42bis_dict_node_t; + +/*! + V.42bis compression. This defines the working state for a single instance + of V.42bis compression. +*/ +typedef struct +{ + /*! \brief Compression mode. */ + int compression_mode; + /*! \brief Callback function to handle received frames. */ + v42bis_frame_handler_t handler; + /*! \brief An opaque pointer passed in calls to frame_handler. */ + void *user_data; + /*! \brief The maximum frame length allowed */ + int max_len; + + uint32_t string_code; + uint32_t latest_code; + int string_length; + uint32_t output_bit_buffer; + int output_bit_count; + int output_octet_count; + uint8_t output_buf[1024]; + v42bis_dict_node_t dict[V42BIS_MAX_CODEWORDS]; + /*! \brief TRUE if we are in transparent (i.e. uncompressable) mode */ + int transparent; + int change_transparency; + /*! \brief IIR filter state, used in assessing compressibility. */ + int compressibility_filter; + int compressibility_persistence; + + /*! \brief Next empty dictionary entry */ + uint32_t v42bis_parm_c1; + /*! \brief Current codeword size */ + int v42bis_parm_c2; + /*! \brief Threshold for codeword size change */ + uint32_t v42bis_parm_c3; + + /*! \brief Mark that this is the first octet/code to be processed */ + int first; + uint8_t escape_code; +} v42bis_compress_state_t; + +/*! + V.42bis decompression. This defines the working state for a single instance + of V.42bis decompression. +*/ +typedef struct +{ + /*! \brief Callback function to handle decompressed data. */ + v42bis_data_handler_t handler; + /*! \brief An opaque pointer passed in calls to data_handler. */ + void *user_data; + /*! \brief The maximum decompressed data block length allowed */ + int max_len; + + uint32_t old_code; + uint32_t last_old_code; + uint32_t input_bit_buffer; + int input_bit_count; + int octet; + int last_length; + int output_octet_count; + uint8_t output_buf[1024]; + v42bis_dict_node_t dict[V42BIS_MAX_CODEWORDS]; + /*! \brief TRUE if we are in transparent (i.e. uncompressable) mode */ + int transparent; + + int last_extra_octet; + + /*! \brief Next empty dictionary entry */ + uint32_t v42bis_parm_c1; + /*! \brief Current codeword size */ + int v42bis_parm_c2; + /*! \brief Threshold for codeword size change */ + uint32_t v42bis_parm_c3; + + /*! \brief Mark that this is the first octet/code to be processed */ + int first; + uint8_t escape_code; + int escaped; +} v42bis_decompress_state_t; + +/*! + V.42bis compression/decompression descriptor. This defines the working state for a + single instance of V.42bis compress/decompression. +*/ +struct v42bis_state_s +{ + /*! \brief V.42bis data compression directions. */ + int v42bis_parm_p0; + + /*! \brief Compression state. */ + v42bis_compress_state_t compress; + /*! \brief Decompression state. */ + v42bis_decompress_state_t decompress; + + /*! \brief Maximum codeword size (bits) */ + int v42bis_parm_n1; + /*! \brief Total number of codewords */ + uint32_t v42bis_parm_n2; + /*! \brief Maximum string length */ + int v42bis_parm_n7; +}; + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/openbsc/include/openbsc/v42bis.h b/openbsc/include/openbsc/v42bis.h new file mode 100644 index 0000000..f13e5c5 --- /dev/null +++ b/openbsc/include/openbsc/v42bis.h @@ -0,0 +1,143 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * v42bis.h + * + * Written by Steve Underwood + * + * Copyright (C) 2005 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: v42bis.h,v 1.27 2009/04/11 18:11:19 steveu Exp $ + */ + +/*! \page v42bis_page V.42bis modem data compression +\section v42bis_page_sec_1 What does it do? +The v.42bis specification defines a data compression scheme, to work in +conjunction with the error correction scheme defined in V.42. + +\section v42bis_page_sec_2 How does it work? +*/ + +#if !defined(_SPANDSP_V42BIS_H_) +#define _SPANDSP_V42BIS_H_ + +#define V42BIS_MAX_BITS 12 +#define V42BIS_MAX_CODEWORDS 4096 /* 2^V42BIS_MAX_BITS */ +#define V42BIS_TABLE_SIZE 5021 /* This should be a prime >(2^V42BIS_MAX_BITS) */ +#define V42BIS_MAX_STRING_SIZE 250 + +enum +{ + V42BIS_P0_NEITHER_DIRECTION = 0, + V42BIS_P0_INITIATOR_RESPONDER, + V42BIS_P0_RESPONDER_INITIATOR, + V42BIS_P0_BOTH_DIRECTIONS +}; + +enum +{ + V42BIS_COMPRESSION_MODE_DYNAMIC = 0, + V42BIS_COMPRESSION_MODE_ALWAYS, + V42BIS_COMPRESSION_MODE_NEVER +}; + +typedef void (*v42bis_frame_handler_t)(void *user_data, const uint8_t *pkt, int len); +typedef void (*v42bis_data_handler_t)(void *user_data, const uint8_t *buf, int len); + +/*! + V.42bis compression/decompression descriptor. This defines the working state for a + single instance of V.42bis compress/decompression. +*/ +typedef struct v42bis_state_s v42bis_state_t; + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/*! Compress a block of octets. + \param s The V.42bis context. + \param buf The data to be compressed. + \param len The length of the data buffer. + \return 0 */ +SPAN_DECLARE(int) v42bis_compress(v42bis_state_t *s, const uint8_t *buf, int len); + +/*! Flush out any data remaining in a compression buffer. + \param s The V.42bis context. + \return 0 */ +SPAN_DECLARE(int) v42bis_compress_flush(v42bis_state_t *s); + +/*! Decompress a block of octets. + \param s The V.42bis context. + \param buf The data to be decompressed. + \param len The length of the data buffer. + \return 0 */ +SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *s, const uint8_t *buf, int len); + +/*! Flush out any data remaining in the decompression buffer. + \param s The V.42bis context. + \return 0 */ +SPAN_DECLARE(int) v42bis_decompress_flush(v42bis_state_t *s); + +/*! Set the compression mode. + \param s The V.42bis context. + \param mode One of the V.42bis compression modes - + V42BIS_COMPRESSION_MODE_DYNAMIC, + V42BIS_COMPRESSION_MODE_ALWAYS, + V42BIS_COMPRESSION_MODE_NEVER */ +SPAN_DECLARE(void) v42bis_compression_control(v42bis_state_t *s, int mode); + +/*! Initialise a V.42bis context. + \param s The V.42bis context. + \param negotiated_p0 The negotiated P0 parameter, from the V.42bis spec. + \param negotiated_p1 The negotiated P1 parameter, from the V.42bis spec. + \param negotiated_p2 The negotiated P2 parameter, from the V.42bis spec. + \param frame_handler Frame callback handler. + \param frame_user_data An opaque pointer passed to the frame callback handler. + \param max_frame_len The maximum length that should be passed to the frame handler. + \param data_handler data callback handler. + \param data_user_data An opaque pointer passed to the data callback handler. + \param max_data_len The maximum length that should be passed to the data handler. + \return The V.42bis context. */ +SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, + int negotiated_p0, + int negotiated_p1, + int negotiated_p2, + v42bis_frame_handler_t frame_handler, + void *frame_user_data, + int max_frame_len, + v42bis_data_handler_t data_handler, + void *data_user_data, + int max_data_len); + +/*! Release a V.42bis context. + \param s The V.42bis context. + \return 0 if OK */ +SPAN_DECLARE(int) v42bis_release(v42bis_state_t *s); + +/*! Free a V.42bis context. + \param s The V.42bis context. + \return 0 if OK */ +SPAN_DECLARE(int) v42bis_free(v42bis_state_t *s); + +#if defined(__cplusplus) +} +#endif + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/openbsc/src/gprs/v42bis.c b/openbsc/src/gprs/v42bis.c new file mode 100644 index 0000000..6d38916 --- /dev/null +++ b/openbsc/src/gprs/v42bis.c @@ -0,0 +1,742 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * v42bis.c + * + * Written by Steve Underwood + * + * Copyright (C) 2005 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: v42bis.c,v 1.37 2009/02/10 13:06:47 steveu Exp $ + */ + +/* THIS IS A WORK IN PROGRESS. IT IS NOT FINISHED. + Currently it performs the core compression and decompression functions OK. + However, a number of the bells and whistles in V.42bis are incomplete. */ + +/*! \file */ + +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "spandsp/telephony.h" +#include "spandsp/logging.h" +#include "spandsp/bit_operations.h" +#include "spandsp/v42bis.h" + +#include "spandsp/private/logging.h" +#include "spandsp/private/v42bis.h" + +/* Fixed parameters from the spec. */ +#define V42BIS_N3 8 /* Character size (bits) */ +#define V42BIS_N4 256 /* Number of characters in the alphabet */ +#define V42BIS_N5 (V42BIS_N4 + V42BIS_N6) /* Index number of first dictionary entry used to store a string */ +#define V42BIS_N6 3 /* Number of control codewords */ + +/* Control code words in compressed mode */ +enum +{ + V42BIS_ETM = 0, /* Enter transparent mode */ + V42BIS_FLUSH = 1, /* Flush data */ + V42BIS_STEPUP = 2 /* Step up codeword size */ +}; + +/* Command codes in transparent mode */ +enum +{ + V42BIS_ECM = 0, /* Enter compression mode */ + V42BIS_EID = 1, /* Escape character in data */ + V42BIS_RESET = 2 /* Force reinitialisation */ +}; + +/*! \brief Find the bit position of the highest set bit in a word + \param bits The word to be searched + \return The bit number of the highest set bit, or -1 if the word is zero. */ +static __inline__ int top_bit(unsigned int bits) +{ +/* Note: This function was taken from spandsp/bit_operations.h */ + int res; + + if (bits == 0) + return -1; + res = 0; + if (bits & 0xFFFF0000) + { + bits &= 0xFFFF0000; + res += 16; + } + if (bits & 0xFF00FF00) + { + bits &= 0xFF00FF00; + res += 8; + } + if (bits & 0xF0F0F0F0) + { + bits &= 0xF0F0F0F0; + res += 4; + } + if (bits & 0xCCCCCCCC) + { + bits &= 0xCCCCCCCC; + res += 2; + } + if (bits & 0xAAAAAAAA) + { + bits &= 0xAAAAAAAA; + res += 1; + } + return res; +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ void push_compressed_raw_octet(v42bis_compress_state_t *ss, int octet) +{ + ss->output_buf[ss->output_octet_count++] = (uint8_t) octet; + if (ss->output_octet_count >= ss->max_len) + { + ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); + ss->output_octet_count = 0; + } +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ void push_compressed_code(v42bis_compress_state_t *ss, int code) +{ + ss->output_bit_buffer |= code << (32 - ss->v42bis_parm_c2 - ss->output_bit_count); + ss->output_bit_count += ss->v42bis_parm_c2; + while (ss->output_bit_count >= 8) + { + push_compressed_raw_octet(ss, ss->output_bit_buffer >> 24); + ss->output_bit_buffer <<= 8; + ss->output_bit_count -= 8; + } +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ void push_compressed_octet(v42bis_compress_state_t *ss, int code) +{ + ss->output_bit_buffer |= code << (32 - 8 - ss->output_bit_count); + ss->output_bit_count += 8; + while (ss->output_bit_count >= 8) + { + push_compressed_raw_octet(ss, ss->output_bit_buffer >> 24); + ss->output_bit_buffer <<= 8; + ss->output_bit_count -= 8; + } +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v42bis_compress(v42bis_state_t *s, const uint8_t *buf, int len) +{ + int ptr; + int i; + uint32_t octet; + uint32_t code; + v42bis_compress_state_t *ss; + + ss = &s->compress; + if ((s->v42bis_parm_p0 & 2) == 0) + { + /* Compression is off - just push the incoming data out */ + for (i = 0; i < len - ss->max_len; i += ss->max_len) + ss->handler(ss->user_data, buf + i, ss->max_len); + if (i < len) + ss->handler(ss->user_data, buf + i, len - i); + return 0; + } + ptr = 0; + if (ss->first && len > 0) + { + octet = buf[ptr++]; + ss->string_code = octet + V42BIS_N6; + if (ss->transparent) + push_compressed_octet(ss, octet); + ss->first = FALSE; + } + while (ptr < len) + { + octet = buf[ptr++]; + if ((ss->dict[ss->string_code].children[octet >> 5] & (1 << (octet & 0x1F)))) + { + /* The leaf exists. Now find it in the table. */ + /* TODO: This is a brute force scan for a match. We need something better. */ + for (code = 0; code < ss->v42bis_parm_c3; code++) + { + if (ss->dict[code].parent_code == ss->string_code && ss->dict[code].node_octet == octet) + break; + } + } + else + { + /* The leaf does not exist. */ + code = s->v42bis_parm_n2; + } + /* 6.3(b) If the string matches a dictionary entry, and the entry is not that entry + created by the last invocation of the string matching procedure, then the + next character shall be read and appended to the string and this step + repeated. */ + if (code < ss->v42bis_parm_c3 && code != ss->latest_code) + { + /* The string was found */ + ss->string_code = code; + ss->string_length++; + } + else + { + /* The string is not in the table. */ + if (!ss->transparent) + { + /* 7.4 Encoding - we now have the longest matchable string, and will need to output the code for it. */ + while (ss->v42bis_parm_c1 >= ss->v42bis_parm_c3 && ss->v42bis_parm_c3 <= s->v42bis_parm_n2) + { + /* We need to increase the codeword size */ + /* 7.4(a) */ + push_compressed_code(ss, V42BIS_STEPUP); + /* 7.4(b) */ + ss->v42bis_parm_c2++; + /* 7.4(c) */ + ss->v42bis_parm_c3 <<= 1; + /* 7.4(d) this might need to be repeated, so we loop */ + } + /* 7.5 Transfer - output the last state of the string */ + push_compressed_code(ss, ss->string_code); + } + /* 7.6 Dictionary updating */ + /* 6.4 Add the string to the dictionary */ + /* 6.4(b) The string is not in the table. */ + if (code != ss->latest_code && ss->string_length < s->v42bis_parm_n7) + { + ss->latest_code = ss->v42bis_parm_c1; + /* 6.4(a) The length of the string is in range for adding to the dictionary */ + /* If the last code was a leaf, it no longer is */ + ss->dict[ss->string_code].leaves++; + ss->dict[ss->string_code].children[octet >> 5] |= (1 << (octet & 0x1F)); + /* The new one is definitely a leaf */ + ss->dict[ss->v42bis_parm_c1].parent_code = (uint16_t) ss->string_code; + ss->dict[ss->v42bis_parm_c1].leaves = 0; + ss->dict[ss->v42bis_parm_c1].node_octet = (uint8_t) octet; + /* 7.7 Node recovery */ + /* 6.5 Recovering a dictionary entry to use next */ + for (;;) + { + /* 6.5(a) and (b) */ + if ((int) (++ss->v42bis_parm_c1) >= s->v42bis_parm_n2) + ss->v42bis_parm_c1 = V42BIS_N5; + /* 6.5(c) We need to reuse a leaf node */ + if (ss->dict[ss->v42bis_parm_c1].leaves) + continue; + if (ss->dict[ss->v42bis_parm_c1].parent_code == 0xFFFF) + break; + /* 6.5(d) Detach the leaf node from its parent, and re-use it */ + /* Possibly make the parent a leaf node again */ + ss->dict[ss->dict[ss->v42bis_parm_c1].parent_code].leaves--; + ss->dict[ss->dict[ss->v42bis_parm_c1].parent_code].children[ss->dict[ss->v42bis_parm_c1].node_octet >> 5] &= ~(1 << (ss->dict[ss->v42bis_parm_c1].node_octet & 0x1F)); + ss->dict[ss->v42bis_parm_c1].parent_code = 0xFFFF; + break; + } + } + else + { + ss->latest_code = 0xFFFFFFFF; + } + /* 7.8 Data compressibility test */ + /* Filter on the balance of what went into the compressor, and what came out */ + ss->compressibility_filter += ((((8*ss->string_length - ss->v42bis_parm_c2) << 20) - ss->compressibility_filter) >> 10); + if (ss->compression_mode == V42BIS_COMPRESSION_MODE_DYNAMIC) + { + /* Work out if it is appropriate to change between transparent and + compressed mode. */ + if (ss->transparent) + { + if (ss->compressibility_filter > 0) + { + if (++ss->compressibility_persistence > 1000) + { + /* Schedule a switch to compressed mode */ + ss->change_transparency = -1; + ss->compressibility_persistence = 0; + } + } + else + { + ss->compressibility_persistence = 0; + } + } + else + { + if (ss->compressibility_filter < 0) + { + if (++ss->compressibility_persistence > 1000) + { + /* Schedule a switch to transparent mode */ + ss->change_transparency = 1; + ss->compressibility_persistence = 0; + } + } + else + { + ss->compressibility_persistence = 0; + } + } + } + if (ss->change_transparency) + { + if (ss->change_transparency < 0) + { + if (ss->transparent) + { + printf("Going compressed\n"); + /* 7.8.1 Transition to compressed mode */ + /* Switch out of transparent now, between codes. We need to send the octet which did not + match, just before switching. */ + if (octet == ss->escape_code) + { + push_compressed_octet(ss, ss->escape_code++); + push_compressed_octet(ss, V42BIS_EID); + } + else + { + push_compressed_octet(ss, octet); + } + push_compressed_octet(ss, ss->escape_code++); + push_compressed_octet(ss, V42BIS_ECM); + ss->transparent = FALSE; + } + } + else + { + if (!ss->transparent) + { + printf("Going transparent\n"); + /* 7.8.2 Transition to transparent mode */ + /* Switch into transparent now, between codes, and the unmatched octet should + go out in transparent mode, just below */ + push_compressed_code(ss, V42BIS_ETM); + ss->transparent = TRUE; + } + } + ss->change_transparency = 0; + } + /* 7.8.3 Reset function - TODO */ + ss->string_code = octet + V42BIS_N6; + ss->string_length = 1; + } + if (ss->transparent) + { + if (octet == ss->escape_code) + { + push_compressed_octet(ss, ss->escape_code++); + push_compressed_octet(ss, V42BIS_EID); + } + else + { + push_compressed_octet(ss, octet); + } + } + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v42bis_compress_flush(v42bis_state_t *s) +{ + v42bis_compress_state_t *ss; + + ss = &s->compress; + if (!ss->transparent) + { + /* Output the last state of the string */ + push_compressed_code(ss, ss->string_code); + /* TODO: We use a positive FLUSH at all times. It is really needed, if the + previous step resulted in no leftover bits. */ + push_compressed_code(ss, V42BIS_FLUSH); + } + while (ss->output_bit_count > 0) + { + push_compressed_raw_octet(ss, ss->output_bit_buffer >> 24); + ss->output_bit_buffer <<= 8; + ss->output_bit_count -= 8; + } + /* Now push out anything remaining. */ + if (ss->output_octet_count > 0) + { + ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); + ss->output_octet_count = 0; + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +#if 0 +SPAN_DECLARE(int) v42bis_compress_dump(v42bis_state_t *s) +{ + int i; + + for (i = 0; i < V42BIS_MAX_CODEWORDS; i++) + { + if (s->compress.dict[i].parent_code != 0xFFFF) + { + printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); + } + } + return 0; +} +/*- End of function --------------------------------------------------------*/ +#endif + +SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *s, const uint8_t *buf, int len) +{ + int ptr; + int i; + int this_length; + uint8_t *string; + uint32_t code; + uint32_t new_code; + int code_len; + v42bis_decompress_state_t *ss; + uint8_t decode_buf[V42BIS_MAX_STRING_SIZE]; + + ss = &s->decompress; + if ((s->v42bis_parm_p0 & 1) == 0) + { + /* Compression is off - just push the incoming data out */ + for (i = 0; i < len - ss->max_len; i += ss->max_len) + ss->handler(ss->user_data, buf + i, ss->max_len); + if (i < len) + ss->handler(ss->user_data, buf + i, len - i); + return 0; + } + ptr = 0; + code_len = (ss->transparent) ? 8 : ss->v42bis_parm_c2; + for (;;) + { + /* Fill up the bit buffer. */ + while (ss->input_bit_count < 32 - 8 && ptr < len) + { + ss->input_bit_count += 8; + ss->input_bit_buffer |= (uint32_t) buf[ptr++] << (32 - ss->input_bit_count); + } + if (ss->input_bit_count < code_len) + break; + new_code = ss->input_bit_buffer >> (32 - code_len); + ss->input_bit_count -= code_len; + ss->input_bit_buffer <<= code_len; + if (ss->transparent) + { + code = new_code; + if (ss->escaped) + { + ss->escaped = FALSE; + if (code == V42BIS_ECM) + { + printf("Hit V42BIS_ECM\n"); + ss->transparent = FALSE; + code_len = ss->v42bis_parm_c2; + } + else if (code == V42BIS_EID) + { + printf("Hit V42BIS_EID\n"); + ss->output_buf[ss->output_octet_count++] = ss->escape_code - 1; + if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) + { + ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); + ss->output_octet_count = 0; + } + } + else if (code == V42BIS_RESET) + { + printf("Hit V42BIS_RESET\n"); + } + else + { + printf("Hit V42BIS_???? - %" PRIu32 "\n", code); + } + } + else if (code == ss->escape_code) + { + ss->escape_code++; + ss->escaped = TRUE; + } + else + { + ss->output_buf[ss->output_octet_count++] = (uint8_t) code; + if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) + { + ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); + ss->output_octet_count = 0; + } + } + } + else + { + if (new_code < V42BIS_N6) + { + /* We have a control code. */ + switch (new_code) + { + case V42BIS_ETM: + printf("Hit V42BIS_ETM\n"); + ss->transparent = TRUE; + code_len = 8; + break; + case V42BIS_FLUSH: + printf("Hit V42BIS_FLUSH\n"); + v42bis_decompress_flush(s); + break; + case V42BIS_STEPUP: + /* We need to increase the codeword size */ + printf("Hit V42BIS_STEPUP\n"); + if (ss->v42bis_parm_c3 >= s->v42bis_parm_n2) + { + /* Invalid condition */ + return -1; + } + code_len = ++ss->v42bis_parm_c2; + ss->v42bis_parm_c3 <<= 1; + break; + } + continue; + } + if (ss->first) + { + ss->first = FALSE; + ss->octet = new_code - V42BIS_N6; + ss->output_buf[0] = (uint8_t) ss->octet; + ss->output_octet_count = 1; + if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) + { + ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); + ss->output_octet_count = 0; + } + ss->old_code = new_code; + continue; + } + /* Start at the end of the buffer, and decode backwards */ + string = &decode_buf[V42BIS_MAX_STRING_SIZE - 1]; + /* Check the received code is valid. It can't be too big, as we pulled only the expected number + of bits from the input stream. It could, however, be unknown. */ + if (ss->dict[new_code].parent_code == 0xFFFF) + return -1; + /* Otherwise we do a straight decode of the new code. */ + code = new_code; + /* Trace back through the octets which form the string, and output them. */ + while (code >= V42BIS_N5) + { +if (code > 4095) {printf("Code is 0x%" PRIu32 "\n", code); exit(2);} + *string-- = ss->dict[code].node_octet; + code = ss->dict[code].parent_code; + } + *string = (uint8_t) (code - V42BIS_N6); + ss->octet = code - V42BIS_N6; + /* Output the decoded string. */ + this_length = V42BIS_MAX_STRING_SIZE - (int) (string - decode_buf); + memcpy(ss->output_buf + ss->output_octet_count, string, this_length); + ss->output_octet_count += this_length; + if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) + { + ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); + ss->output_octet_count = 0; + } + /* 6.4 Add the string to the dictionary */ + if (ss->last_length < s->v42bis_parm_n7) + { + /* 6.4(a) The string does not exceed N7 in length */ + if (ss->last_old_code != ss->old_code + || + ss->last_extra_octet != *string) + { + /* 6.4(b) The string is not in the table. */ + ss->dict[ss->old_code].leaves++; + /* The new one is definitely a leaf */ + ss->dict[ss->v42bis_parm_c1].parent_code = (uint16_t) ss->old_code; + ss->dict[ss->v42bis_parm_c1].leaves = 0; + ss->dict[ss->v42bis_parm_c1].node_octet = (uint8_t) ss->octet; + /* 6.5 Recovering a dictionary entry to use next */ + for (;;) + { + /* 6.5(a) and (b) */ + if (++ss->v42bis_parm_c1 >= s->v42bis_parm_n2) + ss->v42bis_parm_c1 = V42BIS_N5; + /* 6.5(c) We need to reuse a leaf node */ + if (ss->dict[ss->v42bis_parm_c1].leaves) + continue; + /* 6.5(d) This is a leaf node, so re-use it */ + /* Possibly make the parent a leaf node again */ + if (ss->dict[ss->v42bis_parm_c1].parent_code != 0xFFFF) + ss->dict[ss->dict[ss->v42bis_parm_c1].parent_code].leaves--; + ss->dict[ss->v42bis_parm_c1].parent_code = 0xFFFF; + break; + } + } + } + /* Record the addition to the dictionary, so we can check for repeat attempts + at the next code - see II.4.3 */ + ss->last_old_code = ss->old_code; + ss->last_extra_octet = *string; + + ss->old_code = new_code; + ss->last_length = this_length; + } + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v42bis_decompress_flush(v42bis_state_t *s) +{ + v42bis_decompress_state_t *ss; + + ss = &s->decompress; + /* Push out anything remaining. */ + if (ss->output_octet_count > 0) + { + ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); + ss->output_octet_count = 0; + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +#if 0 +SPAN_DECLARE(int) v42bis_decompress_dump(v42bis_state_t *s) +{ + int i; + + for (i = 0; i < V42BIS_MAX_CODEWORDS; i++) + { + if (s->decompress.dict[i].parent_code != 0xFFFF) + { + printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); + } + } + return 0; +} +/*- End of function --------------------------------------------------------*/ +#endif + +SPAN_DECLARE(void) v42bis_compression_control(v42bis_state_t *s, int mode) +{ + s->compress.compression_mode = mode; + switch (mode) + { + case V42BIS_COMPRESSION_MODE_ALWAYS: + s->compress.change_transparency = -1; + break; + case V42BIS_COMPRESSION_MODE_NEVER: + s->compress.change_transparency = 1; + break; + } +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, + int negotiated_p0, + int negotiated_p1, + int negotiated_p2, + v42bis_frame_handler_t frame_handler, + void *frame_user_data, + int max_frame_len, + v42bis_data_handler_t data_handler, + void *data_user_data, + int max_data_len) +{ + int i; + + if (negotiated_p1 < 512 || negotiated_p1 > 65535) + return NULL; + if (negotiated_p2 < 6 || negotiated_p2 > V42BIS_MAX_STRING_SIZE) + return NULL; + if (s == NULL) + { + if ((s = (v42bis_state_t *) malloc(sizeof(*s))) == NULL) + return NULL; + } + memset(s, 0, sizeof(*s)); + + s->compress.handler = frame_handler; + s->compress.user_data = frame_user_data; + s->compress.max_len = (max_frame_len < 1024) ? max_frame_len : 1024; + + s->decompress.handler = data_handler; + s->decompress.user_data = data_user_data; + s->decompress.max_len = (max_data_len < 1024) ? max_data_len : 1024; + + s->v42bis_parm_p0 = negotiated_p0; /* default is both ways off */ + + s->v42bis_parm_n1 = top_bit(negotiated_p1 - 1) + 1; + s->v42bis_parm_n2 = negotiated_p1; + s->v42bis_parm_n7 = negotiated_p2; + + /* 6.5 */ + s->compress.v42bis_parm_c1 = + s->decompress.v42bis_parm_c1 = V42BIS_N5; + + s->compress.v42bis_parm_c2 = + s->decompress.v42bis_parm_c2 = V42BIS_N3 + 1; + + s->compress.v42bis_parm_c3 = + s->decompress.v42bis_parm_c3 = 2*V42BIS_N4; + + s->compress.first = + s->decompress.first = TRUE; + for (i = 0; i < V42BIS_MAX_CODEWORDS; i++) + { + s->compress.dict[i].parent_code = + s->decompress.dict[i].parent_code = 0xFFFF; + s->compress.dict[i].leaves = + s->decompress.dict[i].leaves = 0; + } + /* Point the root nodes for decompression to themselves. It doesn't matter much what + they are set to, as long as they are considered "known" codes. */ + for (i = 0; i < V42BIS_N5; i++) + s->decompress.dict[i].parent_code = (uint16_t) i; + s->compress.string_code = 0xFFFFFFFF; + s->compress.latest_code = 0xFFFFFFFF; + + s->decompress.last_old_code = 0xFFFFFFFF; + s->decompress.last_extra_octet = -1; + + s->compress.compression_mode = V42BIS_COMPRESSION_MODE_DYNAMIC; + + return s; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v42bis_release(v42bis_state_t *s) +{ + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v42bis_free(v42bis_state_t *s) +{ + free(s); + return 0; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ -- To view, visit https://gerrit.osmocom.org/643 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Iabedece9f97ca944a1e3f747bb073e532c4e9dca Gerrit-PatchSet: 8 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte From gerrit-no-reply at lists.osmocom.org Fri Aug 5 09:35:03 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Fri, 5 Aug 2016 09:35:03 +0000 Subject: [PATCH] openbsc[master]: V42BIS integration In-Reply-To: References: Message-ID: Hello Harald Welte, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/644 to look at the new patch set (#10). V42BIS integration The previously committed SPANDSP v42bis implementation has been edited to function outside the SPANDSP library. Debug printf statements were changed into DEBUGP statements. Als removed the assembely code in top_bit(). Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d --- M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/debug.h M openbsc/include/openbsc/v42bis.h R openbsc/include/openbsc/v42bis_private.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/v42bis.c 6 files changed, 11 insertions(+), 11 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/44/644/10 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index e159db5..e404b17 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,8 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h gprs_sndcp_xid.h \ - gprs_sndcp_comp_entity.h gprs_sndcp_hdrcomp.h + gprs_sndcp_comp_entity.h gprs_sndcp_hdrcomp.h v42bis.h \ + v42bis_private.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 90ddca5..ca3d4ad 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -37,6 +37,7 @@ DGTPHUB, DRANAP, DSUA, + DV42BIS, Debug_LastEntry, }; diff --git a/openbsc/include/openbsc/v42bis.h b/openbsc/include/openbsc/v42bis.h index f13e5c5..e7592e8 100644 --- a/openbsc/include/openbsc/v42bis.h +++ b/openbsc/include/openbsc/v42bis.h @@ -36,6 +36,8 @@ #if !defined(_SPANDSP_V42BIS_H_) #define _SPANDSP_V42BIS_H_ +#define SPAN_DECLARE(x) x + #define V42BIS_MAX_BITS 12 #define V42BIS_MAX_CODEWORDS 4096 /* 2^V42BIS_MAX_BITS */ #define V42BIS_TABLE_SIZE 5021 /* This should be a prime >(2^V42BIS_MAX_BITS) */ diff --git a/openbsc/include/openbsc/private_v42bis.h b/openbsc/include/openbsc/v42bis_private.h similarity index 100% rename from openbsc/include/openbsc/private_v42bis.h rename to openbsc/include/openbsc/v42bis_private.h diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 3d6c82a..2c03a45 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -22,7 +22,7 @@ osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \ slhc.c gprs_sndcp_xid.c gprs_sndcp_comp_entity.c \ - gprs_sndcp_hdrcomp.c \ + gprs_sndcp_hdrcomp.c v42bis.c \ sgsn_main.c sgsn_vty.c sgsn_libgtp.c \ gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c \ gprs_llc_xid.c crc24.c \ diff --git a/openbsc/src/gprs/v42bis.c b/openbsc/src/gprs/v42bis.c index 6d38916..a306107 100644 --- a/openbsc/src/gprs/v42bis.c +++ b/openbsc/src/gprs/v42bis.c @@ -31,9 +31,8 @@ /*! \file */ -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif +#define FALSE 0 +#define TRUE 1 #include #include @@ -44,13 +43,9 @@ #include #include -#include "spandsp/telephony.h" -#include "spandsp/logging.h" -#include "spandsp/bit_operations.h" -#include "spandsp/v42bis.h" +#include +#include -#include "spandsp/private/logging.h" -#include "spandsp/private/v42bis.h" /* Fixed parameters from the spec. */ #define V42BIS_N3 8 /* Character size (bits) */ @@ -79,6 +74,7 @@ \return The bit number of the highest set bit, or -1 if the word is zero. */ static __inline__ int top_bit(unsigned int bits) { + /* Note: This function was taken from spandsp/bit_operations.h */ int res; -- To view, visit https://gerrit.osmocom.org/644 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d Gerrit-PatchSet: 10 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte From gerrit-no-reply at lists.osmocom.org Fri Aug 5 09:35:03 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Fri, 5 Aug 2016 09:35:03 +0000 Subject: [PATCH] openbsc[master]: XID related modifications in LLC In-Reply-To: References: Message-ID: Hello Harald Welte, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/652 to look at the new patch set (#5). XID related modifications in LLC With this commit the already existing XID mechanism has been modified to suit the needs for the upcomming SNDCP-XID patches. The SNDCP-XID related calls are currently disabled since the necessary patches for gprs_sndcp.c are not yet pushed. This commit should not break anything since it does not alter the current behaviour (incoming XID is still just echoed, on GMM-Reset a basic XID message is still echoed) Change-Id: I65b9d625e72d3d61c99abdc7041773701d694d52 --- M openbsc/include/openbsc/gprs_llc.h M openbsc/src/gprs/gprs_llc.c M openbsc/src/gprs/v42bis.c M openbsc/tests/sgsn/Makefile.am 4 files changed, 359 insertions(+), 74 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/52/652/5 diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h index 39d17f4..8b93784 100644 --- a/openbsc/include/openbsc/gprs_llc.h +++ b/openbsc/include/openbsc/gprs_llc.h @@ -4,6 +4,7 @@ #include #include #include +#include /* Section 4.7 LLC Layer Structure */ enum gprs_llc_sapi { @@ -148,10 +149,8 @@ /* Lists holding the compression entities */ struct comp_ent { - /* - * In this two list_heads we will store the data and protocol - * compression entities, together with their compression states - */ + /* In this two list_heads we will store the data and protocol + * compression entities, together with their compression states */ struct llist_head proto; struct llist_head data; }; @@ -235,6 +234,10 @@ int gprs_llgmm_reset_oldmsg(struct msgb* oldmsg, uint8_t sapi, struct gprs_llc_llme *llme); +/* Set of LL-XID negotiation (See also: TS 101 351, Section 7.2.2.4) */ +int gprs_ll_xid_req(struct gprs_llc_lle *lle, + struct gprs_llc_xid_field *l3_xid_field); + /* 04.64 Chapter 7.2.1.1 LLGMM-ASSIGN */ int gprs_llgmm_assign(struct gprs_llc_llme *llme, uint32_t old_tlli, uint32_t new_tlli); diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c index 7724ebb..9e85f63 100644 --- a/openbsc/src/gprs/gprs_llc.c +++ b/openbsc/src/gprs/gprs_llc.c @@ -38,8 +38,312 @@ #include #include #include +#include +#include +#include + + +/* FIXME: Remove this switch as soon as the XID integration in + * gprs_sndcp.c h is done */ +#define WITH_SNDCP_XID 1 static struct gprs_llc_llme *llme_alloc(uint32_t tlli); +static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg, + int command); +static int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi, + int command, enum gprs_llc_u_cmd u_cmd, int pf_bit); + +/* BEGIN XID RELATED */ + +/* Generate XID message */ +static int gprs_llc_generate_xid(uint8_t *bytes, int bytes_len, + struct gprs_llc_xid_field *l3_xid_field, + struct gprs_llc_llme *llme) +{ + /* Note: Called by gprs_ll_xid_req() */ + + LLIST_HEAD(xid_fields); + + struct gprs_llc_xid_field xid_version; + struct gprs_llc_xid_field xid_n201u; + struct gprs_llc_xid_field xid_n201i; + + xid_version.type = GPRS_LLC_XID_T_VERSION; + xid_version.data = (uint8_t *) "\x00"; + xid_version.data_len = 1; + + xid_n201u.type = GPRS_LLC_XID_T_N201_U; + xid_n201u.data = (uint8_t *) "\x05\xf0"; + xid_n201u.data_len = 2; + + xid_n201i.type = GPRS_LLC_XID_T_N201_I; + xid_n201i.data = (uint8_t *) "\x05\xf0"; + xid_n201i.data_len = 2; + + /* Add layer 3 XID field (if present) */ + if (l3_xid_field) { + /* Enforce layer 3 XID type (just to be sure) */ + l3_xid_field->type = GPRS_LLC_XID_T_L3_PAR; + + /* Add Layer 3 XID field to the list */ + llist_add(&l3_xid_field->list, &xid_fields); + } + + /* Add locally managed XID Fields */ + llist_add(&xid_n201i.list, &xid_fields); + llist_add(&xid_n201u.list, &xid_fields); + llist_add(&xid_version.list, &xid_fields); + + gprs_llc_copy_xid(&llme->xid, &xid_fields); + + return gprs_llc_compile_xid(&xid_fields, bytes, bytes_len); +} + +/* Generate XID message that will cause the GMM to reset */ +static int gprs_llc_generate_xid_for_gmm_reset(uint8_t *bytes, + int bytes_len, uint32_t iov_ui, + struct gprs_llc_llme *llme) +{ + /* Called by gprs_llgmm_reset() and + * gprs_llgmm_reset_oldmsg() */ + + LLIST_HEAD(xid_fields); + + struct gprs_llc_xid_field xid_reset; + struct gprs_llc_xid_field xid_iovui; + + /* First XID component must be RESET */ + xid_reset.type = GPRS_LLC_XID_T_RESET; + xid_reset.data = NULL; + xid_reset.data_len = 0; + + /* Add new IOV-UI */ + xid_iovui.type = GPRS_LLC_XID_T_IOV_UI; + xid_iovui.data = (uint8_t *) & iov_ui; + xid_iovui.data_len = 4; + + /* Add locally managed XID Fields */ + llist_add(&xid_iovui.list, &xid_fields); + llist_add(&xid_reset.list, &xid_fields); + + gprs_llc_copy_xid(&llme->xid, &xid_fields); + + return gprs_llc_compile_xid(&xid_fields, bytes, bytes_len); +} + +/* Process an incoming XID confirmation */ +static int gprs_llc_process_xid_conf(uint8_t *bytes, int bytes_len, + struct gprs_llc_lle *lle) +{ + /* Note: This function handles the response of a network originated + * XID-Request. There XID messages reflected by the phone are analyzed + * and processed here. The caller is called by rx_llc_xid(). */ + + int rc; + LLIST_HEAD(xid_fields); + struct gprs_llc_xid_field *xid_field; + struct gprs_llc_xid_field *xid_field_request; + struct gprs_llc_xid_field *xid_field_request_l3 = NULL; + + /* Pick layer3 XID from the XID request we have sent last */ + llist_for_each_entry(xid_field_request, &lle->llme->xid, list) { + if (xid_field_request->type == GPRS_LLC_XID_T_L3_PAR) + xid_field_request_l3 = xid_field_request; + } + + /* Parse and analyze XID-Response */ + rc = gprs_llc_parse_xid(&xid_fields, bytes, bytes_len); + if (rc == 0) { + gprs_llc_dump_xid_fields(&xid_fields, LOGL_DEBUG); + + llist_for_each_entry(xid_field, &xid_fields, list) { + + /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { +#if WITH_SNDCP_XID == 1 + sndcp_sn_xid_conf(xid_field, + xid_field_request_l3, + lle); +#endif + } + + /* Process LLC-XID fields: */ + else { + + /* FIXME: Do something more useful with the + * echoed XID-Information. Currently we + * just ignore the response completely and + * by doing so we blindly accept any changes + * the MS might have done to the our XID + * inquiry. There is a remainig risk of + * malfunction! */ + LOGP(DLLC, LOGL_NOTICE, + "Ignoring XID-Field: XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + xid_field->data); + + } + } + } + + /* Flush pending XID fields */ + gprs_llc_free_xid(&lle->llme->xid); + + return 0; +} + + +/* Process an incoming XID indication and generate an appropiate response */ +static int gprs_llc_process_xid_ind(uint8_t *bytes_request, + int bytes_request_len, + uint8_t *bytes_response, + int bytes_response_maxlen, + struct gprs_llc_lle *lle) +{ + /* Note: This function computes the response that is sent back to the + * phone when a phone originated XID is received. The function is + * called by rx_llc_xid() */ + + int rc; + LLIST_HEAD(xid_fields); + LLIST_HEAD(xid_fields_response); + + struct gprs_llc_xid_field *xid_field; + struct gprs_llc_xid_field *xid_field_response; + + /* Flush eventually pending XID fields */ + gprs_llc_free_xid(&lle->llme->xid); + + /* Parse and analyze XID-Request */ + rc = gprs_llc_parse_xid(&xid_fields, bytes_request, + bytes_request_len); + if (rc == 0) { + gprs_llc_dump_xid_fields(&xid_fields, LOGL_DEBUG); + + llist_for_each_entry(xid_field, &xid_fields, list) { + /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { +#if WITH_SNDCP_XID == 1 + xid_field_response = + talloc_zero(NULL, + struct gprs_llc_xid_field); + rc = sndcp_sn_xid_ind(xid_field, + xid_field_response, + lle); + if (rc == 0) + llist_add(&xid_field_response-> + list, + &xid_fields_response); + else + talloc_free(xid_field_response); +#endif + } + + /* Process LLC-XID fields: */ + else { + /* FIXME: Check the incoming XID parameters for + * for validity. Currently we just blindly + * accept all XID fields by just echoing them. + * There is a remaining risk of malfunction + * when a phone submits values which defer from + * the default! */ + LOGP(DLLC, LOGL_NOTICE, + "Echoing XID-Field: XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + osmo_hexdump_nospc(xid_field->data, + xid_field-> + data_len)); + xid_field_response = + gprs_llc_duplicate_xid_field + (xid_field); + llist_add(&xid_field_response->list, + &xid_fields_response); + } + } + + rc = gprs_llc_compile_xid(&xid_fields_response, + bytes_response, + bytes_response_maxlen); + gprs_llc_free_xid(&xid_fields_response); + } + gprs_llc_free_xid(&xid_fields); + + return rc; +} + +/* Dispatch XID indications and responses comming from the Phone */ +static void rx_llc_xid(struct gprs_llc_lle *lle, + struct gprs_llc_hdr_parsed *gph) +{ + uint8_t response[1024]; + int response_len; + + /* FIXME: 8.5.3.3: check if XID is invalid */ + if (gph->is_cmd) { + LOGP(DLLC, LOGL_NOTICE, + "Received XID indication from phone.\n"); + + struct msgb *resp; + uint8_t *xid; + resp = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + + response_len = + gprs_llc_process_xid_ind(gph->data, gph->data_len, + response, sizeof(response), + lle); + xid = msgb_put(resp, response_len); + memcpy(xid, response, response_len); + + gprs_llc_tx_xid(lle, resp, 0); + } else { + LOGP(DLLC, LOGL_NOTICE, + "Received XID confirmation from phone.\n"); + gprs_llc_process_xid_conf(gph->data, gph->data_len, lle); + /* FIXME: if we had sent a XID reset, send + * LLGMM-RESET.conf to GMM */ + } +} + + +/* Set of LL-XID negotiation (See also: TS 101 351, Section 7.2.2.4) */ +int gprs_ll_xid_req(struct gprs_llc_lle *lle, + struct gprs_llc_xid_field *l3_xid_field) +{ + /* Note: This functions is calle from gprs_sndcp.c */ + + uint8_t xid_bytes[1024];; + int xid_bytes_len; + uint8_t *xid; + struct msgb *msg; + + /* Generate XID */ + xid_bytes_len = + gprs_llc_generate_xid(xid_bytes, sizeof(xid_bytes), + l3_xid_field, lle->llme); + + + /* Only perform XID sending if the XID message contains something */ + if (xid_bytes_len > 0) { + /* Transmit XID bytes */ + msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); + LOGP(DLLC, LOGL_NOTICE, + "Sending XID request to phone...\n"); + gprs_llc_tx_xid(lle, msg, 1); + } else { + LOGP(DLLC, LOGL_ERROR, + "XID-Message generation failed, XID not sent!\n"); + return -EINVAL; + } + + return 0; +} + +/* END XID RELATED */ + + + /* Entry function from upper level (LLC), asking us to transmit a BSSGP PDU * to a remote MS (identified by TLLI) at a BTS identified by its BVCI and NSEI */ @@ -51,7 +355,7 @@ memset(&dup, 0, sizeof(dup)); /* before we have received some identity from the MS, we might * not yet have a MMC context (e.g. XID negotiation of primarly - * LLC connection fro GMM sapi). */ + * LLC connection from GMM sapi). */ if (mmctx) { dup.imsi = mmctx->imsi; dup.drx_parms = mmctx->drx_parms; @@ -246,11 +550,18 @@ llist_add(&llme->list, &gprs_llc_llmes); + INIT_LLIST_HEAD(&llme->comp.proto); + INIT_LLIST_HEAD(&llme->comp.data); + INIT_LLIST_HEAD(&llme->xid); + return llme; } static void llme_free(struct gprs_llc_llme *llme) { + gprs_sndcp_comp_entities_free(&llme->comp.proto); + gprs_sndcp_comp_entities_free(&llme->comp.data); + gprs_llc_free_xid(&llme->xid); llist_del(&llme->list); talloc_free(llme); } @@ -464,54 +775,6 @@ /* Send BSSGP-DL-UNITDATA.req */ return _bssgp_tx_dl_ud(msg, mmctx); -} - -/* According to 6.4.1.6 / Figure 11 */ -static int msgb_put_xid_par(struct msgb *msg, uint8_t type, uint8_t length, uint8_t *data) -{ - uint8_t header_len = 1; - uint8_t *cur; - - /* type is a 5-bit field... */ - if (type > 0x1f) - return -EINVAL; - - if (length > 3) - header_len = 2; - - cur = msgb_put(msg, length + header_len); - - /* build the header without or with XL bit */ - if (length <= 3) { - *cur++ = (type << 2) | (length & 3); - } else { - *cur++ = 0x80 | (type << 2) | (length >> 6); - *cur++ = (length << 2); - } - - /* copy over the payload of the parameter*/ - memcpy(cur, data, length); - - return length + header_len; -} - -static void rx_llc_xid(struct gprs_llc_lle *lle, - struct gprs_llc_hdr_parsed *gph) -{ - /* FIXME: 8.5.3.3: check if XID is invalid */ - if (gph->is_cmd) { - /* FIXME: implement XID negotiation using SNDCP */ - struct msgb *resp; - uint8_t *xid; - resp = msgb_alloc_headroom(4096, 1024, "LLC_XID"); - xid = msgb_put(resp, gph->data_len); - memcpy(xid, gph->data, gph->data_len); - gprs_llc_tx_xid(lle, resp, 0); - } else { - /* FIXME: if we had sent a XID reset, send - * LLGMM-RESET.conf to GMM */ - /* FIXME: implement XID negotiation using SNDCP */ - } } static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph, @@ -784,17 +1047,24 @@ { struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); struct gprs_llc_lle *lle = &llme->lle[1]; + uint8_t xid_bytes[1024]; + int xid_bytes_len; + uint8_t *xid; + LOGP(DLLC, LOGL_NOTICE, "LLGM Reset\n"); if (RAND_bytes((uint8_t *) &llme->iov_ui, 4) != 1) { LOGP(DLLC, LOGL_NOTICE, "RAND_bytes failed for LLC XID reset, " "falling back to rand()\n"); llme->iov_ui = rand(); } - /* First XID component must be RESET */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL); - /* randomly select new IOV-UI */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &llme->iov_ui); + /* Generate XID message */ + xid_bytes_len = gprs_llc_generate_xid_for_gmm_reset(xid_bytes, + sizeof(xid_bytes),llme->iov_ui,llme); + if(xid_bytes_len < 0) + return -EINVAL; + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); /* Reset some of the LLC parameters. See GSM 04.64, 8.5.3.1 */ lle->vu_recv = 0; @@ -810,17 +1080,24 @@ struct gprs_llc_llme *llme) { struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + uint8_t xid_bytes[1024]; + int xid_bytes_len; + uint8_t *xid; + LOGP(DLLC, LOGL_NOTICE, "LLGM Reset\n"); if (RAND_bytes((uint8_t *) &llme->iov_ui, 4) != 1) { LOGP(DLLC, LOGL_NOTICE, "RAND_bytes failed for LLC XID reset, " "falling back to rand()\n"); llme->iov_ui = rand(); } - /* First XID component must be RESET */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL); - /* randomly select new IOV-UI */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &llme->iov_ui); + /* Generate XID message */ + xid_bytes_len = gprs_llc_generate_xid_for_gmm_reset(xid_bytes, + sizeof(xid_bytes),llme->iov_ui,llme); + if(xid_bytes_len < 0) + return -EINVAL; + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); /* FIXME: Start T200, wait for XID response */ diff --git a/openbsc/src/gprs/v42bis.c b/openbsc/src/gprs/v42bis.c index a306107..65d8814 100644 --- a/openbsc/src/gprs/v42bis.c +++ b/openbsc/src/gprs/v42bis.c @@ -306,7 +306,7 @@ { if (ss->transparent) { - printf("Going compressed\n"); + DEBUGP(DV42BIS,"Going compressed\n"); /* 7.8.1 Transition to compressed mode */ /* Switch out of transparent now, between codes. We need to send the octet which did not match, just before switching. */ @@ -328,7 +328,7 @@ { if (!ss->transparent) { - printf("Going transparent\n"); + DEBUGP(DV42BIS,"Going transparent\n"); /* 7.8.2 Transition to transparent mode */ /* Switch into transparent now, between codes, and the unmatched octet should go out in transparent mode, just below */ @@ -397,7 +397,7 @@ { if (s->compress.dict[i].parent_code != 0xFFFF) { - printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); + DEBUGP(DV42BIS,"Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); } } return 0; @@ -450,13 +450,13 @@ ss->escaped = FALSE; if (code == V42BIS_ECM) { - printf("Hit V42BIS_ECM\n"); + DEBUGP(DV42BIS,"Hit V42BIS_ECM\n"); ss->transparent = FALSE; code_len = ss->v42bis_parm_c2; } else if (code == V42BIS_EID) { - printf("Hit V42BIS_EID\n"); + DEBUGP(DV42BIS,"Hit V42BIS_EID\n"); ss->output_buf[ss->output_octet_count++] = ss->escape_code - 1; if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) { @@ -466,11 +466,11 @@ } else if (code == V42BIS_RESET) { - printf("Hit V42BIS_RESET\n"); + DEBUGP(DV42BIS,"Hit V42BIS_RESET\n"); } else { - printf("Hit V42BIS_???? - %" PRIu32 "\n", code); + DEBUGP(DV42BIS,"Hit V42BIS_???? - %" PRIu32 "\n", code); } } else if (code == ss->escape_code) @@ -496,17 +496,17 @@ switch (new_code) { case V42BIS_ETM: - printf("Hit V42BIS_ETM\n"); + DEBUGP(DV42BIS,"Hit V42BIS_ETM\n"); ss->transparent = TRUE; code_len = 8; break; case V42BIS_FLUSH: - printf("Hit V42BIS_FLUSH\n"); + DEBUGP(DV42BIS,"Hit V42BIS_FLUSH\n"); v42bis_decompress_flush(s); break; case V42BIS_STEPUP: /* We need to increase the codeword size */ - printf("Hit V42BIS_STEPUP\n"); + DEBUGP(DV42BIS,"Hit V42BIS_STEPUP\n"); if (ss->v42bis_parm_c3 >= s->v42bis_parm_n2) { /* Invalid condition */ @@ -543,7 +543,7 @@ /* Trace back through the octets which form the string, and output them. */ while (code >= V42BIS_N5) { -if (code > 4095) {printf("Code is 0x%" PRIu32 "\n", code); exit(2);} +if (code > 4095) {DEBUGP(DV42BIS,"Code is 0x%" PRIu32 "\n", code); exit(2);} *string-- = ss->dict[code].node_octet; code = ss->dict[code].parent_code; } @@ -627,7 +627,7 @@ { if (s->decompress.dict[i].parent_code != 0xFFFF) { - printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); + DEBUGP(DV42BIS,"Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); } } return 0; diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index b6036c7..3b34452 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -30,6 +30,11 @@ $(top_builddir)/src/gprs/gprs_gb_parse.o \ $(top_builddir)/src/gprs/oap.o \ $(top_builddir)/src/gprs/oap_messages.o \ + $(top_builddir)/src/gprs/gprs_llc_xid.o \ + $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ + $(top_builddir)/src/gprs/gprs_sndcp_comp_entity.o \ + $(top_builddir)/src/gprs/gprs_sndcp_hdrcomp.o \ + $(top_builddir)/src/gprs/slhc.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ @@ -37,5 +42,5 @@ $(LIBOSMOGB_LIBS) \ $(LIBCARES_LIBS) \ $(LIBCRYPTO_LIBS) \ - -lgtp -lrt + -lgtp -lrt -lm -- To view, visit https://gerrit.osmocom.org/652 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I65b9d625e72d3d61c99abdc7041773701d694d52 Gerrit-PatchSet: 5 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte From gerrit-no-reply at lists.osmocom.org Fri Aug 5 11:28:08 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Fri, 5 Aug 2016 11:28:08 +0000 Subject: [PATCH] openbsc[master]: Adding SNDCP-XID encoder / decoder In-Reply-To: References: Message-ID: Hello Harald Welte, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/641 to look at the new patch set (#6). Adding SNDCP-XID encoder / decoder The SNDCP-XID (or layer-3 xid) is used to exchange layer-3 parameters such as compression. The encoder encodes a bytestream that is then sent as regular XID field from LLC. We will need the SNDCP-XID to negotiate the parameters for our upcomming GPRS data and header compression features Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e --- M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_sndcp_xid.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_sndcp_xid.c 4 files changed, 2,201 insertions(+), 3 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/41/641/6 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 9e8c554..b37103f 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,7 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h + gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h gprs_sndcp_xid.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_sndcp_xid.h b/openbsc/include/openbsc/gprs_sndcp_xid.h new file mode 100644 index 0000000..9068152 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_xid.h @@ -0,0 +1,201 @@ +#ifndef _GPRS_SNDCP_XID_H +#define _GPRS_SNDCP_XID_H + +#include +#include + +#define CURRENT_SNDCP_VERSION 0 /* See TS 144 065, clause 8 */ +#define MAX_ENTITIES 32 /* TS 144 065 reserves 5 bit for compr. entity num. */ + +/* According to: TS 144 065 6.5.1.1 Format of the protocol control information + compression field (Figure 7) + + TS 144 065 6.6.1.1 Format of the data compression + field (Figure 9) */ + +struct gprs_sndcp_comp_field { + struct llist_head list; + + /* Propose bit (P), see also: 6.5.1.1.2 and 6.6.1.1.2 */ + unsigned int p; + + /* Entity number, see also: 6.5.1.1.3 and 6.6.1.1.3 */ + unsigned int entity; + + /* Algorithm identifier, see also: 6.5.1.1.4 and 6.6.1.1.4 */ + int algo; + + /* Number of contained PCOMP / DCOMP values */ + unsigned int comp_len; + + /* PCOMP / DCOMP values, see also: 6.5.1.1.5 and 6.6.1.1.5 */ + unsigned int comp[16]; + + /* Note: Only one of the following struct pointers may, + be used unused pointers must be set to NULL! */ + struct gprs_sndcp_hdrcomp_rfc1144_params *rfc1144_params; + struct gprs_sndcp_hdrcomp_rfc2507_params *rfc2507_params; + struct gprs_sndcp_hdrcomp_rohc_params *rohc_params; + struct gprs_sndcp_datacomp_v42bis_params *v42bis_params; + struct gprs_sndcp_datacomp_v44_params *v44_params; +}; + +/* According to: TS 144 065 6.5.1.1.4 Algorithm identifier */ +enum gprs_sndcp_hdr_comp_algo { + RFC_1144 = 0, /* TCP/IP header compression, see also 6.5.2 */ + RFC_2507 = 1, /* TCP/UDP/IP header compression, see also: 6.5.3 */ + ROHC = 2, /* Robust Header Compression, see also 6.5.4 */ +}; + +/* According to: TS 144 065 6.5.1.1.4 Algorithm identifier */ +enum gprs_sndcp_data_comp_algo { + V42BIS = 0, /* V42bis data compression, see also 6.6.2 */ + V44 = 1, /* V44 data compression, see also: 6.6.3 */ +}; + +/* According to: TS 144 065 8 SNDCP XID parameters */ +enum gprs_sndcp_xid_param_types { + SNDCP_XID_VERSION_NUMBER = 0, + SNDCP_XID_DATA_COMPRESSION = 1, /* See also: subclause 6.6.1 */ + SNDCP_XID_PROTOCOL_COMPRESSION = 2, /* See also: subclause 6.5.1 */ +}; + +/* According to: TS 144 065 6.5.2.1 Parameters (Table 5) */ +struct gprs_sndcp_hdrcomp_rfc1144_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int s01; /* (default 15) */ +}; + +/* According to: TS 144 065 6.5.2.2 Assignment of PCOMP values */ +enum gprs_sndcp_hdrcomp_rfc1144_pcomp { + RFC1144_PCOMP1 = 0, /* Uncompressed TCP */ + RFC1144_PCOMP2 = 1, /* Compressed TCP */ + RFC1144_PCOMP_NUM = 2 /* Number of pcomp values */ +}; + + + +/* According to: TS 144 065 6.5.3.1 Parameters (Table 6) */ +struct gprs_sndcp_hdrcomp_rfc2507_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int f_max_period; /* (default 256) */ + int f_max_time; /* (default 5) */ + int max_header; /* (default 168) */ + int tcp_space; /* (default 15) */ + int non_tcp_space; /* (default 15) */ +}; + +/* According to: TS 144 065 6.5.3.2 Assignment of PCOMP values for RFC2507 */ +enum gprs_sndcp_hdrcomp_rfc2507_pcomp { + RFC2507_PCOMP1 = 0, /* Full Header */ + RFC2507_PCOMP2 = 1, /* Compressed TCP */ + RFC2507_PCOMP3 = 2, /* Compressed TCP non delta */ + RFC2507_PCOMP4 = 3, /* Compressed non TCP */ + RFC2507_PCOMP5 = 4, /* Context state */ + RFC2507_PCOMP_NUM = 5 /* Number of pcomp values */ +}; + + + +/* According to: TS 144 065 6.5.4.1 Parameter (Table 10) */ +struct gprs_sndcp_hdrcomp_rohc_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int max_cid; /* (default 15) */ + int max_header; /* (default 168) */ + unsigned int profile_len; /* (default 1) */ + uint16_t profile[16]; /* (default 0, ROHC uncompressed) */ +}; + +/* According to: TS 144 065 6.5.4.2 Assignment of PCOMP values for ROHC */ +enum gprs_sndcp_hdrcomp_rohc_pcomp { + ROHC_PCOMP1 = 0, /* ROHC small CIDs */ + ROHC_PCOMP2 = 1, /* ROHC large CIDs */ + ROHC_PCOMP_NUM = 2 /* Number of pcomp values */ +}; + +/* ROHC compression profiles, see also: + http://www.iana.org/assignments/rohc-pro-ids/rohc-pro-ids.xhtml */ +enum gprs_sndcp_xid_rohc_profiles { + ROHC_UNCOMPRESSED = 0x0000, /* ROHC uncompressed [RFC5795] */ + ROHC_RTP = 0x0001, /* ROHC RTP [RFC3095] */ + ROHCV2_RTP = 0x0101, /* ROHCv2 RTP [RFC5225] */ + ROHC_UDP = 0x0002, /* ROHC UDP [RFC3095] */ + ROHCv2_UDP = 0x0102, /* ROHCv2 UDP [RFC5225] */ + ROHC_ESP = 0x0003, /* ROHC ESP [RFC3095] */ + ROHCV2_ESP = 0x0103, /* ROHCv2 ESP [RFC5225] */ + ROHC_IP = 0x0004, /* ROHC IP [RFC3843] */ + ROHCV2_IP = 0x0104, /* ROHCv2 IP [RFC5225] */ + ROHC_LLA = 0x0005, /* ROHC LLA [RFC4362] */ + ROHC_LLA_WITH_R_MODE = 0x0105, /* ROHC LLA with R-mode [RFC3408] */ + ROHC_TCP = 0x0006, /* ROHC TCP [RFC6846] */ + ROHC_RTP_UDP_LITE = 0x0007, /* ROHC RTP/UDP-Lite [RFC4019] */ + ROHCV2_RTP_UDP_LITE = 0x0107, /* ROHCv2 RTP/UDP-Lite [RFC5225] */ + ROHC_UDP_LITE = 0x0008, /* ROHC UDP-Lite [RFC4019] */ + ROHCV2_UDP_LITE = 0x0108, /* ROHCv2 UDP-Lite [RFC5225] */ +}; + + + +/* According to: TS 144 065 6.6.2.1 Parameters (Table 7a) */ +struct gprs_sndcp_datacomp_v42bis_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int p0; /* (default 3) */ + int p1; /* (default 2048) */ + int p2; /* (default 20) */ + +}; + +/* According to: ETSI TS 144 065 6.6.2.2 Assignment of DCOMP values */ +enum gprs_sndcp_datacomp_v42bis_dcomp { + V42BIS_DCOMP1 = 0, /* V42bis enabled */ + V42BIS_DCOMP_NUM = 1 /* Number of dcomp values */ +}; + + + +/* According to: TS 144 065 6.6.3.1 Parameters (Table 7c) */ +struct gprs_sndcp_datacomp_v44_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int c0; /* (default 10000000) */ + int p0; /* (default 3) */ + int p1t; /* Refer to subclause 6.6.3.1.4 */ + int p1r; /* Refer to subclause 6.6.3.1.5 */ + int p3t; /* (default 3 x p1t) */ + int p3r; /* (default 3 x p1r) */ +}; + +/* According to: ETSI TS 144 065 6.6.3.2 Assignment of DCOMP values */ +enum gprs_sndcp_datacomp_v44_dcomp { + V44_DCOMP1 = 0, /* Packet method compressed */ + V44_DCOMP2 = 1, /* Multi packet method compressed */ + V44_DCOMP_NUM = 2 /* Number of dcomp values */ +}; + +/* Transform a list with compression fields into an SNDCP-XID message (dst) */ +int gprs_sndcp_compile_xid(const struct llist_head *comp_fields, uint8_t *dst, + unsigned int dst_maxlen); + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +int gprs_sndcp_parse_xid(struct llist_head *comp_fields, + const uint8_t *src, unsigned int src_len, + const struct llist_head *comp_fields_req); + +/* Free a list with SNDCP-XID fields */ +void gprs_sndcp_free_comp_fields(struct llist_head *comp_fields); + +/* Find out to which compression class the specified comp-field belongs + (header compression or data compression?) */ +int gprs_sndcp_get_compression_class(const struct gprs_sndcp_comp_field + *comp_field); + +/* Dump a list with SNDCP-XID fields (Debug) */ +void gprs_sndcp_dump_comp_fields(const struct llist_head *comp_fields, + unsigned int logl); + + +#endif diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index b3a5137..67e9943 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -21,7 +21,7 @@ $(OSMO_LIBS) $(LIBCRYPTO_LIBS) -lrt osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \ - slhc.c \ + slhc.c gprs_sndcp_xid.c \ sgsn_main.c sgsn_vty.c sgsn_libgtp.c \ gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c \ gprs_llc_xid.c crc24.c \ @@ -32,7 +32,7 @@ osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ - $(LIBCRYPTO_LIBS) -lrt + $(LIBCRYPTO_LIBS) -lrt -lm osmo_gtphub_SOURCES = gtphub_main.c gtphub.c gtphub_sock.c gtphub_ares.c \ gtphub_vty.c sgsn_ares.c gprs_utils.c diff --git a/openbsc/src/gprs/gprs_sndcp_xid.c b/openbsc/src/gprs/gprs_sndcp_xid.c new file mode 100644 index 0000000..1bf1a03 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_xid.c @@ -0,0 +1,1997 @@ +/* GPRS SNDCP XID field encoding/decoding as per 3GPP TS 144 065 */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* When the propose bit in an SNDCP-XID compression field is set to zero, + the algorithm identifier is stripped. The algoritm parameters are specific + for each algorithms. The following struct is used to pass the information + about the referenced algorithm to the parser. */ +struct gprs_sndcp_hdrcomp_entity_algo_table { + unsigned int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + unsigned int algo; /* see also: 6.5.1.1.4 and 6.6.1.1.4 */ + unsigned int compclass; /* Can be either SNDCP_XID_DATA_COMPRESSION or + SNDCP_XID_PROTOCOL_COMPRESSION */ +}; + +/* + * FUNCTIONS RELATED TO SNDCP-XID ENCODING + */ + +/* Encode applicable sapis (works the same in all three compression schemes) */ +static int encode_hdrcomp_applicable_sapis(uint8_t * dst, + const unsigned int *nsapis, + unsigned int nsapis_len) +{ + /* + * NOTE: Buffer *dst needs offer at 2 bytes + * of space to store the generation results + */ + + uint16_t blob; + unsigned int nsapi; + int i; + + /* Encode applicable SAPIs */ + blob = 0; + for (i = 0; i < nsapis_len; i++) { + nsapi = nsapis[i]; + /* + * Only NSAPI 5 to 15 are applicable for user traffic (PDP- + * contexts). Only for these NSAPIs SNDCP-XID parameters + * can apply. See also ETSI TS 144 065 5.1 Service primitives + */ + if ((nsapi < 5) || (nsapi > 15)) + return -EINVAL; + blob |= (1 << nsapi); + } + + /* Store result */ + *dst = (blob >> 8) & 0xFF; + dst++; + *dst = blob & 0xFF; + + return 2; +} + + +/* + * Encode rfc1144 parameter field + * (see also: ETSI TS 144 065 6.5.2.1, Table 5) + */ +static int encode_hdrcomp_rfc1144_params(uint8_t * dst, + unsigned int dst_maxlen, + const struct + gprs_sndcp_hdrcomp_rfc1144_params + *params) +{ + /* + * NOTE: Buffer *dst should offer at least 3 bytes + * of space to store the generation results + */ + + int dst_counter = 0; + int rc; + + /* Exit immediately if no source struct is available */ + if (!params) + return -EINVAL; + + /* Exit immediately if no sufficient memory space is supplied */ + if ((dst_maxlen < 3) || !dst) + return -EINVAL; + + /* + * Exit if number of possible nsapis exceeds valid range + * (Only 11 nsapis possible for PDP-Contexts) + */ + if ((params->nsapi_len < 0) || (params->nsapi_len > 11)) + return -EINVAL; + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_hdrcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode s01 (see also: ETSI TS 144 065 6.5.2.1, Table 5) */ + *dst = params->s01; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + + +/* + * Encode rfc2507 parameter field + * (see also: ETSI TS 144 065 6.5.3.1, Table 6) + */ +static int encode_hdrcomp_rfc2507_params(uint8_t * dst, + unsigned int dst_maxlen, + const struct + gprs_sndcp_hdrcomp_rfc2507_params + *params) +{ + /* + * NOTE: Buffer *dst should offer at least 3 bytes + * of space to store the generation results + */ + + int dst_counter = 0; + int rc; + + /* Exit immediately if no source struct is available */ + if (!params) + return -EINVAL; + + /* Exit immediately if no sufficient memory space is supplied */ + if ((dst_maxlen < 9) || !dst) + return -EINVAL; + + /* + * Exit if number of possible nsapis exceeds valid range + * (Only 11 nsapis possible for PDP-Contexts) + */ + if ((params->nsapi_len < 0) || (params->nsapi_len > 11)) + return -EINVAL; + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_hdrcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode F_MAX_PERIOD (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + if ((params->f_max_period < 1) || (params->f_max_period > 65535)) + return -EINVAL; + *dst = (params->f_max_period >> 8) & 0xFF; + dst++; + dst_counter++; + *dst = (params->f_max_period) & 0xFF; + dst++; + dst_counter++; + + /* Encode F_MAX_TIME (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + if ((params->f_max_time < 1) || (params->f_max_time > 255)) + return -EINVAL; + *dst = params->f_max_time; + dst++; + dst_counter++; + + /* Encode MAX_HEADER (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + if ((params->max_header < 60) || (params->max_header > 255)) + return -EINVAL; + *dst = params->max_header; + dst++; + dst_counter++; + + /* Encode TCP_SPACE (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + if ((params->tcp_space < 3) || (params->tcp_space > 255)) + return -EINVAL; + *dst = params->tcp_space; + dst++; + dst_counter++; + + /* Encode NON_TCP_SPACE (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + if ((params->non_tcp_space < 3) || (params->tcp_space > 65535)) + return -EINVAL; + *dst = (params->non_tcp_space >> 8) & 0xFF; + dst++; + dst_counter++; + *dst = (params->non_tcp_space) & 0xFF; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + + +/* + * Encode ROHC parameter field + * (see also: ETSI TS 144 065 6.5.4.1, Table 10) + */ +static int encode_hdrcomp_rohc_params(uint8_t * dst, + unsigned int dst_maxlen, const struct + gprs_sndcp_hdrcomp_rohc_params + *params) +{ + /* + * NOTE: Buffer *dst should offer at least 36 + * (2 * 16 Profiles + 2 * 3 Parameter) bytes + * of memory space to store generation results + */ + + int i; + int dst_counter = 0; + int rc; + + /* Exit immediately if no source struct is available */ + if (!params) + return -EINVAL; + + /* Exit immediately if no sufficient memory space is supplied */ + if ((dst_maxlen < 38) || !dst) + return -EINVAL; + + /* + * Exit if number of possible nsapis exceeds valid range + * (Only 11 nsapis possible for PDP-Contexts) + */ + if ((params->nsapi_len < 0) || (params->nsapi_len > 11)) + return -EINVAL; + + /* + * Exit if number of ROHC profiles exceeds limit + * (ROHC supports only a maximum of 16 different profiles) + */ + if ((params->profile_len < 0) || (params->profile_len > 16)) + return -EINVAL; + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_hdrcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode MAX_CID (see also: ETSI TS 144 065 6.5.4.1, Table 10) */ + if ((params->max_cid < 0) || (params->max_cid > 16383)) + return -EINVAL; + *dst = (params->max_cid >> 8) & 0xFF; + dst++; + *dst = params->max_cid & 0xFF; + dst++; + dst_counter += 2; + + /* Encode MAX_HEADER (see also: ETSI TS 144 065 6.5.4.1, Table 10) */ + if ((params->max_header < 60) || (params->max_header > 255)) + return -EINVAL; + *dst = (params->max_header >> 8) & 0xFF; + dst++; + *dst = params->max_header & 0xFF; + dst++; + dst_counter += 2; + + /* Encode ROHC Profiles (see also: ETSI TS 144 065 6.5.4.1, Table 10) */ + for (i = 0; i < params->profile_len; i++) { + *dst = (params->profile[i] >> 8) & 0xFF; + dst++; + *dst = params->profile[i] & 0xFF; + dst++; + dst_counter += 2; + } + + /* Return generated length */ + return dst_counter; +} + + +/* + * Encode V42bis parameter field + * (see also: ETSI TS 144 065 6.6.2.1, Table 7a) + */ +static int encode_datacomp_v42bis_params(uint8_t * dst, + unsigned int dst_maxlen, + const struct + gprs_sndcp_datacomp_v42bis_params + *params) +{ + /* + * NOTE: Buffer *dst should offer at least 6 bytes + * of space to store the generation results + */ + + int dst_counter = 0; + int rc; + + /* Exit immediately if no source struct is available */ + if (!params) + return -EINVAL; + + /* Exit immediately if no sufficient memory space is supplied */ + if ((dst_maxlen < 6) || !dst) + return -EINVAL; + + /* + * Exit if number of possible nsapis exceeds valid range + * (Only 11 nsapis possible for PDP-Contexts) + */ + if ((params->nsapi_len < 0) || (params->nsapi_len > 11)) + return -EINVAL; + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_hdrcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode P0 (see also: ETSI TS 144 065 6.6.2.1, Table 7a) */ + if ((params->p0 < 0) || (params->p0 > 3)) + return -EINVAL; + *dst = params->p0 & 0x03; + dst++; + dst_counter++; + + /* Encode P1 (see also: ETSI TS 144 065 6.6.2.1, Table 7a) */ + if ((params->p1 < 512) || (params->p1 > 65535)) + return -EINVAL; + *dst = (params->p1 >> 8) & 0xFF; + dst++; + *dst = params->p1 & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P2 (see also: ETSI TS 144 065 6.6.2.1, Table 7a) */ + if ((params->p2 < 6) || (params->p2 > 250)) + return -EINVAL; + *dst = params->p2; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + + +/* + * Encode V44 parameter field + * (see also: ETSI TS 144 065 6.6.3.1, Table 7c) + */ +static int encode_datacomp_v44_params(uint8_t * dst, + unsigned int dst_maxlen, const struct + gprs_sndcp_datacomp_v44_params + *params) +{ + /* + * NOTE: Buffer *dst should offer at least 12 bytes + * of space to store the generation results + */ + + int dst_counter = 0; + int rc; + + /* Exit immediately if no source struct is available */ + if (!params) + return -EINVAL; + + /* Exit immediately if no sufficient memory space is supplied */ + if ((dst_maxlen < 12) || !dst) + return -EINVAL; + + /* + * Exit if number of possible nsapis exceeds valid range + * (Only 11 nsapis possible for PDP-Contexts) + */ + if ((params->nsapi_len < 0) || (params->nsapi_len > 11)) + return -EINVAL; + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_hdrcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode C0 (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + if ((params->c0 == 0x80) || (params->c0 == 0xC0)) { + *dst = params->c0 & 0xC0; + dst++; + dst_counter++; + } else + return -EINVAL; + + /* Encode P0 (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + if ((params->p0 < 0) || (params->p0 > 3)) + return -EINVAL; + *dst = params->p0 & 0x03; + dst++; + dst_counter++; + + /* Encode P1T (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + if ((params->p1t < 256) || (params->p1t > 65535)) + return -EINVAL; + *dst = (params->p1t >> 8) & 0xFF; + dst++; + *dst = params->p1t & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P1R (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + if ((params->p1r < 256) || (params->p1r > 65535)) + return -EINVAL; + *dst = (params->p1r >> 8) & 0xFF; + dst++; + *dst = params->p1r & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P3T (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + if ((params->p3t < 0) || (params->p3t > 65535)) + return -EINVAL; + if (params->p3t < 2 * params->p1t) + return -EINVAL; + *dst = (params->p3t >> 8) & 0xFF; + dst++; + *dst = params->p3t & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P3R (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + if ((params->p3r < 0) || (params->p3r > 65535)) + return -EINVAL; + if (params->p3r < 2 * params->p1r) + return -EINVAL; + *dst = (params->p3r >> 8) & 0xFF; + dst++; + *dst = params->p3r & 0xFF; + dst++; + dst_counter += 2; + + /* Return generated length */ + return dst_counter; +} + + +/* + * Encode data or protocol control information compression field + * (see also: ETSI TS 144 065 6.6.1.1, Figure 9 and + * ETSI TS 144 065 6.5.1.1, Figure 7) + */ +static int encode_comp_field(uint8_t * dst, unsigned int dst_maxlen, + const struct gprs_sndcp_comp_field + *comp_field) +{ + int dst_counter = 0; + int len; + int expected_length; + int i; + + uint8_t payload_bytes[256]; + int payload_bytes_len = -1; + + /* If possible, try do encode payload bytes first */ + if (comp_field->rfc1144_params) + payload_bytes_len = + encode_hdrcomp_rfc1144_params(payload_bytes, + sizeof(payload_bytes), + comp_field-> + rfc1144_params); + else if (comp_field->rfc2507_params) + payload_bytes_len = + encode_hdrcomp_rfc2507_params(payload_bytes, + sizeof(payload_bytes), + comp_field-> + rfc2507_params); + else if (comp_field->rohc_params) + payload_bytes_len = + encode_hdrcomp_rohc_params(payload_bytes, + sizeof(payload_bytes), + comp_field->rohc_params); + else if (comp_field->v42bis_params) + payload_bytes_len = + encode_datacomp_v42bis_params(payload_bytes, + sizeof(payload_bytes), + comp_field-> + v42bis_params); + else if (comp_field->v44_params) + payload_bytes_len = + encode_datacomp_v44_params(payload_bytes, + sizeof(payload_bytes), + comp_field->v44_params); + else + return -EINVAL; + + /* Exit immediately if payload byte generation failed */ + if (payload_bytes_len < 0) + return -EINVAL; + + /* Exit immediately if no source struct is available */ + if (!comp_field) + return -EINVAL; + + /* Check if comp_len is within bounds */ + if ((comp_field->comp_len < 0) || (comp_field->comp_len > 16)) + return -EINVAL; + + /* Calculate length field of the data block */ + if (comp_field->p) { + len = + payload_bytes_len + + ceil((double) (comp_field->comp_len) / 2.0); + expected_length = len + 3; + } else { + len = payload_bytes_len; + expected_length = len + 2; + } + + /* Exit immediately if no sufficient memory space is supplied */ + if ((dst_maxlen < expected_length) || !dst) + return -EINVAL; + + /* Check if the entity number is within bounds */ + if ((comp_field->entity < 0) || (comp_field->entity > 0x1f)) + return -EINVAL; + + /* Check if the algorithm number is within bounds */ + if ((comp_field->algo < 0) || (comp_field->algo > 0x1f)) + return -EINVAL; + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode Propose bit */ + if (comp_field->p) + *dst |= (1 << 7); + + /* Encode entity number */ + *dst |= comp_field->entity & 0x1F; + dst++; + dst_counter++; + + /* Encode algorithm number */ + if (comp_field->p) { + *dst |= comp_field->algo & 0x1F; + dst++; + dst_counter++; + } + + /* Encode length field */ + *dst |= len & 0xFF; + dst++; + dst_counter++; + + /* Encode PCOMP/DCOMP values */ + if (comp_field->p) { + for (i = 0; i < comp_field->comp_len; i++) { + /* Check if submitted PCOMP/DCOMP + values are within bounds */ + if ((comp_field->comp[i] < 0) + || (comp_field->comp[i] > 0x0F)) + return -EINVAL; + + if (i & 1) { + *dst |= comp_field->comp[i] & 0x0F; + dst++; + dst_counter++; + } else + *dst |= (comp_field->comp[i] << 4) & 0xF0; + } + + if (i & 1) { + dst++; + dst_counter++; + } + } + + /* Append payload bytes */ + memcpy(dst, payload_bytes, payload_bytes_len); + dst_counter += payload_bytes_len; + + /* Return generated length */ + return dst_counter; +} + + +/* Find out to which compression class the specified comp-field belongs + (header compression or data compression?) */ +int gprs_sndcp_get_compression_class(const struct gprs_sndcp_comp_field + *comp_field) +{ + if (comp_field->rfc1144_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->rfc2507_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->rohc_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->v42bis_params) + return SNDCP_XID_DATA_COMPRESSION; + else if (comp_field->v44_params) + return SNDCP_XID_DATA_COMPRESSION; + else + return -EINVAL; +} + + +/* Convert all compression fields to bytstreams */ +static int gprs_sndcp_pack_fields(const struct llist_head *comp_fields, + uint8_t * dst, + unsigned int dst_maxlen, int class) +{ + struct gprs_sndcp_comp_field *comp_field; + int byte_counter = 0; + int rc; + + llist_for_each_entry(comp_field, comp_fields, list) { + if (class == gprs_sndcp_get_compression_class(comp_field)) { + rc = encode_comp_field(dst + byte_counter, + dst_maxlen - byte_counter, + comp_field); + + /* Immediately stop on error */ + if (rc < 0) + return rc; + + byte_counter += rc; + } + } + + /* Return generated length */ + return byte_counter; +} + + +/* Transform a list with compression fields into an SNDCP-XID message (dst) */ +int gprs_sndcp_compile_xid(const struct llist_head *comp_fields, + uint8_t * dst, unsigned int dst_maxlen) +{ + int rc; + int byte_counter = 0; + uint8_t comp_bytes[512]; + uint8_t xid_version_number[1] = { CURRENT_SNDCP_VERSION }; + + /* Exit immediately if no sufficient memory space is supplied */ + if ((dst_maxlen < 2 + sizeof(xid_version_number)) || !dst) + return -EINVAL; + + /* Prepend header */ + dst = + tlv_put(dst, SNDCP_XID_VERSION_NUMBER, + sizeof(xid_version_number), xid_version_number); + byte_counter += (sizeof(xid_version_number) + 2); + + /* Add data compression fields */ + rc = gprs_sndcp_pack_fields(comp_fields, comp_bytes, + sizeof(comp_bytes), + SNDCP_XID_DATA_COMPRESSION); + if (rc < 0) + return rc; + else if (rc > 0) { + dst = + tlv_put(dst, SNDCP_XID_DATA_COMPRESSION, rc, + comp_bytes); + byte_counter += rc + 2; + } + + /* Add header compression fields */ + rc = gprs_sndcp_pack_fields(comp_fields, comp_bytes, + sizeof(comp_bytes), + SNDCP_XID_PROTOCOL_COMPRESSION); + if (rc < 0) + return rc; + else if (rc > 0) { + dst = + tlv_put(dst, SNDCP_XID_PROTOCOL_COMPRESSION, rc, + comp_bytes); + byte_counter += rc + 2; + } + + /* Return generated length */ + return byte_counter; +} + + + + + + + + + + +/* + * FUNCTIONS RELATED TO SNDCP-XID DECODING + */ + +/* Decode applicable sapis (works the same in all three compression schemes) */ +static int decode_hdrcomp_applicable_sapis(const uint8_t * src, + unsigned int src_len, + unsigned int *nsapis, + unsigned int *nsapis_len) +{ + uint16_t blob; + int i; + int nsapi_len = 0; + + /* Exit immediately if no result can be stored */ + if (!nsapis) + return -EINVAL; + + /* Exit immediately if not enough input data is available */ + if (src_len < 2) + return -EINVAL; + + /* Read bitmask */ + blob = *src; + blob = (blob << 8) & 0xFF00; + src++; + blob |= (*src) & 0xFF; + blob = (blob >> 5); + + /* Decode applicable SAPIs */ + for (i = 0; i < 15; i++) { + if ((blob >> i) & 1) { + nsapis[nsapi_len] = i + 5; + nsapi_len++; + } + } + + /* Return consumed length */ + *nsapis_len = nsapi_len; + return 2; +} + +/* Decode 16 bit field */ +static int decode_hdrcomp_16_bit_field(const uint8_t * src, + unsigned int src_len, + int value_min, int value_max, + int *value_int, + uint16_t * value_uint16) +{ + uint16_t blob; + + /* Reset values to zero (just to be sure) */ + if (value_int) + *value_int = -1; + if (value_uint16) + *value_uint16 = 0; + + /* Exit if not enough src are available */ + if (src_len < 2) + return -EINVAL; + + /* Decode bit value */ + blob = *src; + blob = (blob << 8) & 0xFF00; + src++; + blob |= *src; + + /* Check if parsed value is within bounds */ + if (blob < value_min) + return -EINVAL; + if (blob > value_max) + return -EINVAL; + + /* Hand back results to the caller */ + if (value_int) + *value_int = blob; + if (value_uint16) + *value_uint16 = blob; + + /* Return consumed length */ + return 2; +} + +/* Decode 8 bit field */ +static int decode_hdrcomp_8_bit_field(const uint8_t * src, + unsigned int src_len, + int value_min, int value_max, + int *value_int, + uint8_t * value_uint8) +{ + uint8_t blob; + + /* Reset values to invalid (just to be sure) */ + if (value_int) + *value_int = -1; + if (value_uint8) + *value_uint8 = 0; + + /* Exit if not enough src are available */ + if (src_len < 1) + return -EINVAL; + + /* Decode bit value */ + blob = *src; + + /* Check if parsed value is within bounds */ + if (blob < value_min) + return -EINVAL; + if (blob > value_max) + return -EINVAL; + + /* Hand back results to the caller */ + if (value_int) + *value_int = blob; + if (value_uint8) + *value_uint8 = blob; + + /* Return consumed length */ + return 1; +} + + + + +/* Decode rfc1144 parameter field see also: ETSI TS 144 065 6.5.2.1, Table 5) */ +static int decode_hdrcomp_rfc1144_params(const uint8_t * src, + unsigned int src_len, struct + gprs_sndcp_hdrcomp_rfc1144_params + *params) +{ + int rc; + int byte_counter = 0; + + /* Exit immediately if no result can be stored */ + if (!params) + return -EINVAL; + + /* Mark all optional parameters invalid by default */ + params->s01 = -1; + + /* Decode applicable SAPIs */ + rc = decode_hdrcomp_applicable_sapis(src, src_len, + params->nsapi, + ¶ms->nsapi_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* + * Decode parameter S0 -1 + * (see also: ETSI TS 144 065 6.5.2.1, Table 5) + */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, 0, + 255, ¶ms->s01, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* + * Decode rfc2507 parameter field + * (see also: ETSI TS 144 065 6.5.3.1, Table 6) + */ +static int decode_hdrcomp_rfc2507_params(const uint8_t * src, + unsigned int src_len, struct + gprs_sndcp_hdrcomp_rfc2507_params + *params) +{ + int rc; + int byte_counter = 0; + + /* Exit immediately if no result can be stored */ + if (!params) + return -EINVAL; + + /* Mark all optional parameters invalid by default */ + params->f_max_period = -1; + params->f_max_time = -1; + params->max_header = -1; + params->tcp_space = -1; + params->non_tcp_space = -1; + + /* Decode applicable SAPIs */ + rc = decode_hdrcomp_applicable_sapis(src, src_len, + params->nsapi, + ¶ms->nsapi_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode F_MAX_PERIOD (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 1, 65535, ¶ms->f_max_period, + NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode F_MAX_TIME (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, 1, + 255, ¶ms->f_max_time, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_HEADER (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, + 60, 255, ¶ms->max_header, + NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode TCP_SPACE (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, 3, + 255, ¶ms->tcp_space, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode NON_TCP_SPACE (see also: ETSI TS 144 065 6.5.3.1, Table 6) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 3, 65535, ¶ms->non_tcp_space, + NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Decode ROHC parameter field (see also: ETSI TS 144 065 6.5.4.1, Table 10) */ +static int decode_hdrcomp_rohc_params(const uint8_t * src, + unsigned int src_len, + struct gprs_sndcp_hdrcomp_rohc_params + *params) +{ + int rc; + int byte_counter = 0; + int i; + + /* Exit immediately if no result can be stored */ + if (!params) + return -EINVAL; + + /* Mark all optional parameters invalid by default */ + params->max_cid = -1; + params->max_header = -1; + + /* Decode applicable SAPIs */ + rc = decode_hdrcomp_applicable_sapis(src, src_len, + params->nsapi, + ¶ms->nsapi_len); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_CID (see also: ETSI TS 144 065 6.5.4.1, Table 10) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 0, 16383, ¶ms->max_cid, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_HEADER (see also: ETSI TS 144 065 6.5.4.1, Table 10) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 60, 255, ¶ms->max_header, + NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode Profiles (see also: ETSI TS 144 065 6.5.4.1, Table 10) */ + for (i = 0; i < 16; i++) { + params->profile_len = 0; + rc = decode_hdrcomp_16_bit_field(src, + src_len - byte_counter, + 0, 65535, NULL, + ¶ms->profile[i]); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + params->profile_len = i + 1; + } + + /* Return consumed length */ + return byte_counter; +} + + +/* + * Decode V42bis parameter field + * (see also: ETSI TS 144 065 6.6.2.1, Table 7a) + */ +static int decode_datacomp_v42bis_params(const uint8_t * src, + unsigned int src_len, struct + gprs_sndcp_datacomp_v42bis_params + *params) +{ + int rc; + int byte_counter = 0; + + /* Exit immediately if no result can be stored */ + if (!params) + return -EINVAL; + + /* Mark all optional parameters invalid by default */ + params->p0 = -1; + params->p1 = -1; + params->p2 = -1; + + /* Decode applicable SAPIs */ + rc = decode_hdrcomp_applicable_sapis(src, src_len, + params->nsapi, + ¶ms->nsapi_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode P0 (see also: ETSI TS 144 065 6.6.2.1, Table 7a) */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, 0, + 3, ¶ms->p0, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1 (see also: ETSI TS 144 065 6.6.2.1, Table 7a) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 512, 65535, ¶ms->p1, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P2 (see also: ETSI TS 144 065 6.6.2.1, Table 7a) */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, 6, + 250, ¶ms->p2, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + + +/* Decode V44 parameter field (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ +static int decode_datacomp_v44_params(const uint8_t * src, + unsigned int src_len, + struct gprs_sndcp_datacomp_v44_params + *params) +{ + int rc; + int byte_counter = 0; + + /* Exit immediately if no result can be stored */ + if (!params) + return -EINVAL; + + /* Mark all optional parameters invalid by default */ + params->c0 = -1; + params->p0 = -1; + params->p1t = -1; + params->p1r = -1; + params->p3t = -1; + params->p3r = -1; + + /* Decode applicable SAPIs */ + rc = decode_hdrcomp_applicable_sapis(src, src_len, + params->nsapi, + ¶ms->nsapi_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode C0 (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, 0, + 255, ¶ms->c0, NULL); + if (rc <= 0) + return byte_counter; + if ((params->c0 != 0x80) && (params->c0 != 0xC0)) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Decode P0 (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + rc = decode_hdrcomp_8_bit_field(src, src_len - byte_counter, 0, + 3, ¶ms->p0, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1T (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 265, 65535, ¶ms->p1t, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1R (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 265, 65535, ¶ms->p1r, NULL); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P3T (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 265, 65535, ¶ms->p3t, NULL); + if (rc <= 0) + return byte_counter; + if (params->p3t < 2 * params->p1t) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Decode P3R (see also: ETSI TS 144 065 6.6.3.1, Table 7c) */ + rc = decode_hdrcomp_16_bit_field(src, src_len - byte_counter, + 265, 65535, ¶ms->p3r, NULL); + if (rc <= 0) + return byte_counter; + if (params->p3r < 2 * params->p1r) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + + +/* Lookup algorithm identfier by entity ID */ +static int lookup_algorithm_identifier(int entity, struct + gprs_sndcp_hdrcomp_entity_algo_table + *lt, unsigned int lt_len, + int compclass) +{ + int i; + if ((lt) && (lt_len > 0)) { + for (i = 0; i < lt_len; i++) { + if ((lt[i].entity == entity) + && (lt[i].compclass == compclass)) + return lt[i].algo; + } + } + + return -1; +} + +/* + * Helper function for decode_comp_field(), decodes + * numeric pcomp/dcomp values + */ +static int decode_comp_values(struct gprs_sndcp_comp_field *comp_field, + const uint8_t * src, int compclass) +{ + int src_counter = 0; + int i; + + if (comp_field->p) { + /* Determine the number of expected PCOMP/DCOMP values */ + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + /* For protocol compression */ + switch (comp_field->algo) { + case RFC_1144: + comp_field->comp_len = RFC1144_PCOMP_NUM; + break; + case RFC_2507: + comp_field->comp_len = RFC2507_PCOMP_NUM; + break; + case ROHC: + comp_field->comp_len = ROHC_PCOMP_NUM; + break; + + /* Exit if the algorithem type encodes + something unknown / unspecified */ + default: + return -EINVAL; + } + } else { + /* For data compression */ + switch (comp_field->algo) { + case V42BIS: + comp_field->comp_len = V42BIS_DCOMP_NUM; + break; + case V44: + comp_field->comp_len = V44_DCOMP_NUM; + break; + + /* Exit if the algorithem type encodes + something unknown / unspecified */ + default: + return -EINVAL; + } + } + + for (i = 0; i < comp_field->comp_len; i++) { + if (i & 1) { + comp_field->comp[i] = (*src) & 0x0F; + src++; + src_counter++; + } else + comp_field->comp[i] = ((*src) >> 4) & 0x0F; + } + + if (i & 1) { + src++; + src_counter++; + } + } + + return src_counter; +} + +/* + * Helper function for decode_comp_field(), decodes the parameters + * which are protocol compression specific + */ +static int decode_pcomp_params(struct gprs_sndcp_comp_field *comp_field, + const uint8_t * src, int src_len) +{ + int rc; + + switch (comp_field->algo) { + case RFC_1144: + comp_field->rfc1144_params = talloc_zero(NULL, struct + gprs_sndcp_hdrcomp_rfc1144_params); + rc = decode_hdrcomp_rfc1144_params(src, src_len, + comp_field-> + rfc1144_params); + if (rc < 0) + talloc_free(comp_field->rfc1144_params); + break; + case RFC_2507: + comp_field->rfc2507_params = talloc_zero(NULL, struct + gprs_sndcp_hdrcomp_rfc2507_params); + rc = decode_hdrcomp_rfc2507_params(src, src_len, + comp_field-> + rfc2507_params); + if (rc < 0) + talloc_free(comp_field->rfc1144_params); + break; + case ROHC: + comp_field->rohc_params = talloc_zero(NULL, struct + gprs_sndcp_hdrcomp_rohc_params); + rc = decode_hdrcomp_rohc_params(src, src_len, + comp_field->rohc_params); + if (rc < 0) + talloc_free(comp_field->rohc_params); + break; + + /* If no suitable decoder is detected, + leave the remaining bytes undecoded */ + default: + rc = src_len; + } + + if (rc < 0) { + comp_field->rfc1144_params = NULL; + comp_field->rfc2507_params = NULL; + comp_field->rohc_params = NULL; + } + + return rc; +} + +/* + * Helper function for decode_comp_field(), decodes the parameters + * which are data compression specific + */ +static int decode_dcomp_params(struct gprs_sndcp_comp_field *comp_field, + const uint8_t * src, int src_len) +{ + int rc; + + + switch (comp_field->algo) { + case V42BIS: + comp_field->v42bis_params = talloc_zero(NULL, struct + gprs_sndcp_datacomp_v42bis_params); + rc = decode_datacomp_v42bis_params(src, src_len, + comp_field-> + v42bis_params); + if (rc < 0) + talloc_free(comp_field->v42bis_params); + break; + case V44: + comp_field->v44_params = talloc_zero(NULL, struct + gprs_sndcp_datacomp_v44_params); + rc = decode_datacomp_v44_params(src, src_len, + comp_field->v44_params); + if (rc < 0) + talloc_free(comp_field->v44_params); + break; + + /* If no suitable decoder is detected, + leave the remaining bytes undecoded */ + default: + rc = src_len; + } + + + if (rc < 0) { + comp_field->v42bis_params = NULL; + comp_field->v44_params = NULL; + } + + return rc; +} + + + +/* + * Decode data or protocol control information compression field + * (see also: ETSI TS 144 065 6.6.1.1, Figure 9 and + * ETSI TS 144 065 6.5.1.1, Figure 7) + */ +static int decode_comp_field(const uint8_t * src, unsigned int src_len, + struct gprs_sndcp_comp_field *comp_field, + struct + gprs_sndcp_hdrcomp_entity_algo_table + *lt, unsigned int lt_len, int compclass) +{ + int src_counter = 0; + unsigned int len; + int rc; + + /* Exit immediately if it is clear that no + parseable data is present */ + if ((src_len < 1) || !src) + return -EINVAL; + + /* Exit immediately if no result can be stored */ + if (!comp_field) + return -EINVAL; + + /* Zero out target struct */ + memset(comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + + /* Decode Propose bit and Entity number */ + if ((*src) & 0x80) + comp_field->p = 1; + comp_field->entity = (*src) & 0x1F; + src_counter++; + src++; + + /* Decode algorithm number (if present) */ + if (comp_field->p) { + comp_field->algo = (*src) & 0x1F; + src_counter++; + src++; + } + /* Alternatively take the information from the lookup table */ + else + comp_field->algo = + lookup_algorithm_identifier(comp_field->entity, lt, + lt_len, compclass); + + /* Decode length field */ + len = *src; + src_counter++; + src++; + + + /* Decode PCOMP/DCOMP values */ + rc = decode_comp_values(comp_field, src, compclass); + if (rc < 0) + return -EINVAL; + src_counter += rc; + src += rc; + len -= rc; + + /* Decode algorithm specific payload data */ + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + rc = decode_pcomp_params(comp_field, src, len); + else if (compclass == SNDCP_XID_DATA_COMPRESSION) + rc = decode_dcomp_params(comp_field, src, len); + else + return -EINVAL; + + if (rc >= 0) + src_counter += rc; + else + return -EINVAL; + + + /* Return consumed length */ + return src_counter; +} + + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +static int gprs_sndcp_decode_xid(struct llist_head *comp_fields, + const uint8_t * src, unsigned int src_len, + struct + gprs_sndcp_hdrcomp_entity_algo_table + *lt, unsigned int lt_len) +{ + int src_pos = 0; + uint8_t tag; + uint16_t tag_len; + const uint8_t *val; + struct gprs_sndcp_comp_field *comp_field; + int rc; + int byte_counter = 0; + int comp_field_count = 0; + + /* Valid TLV-Tag and types */ + static const struct tlv_definition sndcp_xid_def = { + .def = { + [SNDCP_XID_VERSION_NUMBER] = {TLV_TYPE_TLV,}, + [SNDCP_XID_DATA_COMPRESSION] = {TLV_TYPE_TLV,}, + [SNDCP_XID_PROTOCOL_COMPRESSION] = {TLV_TYPE_TLV,}, + }, + }; + + /* Parse TLV-Encoded SNDCP-XID message and defer payload + to the apporpiate sub-parser functions */ + while (1) { + src_pos += + tlv_parse_one(&tag, &tag_len, &val, &sndcp_xid_def, + src + src_pos, src_len - src_pos); + + /* Decode compression parameters */ + if ((tag == SNDCP_XID_PROTOCOL_COMPRESSION) + || (tag == SNDCP_XID_DATA_COMPRESSION)) { + byte_counter = 0; + do { + /* Bail if more than the maximum number of + comp_fields is generated */ + if (comp_field_count > MAX_ENTITIES * 2) { + gprs_sndcp_free_comp_fields + (comp_fields); + return -EINVAL; + } + + /* Parse and add comp_field */ + comp_field = + talloc_zero(NULL, + struct + gprs_sndcp_comp_field); + + rc = decode_comp_field(val + byte_counter, + tag_len - + byte_counter, + comp_field, lt, + lt_len, tag); + + if (rc < 0) { + talloc_free(comp_field); + gprs_sndcp_free_comp_fields + (comp_fields); + return -EINVAL; + } else { + byte_counter += rc; + llist_add(&comp_field->list, + comp_fields); + } + + comp_field_count++; + } + while (tag_len - byte_counter > 0); + } + + /* Stop when no further TLV elements can be expected */ + if (src_len - src_pos <= 2) + break; + } + + return 0; +} + +/* Fill up lookutable from a list with comression entitiy fields */ +static int gprs_sndcp_fill_table(struct + gprs_sndcp_hdrcomp_entity_algo_table *lt, + unsigned int lt_len, + const struct llist_head *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field; + int i = 0; + + if (!(comp_fields)) + return -EINVAL; + if (!(lt)) + return -EINVAL; + + memset(lt, 0, + lt_len * + sizeof(struct gprs_sndcp_hdrcomp_entity_algo_table)); + + llist_for_each_entry(comp_field, comp_fields, list) { + + lt[i].entity = comp_field->entity; + lt[i].algo = comp_field->algo; + lt[i].compclass = + gprs_sndcp_get_compression_class(comp_field); + + if (lt[i].compclass < 0) { + memset(lt, 0, lt_len * + sizeof(struct + gprs_sndcp_hdrcomp_entity_algo_table)); + return -EINVAL; + } + + i++; + } + + return i; +} + + +/* + * Complete comp field params + * (if a param (dst) is not valid, it will be copied from source (src) + */ +static int complete_comp_field_params(struct gprs_sndcp_comp_field + *comp_field_dst, const struct gprs_sndcp_comp_field + *comp_field_src) +{ + if (comp_field_dst->algo < 0) + return -EINVAL; + + if ((comp_field_dst->rfc1144_params) + && (comp_field_src->rfc1144_params)) { + if (comp_field_dst->rfc1144_params->s01 < 0) + comp_field_dst->rfc1144_params->s01 = + comp_field_src->rfc1144_params->s01; + return 0; + } + + if ((comp_field_dst->rfc2507_params) + && (comp_field_src->rfc2507_params)) { + + if (comp_field_dst->rfc2507_params->f_max_period < 0) + comp_field_dst->rfc2507_params->f_max_period = + comp_field_src->rfc2507_params->f_max_period; + + if (comp_field_dst->rfc2507_params->f_max_time < 0) + comp_field_dst->rfc2507_params->f_max_time = + comp_field_src->rfc2507_params->f_max_time; + + if (comp_field_dst->rfc2507_params->max_header < 0) + comp_field_dst->rfc2507_params->max_header = + comp_field_src->rfc2507_params->max_header; + + if (comp_field_dst->rfc2507_params->tcp_space < 0) + comp_field_dst->rfc2507_params->tcp_space = + comp_field_src->rfc2507_params->tcp_space; + + if (comp_field_dst->rfc2507_params->non_tcp_space < 0) + comp_field_dst->rfc2507_params->non_tcp_space = + comp_field_src->rfc2507_params->non_tcp_space; + return 0; + } + + if ((comp_field_dst->rohc_params) + && (comp_field_src->rohc_params)) { + if (comp_field_dst->rfc1144_params->s01 < 0) + + if (comp_field_dst->rohc_params->max_cid < 0) + comp_field_dst->rohc_params->max_cid = + comp_field_src->rohc_params->max_cid; + + if (comp_field_dst->rohc_params->max_header < 0) + comp_field_dst->rohc_params->max_header = + comp_field_src->rohc_params->max_header; + + if (comp_field_dst->rohc_params->profile_len > 0) { + memcpy(comp_field_dst->rohc_params->profile, + comp_field_src->rohc_params->profile, + sizeof(comp_field_dst-> + rohc_params->profile)); + comp_field_dst->rohc_params->profile_len = + comp_field_src->rohc_params->profile_len; + } + + return 0; + } + + if ((comp_field_dst->v42bis_params) + && (comp_field_src->v42bis_params)) { + if (comp_field_dst->v42bis_params->p0 < 0) + comp_field_dst->v42bis_params->p0 = + comp_field_src->v42bis_params->p0; + if (comp_field_dst->v42bis_params->p1 < 0) + comp_field_dst->v42bis_params->p1 = + comp_field_src->v42bis_params->p1; + if (comp_field_dst->v42bis_params->p2 < 0) + comp_field_dst->v42bis_params->p2 = + comp_field_src->v42bis_params->p2; + return 0; + } + + if ((comp_field_dst->v44_params) + && (comp_field_src->v44_params)) { + if (comp_field_dst->v44_params->c0 < 0) + comp_field_dst->v44_params->c0 = + comp_field_src->v44_params->c0; + if (comp_field_dst->v44_params->p0 < 0) + comp_field_dst->v44_params->p0 = + comp_field_src->v44_params->p0; + if (comp_field_dst->v44_params->p1t < 0) + comp_field_dst->v44_params->p1t = + comp_field_src->v44_params->p1t; + if (comp_field_dst->v44_params->p1r < 0) + comp_field_dst->v44_params->p1r = + comp_field_src->v44_params->p1r; + if (comp_field_dst->v44_params->p3t < 0) + comp_field_dst->v44_params->p3t = + comp_field_src->v44_params->p3t; + if (comp_field_dst->v44_params->p3r < 0) + comp_field_dst->v44_params->p3r = + comp_field_src->v44_params->p3r; + return 0; + } + + /* + * There should be at least exist one param set + * in the destination struct, otherwise something + * must be wrong! + */ + return -EINVAL; +} + + +/* Complete missing parameters in a comp_field */ +static int gprs_sndcp_complete_comp_field(struct gprs_sndcp_comp_field + *comp_field, + const struct llist_head + *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field_src; + int rc = 0; + + if ((!comp_field) || (!comp_fields)) + return -EINVAL; + + llist_for_each_entry(comp_field_src, comp_fields, list) { + if (comp_field_src->entity == comp_field->entity) { + + /* Complete header fields */ + if (comp_field_src->comp_len > 0) { + memcpy(comp_field->comp, + comp_field_src->comp, + sizeof(comp_field_src->comp)); + comp_field->comp_len = + comp_field_src->comp_len; + } + + /* Complete parameter fields */ + rc = complete_comp_field_params(comp_field, + comp_field_src); + } + } + + return rc; +} + + +/* Complete missing parameters of all comp_field in a list */ +static int gprs_sndcp_complete_comp_fields(struct llist_head + *comp_fields_incomplete, + const struct llist_head + *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field_incomplete; + int rc; + + if ((!comp_fields_incomplete) || (!comp_fields)) + return -EINVAL; + + llist_for_each_entry(comp_field_incomplete, comp_fields_incomplete, + list) { + + rc = gprs_sndcp_complete_comp_field(comp_field_incomplete, + comp_fields); + if (rc < 0) + return -EINVAL; + + } + + return 0; +} + + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +int gprs_sndcp_parse_xid(struct llist_head *comp_fields, + const uint8_t * src, unsigned int src_len, + const struct llist_head *comp_fields_req) +{ + int rc; + int lt_len; + struct gprs_sndcp_hdrcomp_entity_algo_table lt[MAX_ENTITIES * 2]; + + if (comp_fields_req) { + /* Generate lookup table */ + lt_len = + gprs_sndcp_fill_table(lt, MAX_ENTITIES * 2, + comp_fields_req); + if (lt_len < 0) + return -EINVAL; + + /* Parse SNDCP-CID XID-Field */ + rc = gprs_sndcp_decode_xid(comp_fields, src, src_len, lt, + lt_len); + if (rc < 0) + return -EINVAL; + + rc = gprs_sndcp_complete_comp_fields(comp_fields, + comp_fields_req); + if (rc < 0) + return -EINVAL; + } else { + /* Parse SNDCP-CID XID-Field */ + rc = gprs_sndcp_decode_xid(comp_fields, src, src_len, NULL, + 0); + if (rc < 0) + return -EINVAL; + } + + return 0; +} + + +/* Free a list with SNDCP-XID fields */ +void gprs_sndcp_free_comp_fields(struct llist_head *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field; + struct llist_head *lh, *lh2; + + /* Exit immediately if no list is present */ + if (!comp_fields) + return; + + llist_for_each_entry(comp_field, comp_fields, list) { + if (comp_field->rfc1144_params) + talloc_free(comp_field->rfc1144_params); + if (comp_field->rfc2507_params) + talloc_free(comp_field->rfc2507_params); + if (comp_field->rohc_params) + talloc_free(comp_field->rohc_params); + if (comp_field->v42bis_params) + talloc_free(comp_field->v42bis_params); + if (comp_field->v44_params) + talloc_free(comp_field->v44_params); + } + + llist_for_each_safe(lh, lh2, comp_fields) { + llist_del(lh); + talloc_free(lh); + } +} + + +/* + * Helper for gprs_sndcp_dump_comp_fields(), + * dumps protocol compression parameters + */ +static void dump_pcomp_params(const struct gprs_sndcp_comp_field + *comp_field, unsigned int logl) +{ + int i; + switch (comp_field->algo) { + case RFC_1144: + LOGP(DSNDCP, LOGL_DEBUG, + " gprs_sndcp_hdrcomp_rfc1144_params {\n"); + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi_len=%i;\n", + comp_field->rfc1144_params->nsapi_len); + if (comp_field->rfc1144_params->nsapi_len == 0) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rfc1144_params->nsapi_len; i++) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[%i]=%i;\n", i, + comp_field->rfc1144_params->nsapi[i]); + LOGP(DSNDCP, logl, " s01=%i;\n", + comp_field->rfc1144_params->s01); + LOGP(DSNDCP, logl, " }\n"); + break; + case RFC_2507: + LOGP(DSNDCP, LOGL_DEBUG, + " gprs_sndcp_hdrcomp_rfc2507_params {\n"); + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi_len=%i;\n", + comp_field->rfc2507_params->nsapi_len); + if (comp_field->rfc2507_params->nsapi_len == 0) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rfc2507_params->nsapi_len; i++) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[%i]=%i;\n", i, + comp_field->rfc2507_params->nsapi[i]); + LOGP(DSNDCP, LOGL_DEBUG, + " f_max_period=%i;\n", + comp_field->rfc2507_params->f_max_period); + LOGP(DSNDCP, LOGL_DEBUG, + " f_max_time=%i;\n", + comp_field->rfc2507_params->f_max_time); + LOGP(DSNDCP, LOGL_DEBUG, + " max_header=%i;\n", + comp_field->rfc2507_params->max_header); + LOGP(DSNDCP, LOGL_DEBUG, + " tcp_space=%i;\n", + comp_field->rfc2507_params->tcp_space); + LOGP(DSNDCP, LOGL_DEBUG, + " non_tcp_space=%i;\n", + comp_field->rfc2507_params->non_tcp_space); + LOGP(DSNDCP, logl, " }\n"); + break; + case ROHC: + LOGP(DSNDCP, LOGL_DEBUG, + " gprs_sndcp_hdrcomp_rohc_params {\n"); + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi_len=%i;\n", + comp_field->rohc_params->nsapi_len); + if (comp_field->rohc_params->nsapi_len == 0) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rohc_params->nsapi_len; i++) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[%i]=%i;\n", i, + comp_field->rohc_params->nsapi[i]); + LOGP(DSNDCP, LOGL_DEBUG, + " max_cid=%i;\n", + comp_field->rohc_params->max_cid); + LOGP(DSNDCP, LOGL_DEBUG, + " max_header=%i;\n", + comp_field->rohc_params->max_header); + if (comp_field->rohc_params->profile_len == 0) + LOGP(DSNDCP, LOGL_DEBUG, + " profile[] = NULL;\n"); + for (i = 0; i < comp_field->rohc_params->profile_len; i++) + LOGP(DSNDCP, LOGL_DEBUG, + " profile[%i]=%04x;\n", + i, comp_field->rohc_params->profile[i]); + LOGP(DSNDCP, logl, " }\n"); + break; + } + + +} + + +/* + * Helper for gprs_sndcp_dump_comp_fields(), + * data protocol compression parameters + */ +static void dump_dcomp_params(const struct gprs_sndcp_comp_field + *comp_field, unsigned int logl) +{ + int i; + switch (comp_field->algo) { + case V42BIS: + LOGP(DSNDCP, LOGL_DEBUG, + " gprs_sndcp_datacomp_v42bis_params {\n"); + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi_len=%i;\n", + comp_field->v42bis_params->nsapi_len); + if (comp_field->v42bis_params->nsapi_len == 0) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->v42bis_params->nsapi_len; i++) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[%i]=%i;\n", i, + comp_field->v42bis_params->nsapi[i]); + LOGP(DSNDCP, logl, " p0=%i;\n", + comp_field->v42bis_params->p0); + LOGP(DSNDCP, logl, " p1=%i;\n", + comp_field->v42bis_params->p1); + LOGP(DSNDCP, logl, " p2=%i;\n", + comp_field->v42bis_params->p2); + LOGP(DSNDCP, logl, " }\n"); + break; + case V44: + LOGP(DSNDCP, LOGL_DEBUG, + " gprs_sndcp_datacomp_v44_params {\n"); + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi_len=%i;\n", + comp_field->v44_params->nsapi_len); + if (comp_field->v44_params->nsapi_len == 0) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->v44_params->nsapi_len; i++) + LOGP(DSNDCP, LOGL_DEBUG, + " nsapi[%i]=%i;\n", i, + comp_field->v44_params->nsapi[i]); + LOGP(DSNDCP, logl, " c0=%i;\n", + comp_field->v44_params->c0); + LOGP(DSNDCP, logl, " p0=%i;\n", + comp_field->v44_params->p0); + LOGP(DSNDCP, logl, " p1t=%i;\n", + comp_field->v44_params->p1t); + LOGP(DSNDCP, logl, " p1r=%i;\n", + comp_field->v44_params->p1r); + LOGP(DSNDCP, logl, " p3t=%i;\n", + comp_field->v44_params->p3t); + LOGP(DSNDCP, logl, " p3r=%i;\n", + comp_field->v44_params->p3r); + LOGP(DSNDCP, logl, " }\n"); + break; + } +} + + +/* Dump a list with SNDCP-XID fields (Debug) */ +void gprs_sndcp_dump_comp_fields(const struct llist_head *comp_fields, + unsigned int logl) +{ + struct gprs_sndcp_comp_field *comp_field; + int i; + int compclass; + + llist_for_each_entry(comp_field, comp_fields, list) { + LOGP(DSNDCP, logl, "SNDCP-XID:\n"); + LOGP(DSNDCP, LOGL_DEBUG, + "struct gprs_sndcp_comp_field {\n"); + LOGP(DSNDCP, logl, " entity=%i;\n", comp_field->entity); + LOGP(DSNDCP, logl, " algo=%i;\n", comp_field->algo); + LOGP(DSNDCP, logl, " comp_len=%i;\n", + comp_field->comp_len); + if (comp_field->comp_len == 0) + LOGP(DSNDCP, logl, " comp[] = NULL;\n"); + for (i = 0; i < comp_field->comp_len; i++) + LOGP(DSNDCP, logl, " comp[%i]=%i;\n", i, + comp_field->comp[i]); + + compclass = gprs_sndcp_get_compression_class(comp_field); + + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + dump_pcomp_params(comp_field, logl); + } else if (compclass == SNDCP_XID_DATA_COMPRESSION) { + dump_dcomp_params(comp_field, logl); + } + + LOGP(DSNDCP, logl, "}\n"); + LOGP(DSNDCP, logl, "\n"); + } + +} -- To view, visit https://gerrit.osmocom.org/641 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e Gerrit-PatchSet: 6 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte From gerrit-no-reply at lists.osmocom.org Fri Aug 5 11:28:08 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Fri, 5 Aug 2016 11:28:08 +0000 Subject: [PATCH] openbsc[master]: Adding code to control GPRS TCP/IP header compression. In-Reply-To: References: Message-ID: Hello Harald Welte, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/642 to look at the new patch set (#8). Adding code to control GPRS TCP/IP header compression. In this commit two modules were added: gprs_sndcp_comp_entity.h/c: This part handles the creation and destruction of conpression entites. It handles the allocation and freeing of the memory and offers functions to query compression parameters (i.e. which compression entity should be used if a packet from NSAPI x has to be compressed?) gprs_sndcp_hdrcomp.c/h: This is the code that performs the actual header compression. It takes care that the packets are compressed/decompressed with the right modes etc. It works, but is not yet ready for merging. Both files depend on each other so that they only can be merged both at the same time. Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 --- M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/gprs_llc.h A openbsc/include/openbsc/gprs_sndcp_comp_entity.h A openbsc/include/openbsc/gprs_sndcp_hdrcomp.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/gprs_sndcp_comp_entity.c A openbsc/src/gprs/gprs_sndcp_hdrcomp.c 7 files changed, 718 insertions(+), 15 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/42/642/8 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index b37103f..e159db5 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,8 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h gprs_sndcp_xid.h + gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h gprs_sndcp_xid.h \ + gprs_sndcp_comp_entity.h gprs_sndcp_hdrcomp.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h index 0e497a0..39d17f4 100644 --- a/openbsc/include/openbsc/gprs_llc.h +++ b/openbsc/include/openbsc/gprs_llc.h @@ -146,6 +146,16 @@ #define NUM_SAPIS 16 +/* Lists holding the compression entities */ +struct comp_ent { + /* + * In this two list_heads we will store the data and protocol + * compression entities, together with their compression states + */ + struct llist_head proto; + struct llist_head data; +}; + struct gprs_llc_llme { struct llist_head list; @@ -166,6 +176,12 @@ uint16_t nsei; struct gprs_llc_lle lle[NUM_SAPIS]; + /* Compression entities */ + struct comp_ent comp; + + /* Copy of the XID fields we sent */ + struct llist_head xid; + /* Internal management */ uint32_t age_timestamp; }; diff --git a/openbsc/include/openbsc/gprs_sndcp_comp_entity.h b/openbsc/include/openbsc/gprs_sndcp_comp_entity.h new file mode 100644 index 0000000..3e3ea44 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_comp_entity.h @@ -0,0 +1,91 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_SNDCP_COMP_ENTITY_H +#define _GPRS_SNDCP_COMP_ENTITY_H + +#include +#include +#include + +/* Header / Data compression entity */ +struct gprs_sndcp_comp_entity +{ + struct llist_head list; + + /* Serves as an ID in case we want to delete this entity later */ + int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + + /* Specifies to which NSAPIs the compression entity is assigned */ + int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + int nsapi[11]; /* Applicable NSAPIs (default 0) */ + + /* Assigned pcomp values */ + int comp_len; /* Number of contained PCOMP / DCOMP values */ + int comp[16]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */ + + /* Algorithm parameters */ + int algo; /* Algorithm type (see gprs_sndcp_xid.h) */ + int compclass; /* See gprs_sndcp_xid.h/c */ + void *state; /* Algorithm status and parameters */ +}; + +/* Free a list with compression entities */ +void gprs_sndcp_comp_entities_free (struct llist_head *comp_entities); + +/* Delete a compression entity */ +void gprs_sndcp_comp_entities_delete (struct llist_head *comp_entities, + int entity); + +/* Create and Add a new compression entity +(returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entities_add (struct llist_head *comp_entities, + const struct gprs_sndcp_comp_field *comp_field); + +/* Find compression entity by its entity number */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_entity (const struct llist_head*comp_entities, + int entity); + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_comp (const struct llist_head *comp_entities, + int comp); + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_nsapi (const struct llist_head *comp_entities, + int nsapi); + +/* Find a comp_index for a given pcomp/dcomp value */ +int +gprs_sndcp_comp_entity_find_comp_index_by_comp (const struct gprs_sndcp_comp_entity + *comp_entity, int comp); + +/* Find a pcomp/dcomp value for a given comp_index */ +int +gprs_sndcp_comp_entity_find_comp_by_comp_index (const struct gprs_sndcp_comp_entity + *comp_entity, + int comp_index); + +#endif diff --git a/openbsc/include/openbsc/gprs_sndcp_hdrcomp.h b/openbsc/include/openbsc/gprs_sndcp_hdrcomp.h new file mode 100644 index 0000000..ffad997 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_hdrcomp.h @@ -0,0 +1,68 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_SNDCP_HDRCOMP_H +#define _GPRS_SNDCP_HDRCOMP_H + +#include +#include +#include + +/* 1=Bypass any header compression, 0=Normal */ +#define GPRS_SNDCP_HDRCOMP_BYPASS 0 + +/* Header compression entity */ +struct gprs_sndcp_hdrcomp_compression_entity { + + /* Specifies to which NSAPIs the compression entity is assigned */ + int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + int nsapi[11]; /* Applicable NSAPIs (default 0) */ + + /* Assigned pcomp values */ + int pcomp_len; /* Number of contained PCOMP / DCOMP values */ + int pcomp[16]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */ + + /* Algorithm parameters */ + int compclass; /* 1=Header compression, 2=Data compression */ + int algo; /* Algorithm type (see gprs_sndcp_xid.h) */ + void *status; /* Algorithm status and parameters */ +}; + + +/* Initalize header compression */ +int gprs_sndcp_hdrcomp_init(struct gprs_sndcp_comp_entity *comp_entity, + const struct gprs_sndcp_comp_field *comp_field); + +/* Terminate header compression */ +void gprs_sndcp_hdrcomp_term(struct gprs_sndcp_comp_entity *comp_entity); + +/* Expand header compressed packet */ +int gprs_sndcp_hdrcomp_expand(uint8_t * packet, int packet_len, int pcomp, + const struct llist_head *comp_entities); + +/* Expand header compressed packet */ +int gprs_sndcp_hdrcomp_compress(uint8_t * packet, int packet_len, + int *pcomp, + const struct llist_head *comp_entities, + int nsapi); + +#endif diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 67e9943..3d6c82a 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -21,7 +21,8 @@ $(OSMO_LIBS) $(LIBCRYPTO_LIBS) -lrt osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \ - slhc.c gprs_sndcp_xid.c \ + slhc.c gprs_sndcp_xid.c gprs_sndcp_comp_entity.c \ + gprs_sndcp_hdrcomp.c \ sgsn_main.c sgsn_vty.c sgsn_libgtp.c \ gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c \ gprs_llc_xid.c crc24.c \ diff --git a/openbsc/src/gprs/gprs_sndcp_comp_entity.c b/openbsc/src/gprs/gprs_sndcp_comp_entity.c index 095a32a..baaa8f9 100644 --- a/openbsc/src/gprs/gprs_sndcp_comp_entity.c +++ b/openbsc/src/gprs/gprs_sndcp_comp_entity.c @@ -36,7 +36,7 @@ /* Create a new compression entity from a XID-Field */ static struct gprs_sndcp_comp_entity * -gprs_sndcp_comp_entity_create (struct gprs_sndcp_comp_field *comp_field) +gprs_sndcp_comp_entity_create (const struct gprs_sndcp_comp_field *comp_field) { struct gprs_sndcp_comp_entity *comp_entity; comp_entity = talloc_zero (NULL, struct gprs_sndcp_comp_entity); @@ -118,26 +118,29 @@ void gprs_sndcp_comp_entities_free (struct llist_head *comp_entities) { - if (comp_entities) { - struct gprs_sndcp_comp_entity *comp_entity; + struct llist_head *lh, *lh2; + struct gprs_sndcp_comp_entity *comp_entity; + if (comp_entities) { llist_for_each_entry (comp_entity, comp_entities, list) { /* Free compression entity */ if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { LOGP (DSNDCP, LOGL_INFO, - "Deleting (free) header compression entity %i ...\n", + "Deleting header compression entity %i ...\n", comp_entity->entity); gprs_sndcp_hdrcomp_term (comp_entity); } else LOGP (DSNDCP, LOGL_INFO, - "Deleting (free) data compression entity %i ...\n", + "Deleting data compression entity %i ...\n", comp_entity->entity); - - talloc_free (comp_entity); } + llist_for_each_safe(lh, lh2, comp_entities) { + llist_del(lh); + talloc_free(lh); + } } } @@ -181,7 +184,7 @@ struct gprs_sndcp_comp_entity * gprs_sndcp_comp_entities_add (struct llist_head - *comp_entities, struct + *comp_entities, const struct gprs_sndcp_comp_field *comp_field) { struct gprs_sndcp_comp_entity *comp_entity; @@ -203,7 +206,7 @@ /* Find compression entity by its entity number */ struct gprs_sndcp_comp_entity * -gprs_sndcp_comp_entity_find_by_entity (struct +gprs_sndcp_comp_entity_find_by_entity (const struct llist_head *comp_entities, int entity) { struct gprs_sndcp_comp_entity *comp_entity; @@ -223,7 +226,7 @@ /* Find which compression entity handles the specified pcomp/dcomp */ struct gprs_sndcp_comp_entity * -gprs_sndcp_comp_entity_find_by_comp (struct +gprs_sndcp_comp_entity_find_by_comp (const struct llist_head *comp_entities, int comp) { struct gprs_sndcp_comp_entity *comp_entity; @@ -246,7 +249,7 @@ /* Find which compression entity handles the specified nsapi */ struct gprs_sndcp_comp_entity * -gprs_sndcp_comp_entity_find_by_nsapi (struct +gprs_sndcp_comp_entity_find_by_nsapi (const struct llist_head *comp_entities, int nsapi) { struct gprs_sndcp_comp_entity *comp_entity; @@ -273,7 +276,7 @@ /* Find a comp_index for a given pcomp/dcomp value */ int -gprs_sndcp_comp_entity_find_comp_index_by_comp (struct +gprs_sndcp_comp_entity_find_comp_index_by_comp (const struct gprs_sndcp_comp_entity *comp_entity, int comp) { @@ -305,7 +308,7 @@ /* Find a pcomp/dcomp value for a given comp_index */ int -gprs_sndcp_comp_entity_find_comp_by_comp_index (struct +gprs_sndcp_comp_entity_find_comp_by_comp_index (const struct gprs_sndcp_comp_entity *comp_entity, int comp_index) { diff --git a/openbsc/src/gprs/gprs_sndcp_hdrcomp.c b/openbsc/src/gprs/gprs_sndcp_hdrcomp.c new file mode 100644 index 0000000..94b9f12 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_hdrcomp.c @@ -0,0 +1,523 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* Enable private debug messages */ +#define GPRS_SNDCP_HDRCOMP_DEBUG 1 + +/* Test RFC1144 implementation + (Caution: GPRS_SNDCP_HDRCOMP_BYPASS in .h file has to be set to 1!) */ +#define GPRS_SNDCP_HDRCOMP_RFC1144_TEST 0 + +/* Exit immediately in case of RFC1144 test failure */ +#define GPRS_SNDCP_HDRCOMP_RFC1144_TEST_EXITONERR 1 + +/* For debug/test only! */ +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST == 1 +static struct slcompress *test_compression_state_tx = NULL; +static struct slcompress *test_compression_state_rx = NULL; +static int test_errors = 0; +static int gprs_sndcp_hdrcomp_test_ind(uint8_t * packet, int packet_len); +static int gprs_sndcp_hdrcomp_test_req(uint8_t * packet, int packet_len); +#endif + + +/* Initalize header compression */ +int gprs_sndcp_hdrcomp_init(struct gprs_sndcp_comp_entity *comp_entity, + const struct gprs_sndcp_comp_field *comp_field) +{ + /* Note: This function is automatically called from + gprs_sndcp_comp_entity.c when a new header compression + entity is created by gprs_sndcp.c */ + + if ((comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + && (comp_entity->algo == RFC_1144)) { + comp_entity->state = + slhc_init(comp_field->rfc1144_params->s01 + 1, + comp_field->rfc1144_params->s01 + 1); + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression initalized.\n"); + return 0; + } + + /* Just in case someone tries to initalize an unknown or unsupported + header compresson. Since everything is checked during the SNDCP + negotiation process, this should never happen! */ + LOGP(DSNDCP, LOGL_ERROR, + "Unknown or unsupported header compression type requested for initalization, could not initalize...\n"); + return -EINVAL; + +} + + +/* Terminate header compression */ +void gprs_sndcp_hdrcomp_term(struct gprs_sndcp_comp_entity *comp_entity) +{ + /* Note: This function is automatically called from + gprs_sndcp_comp_entity.c when a header compression + entity is deleted by gprs_sndcp.c */ + + if ((comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + && (comp_entity->algo == RFC_1144)) { + if (comp_entity->state) { + slhc_free((struct slcompress *) comp_entity-> + state); + comp_entity->state = NULL; + } + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression terminated.\n"); + return; + } + + /* Just in case someone tries to initalize an unknown or unsupported + header compresson. Since everything is checked during the SNDCP + negotiation process, this should never happen! */ + LOGP(DSNDCP, LOGL_ERROR, + "Unknown or unsupported header compression type requested for termiation, could not initalize...\n"); +} + + +/* Display compressor status */ +static void gprs_sndcp_hdrcomp_rfc1144_stat(struct slcompress *comp) +{ + slhc_i_status(comp); + slhc_o_status(comp); +} + + +/* Compress a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_hdrcomp_rfc1144_compress(struct slcompress *comp, + uint8_t * packet, + int packet_len, + int *pcomp_index) +{ + uint8_t *packet_compressed; + uint8_t *packet_compressed_ptr; /* Not used */ + int packet_compressed_len; + + /* Reserve some space for to store the compression result */ + packet_compressed = talloc_zero_size(NULL, packet_len); + + /* Run compressor */ + memcpy(packet_compressed, packet, packet_len); + packet_compressed_len = + slhc_compress(comp, packet, packet_len, + (uint8_t *) packet_compressed, + &packet_compressed_ptr, 0); + + /* Copy back compression result */ + memcpy(packet, packet_compressed, packet_len); + talloc_free(packet_compressed); + + /* Generate pcomp_index */ + if ((packet[0] & SL_TYPE_COMPRESSED_TCP) == SL_TYPE_COMPRESSED_TCP) { + *pcomp_index = 2; + /* Remove tag for compressed TCP, because the packet + type is already define by pcomp */ + // packet[0] &= 0x7F; + } else if ((packet[0] & SL_TYPE_UNCOMPRESSED_TCP) == + SL_TYPE_UNCOMPRESSED_TCP) { + *pcomp_index = 1; + + /* Remove tag for uncompressed TCP, because the + packet type is already define by pcomp */ + packet[0] &= 0x4F; + } else + *pcomp_index = 0; + + return packet_compressed_len; +} + +/* Expand a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_hdrcomp_rfc1144_expand(struct slcompress *comp, + uint8_t * packet, + int packet_len, + int pcomp_index) +{ + int packet_decompressed_len; + int type = -1; + + /* Note: this function should never be called with pcomp_index=0, + since this condition is already filtered + out by gprs_sndcp_hdrcomp_expand() */ + + /* Determine the packet type by the PCOMP index */ + switch (pcomp_index) { + case 1: + type = SL_TYPE_UNCOMPRESSED_TCP; + break; + case 2: + type = SL_TYPE_COMPRESSED_TCP; + break; + } + + /* Restore the original version nibble on + marked uncompressed packets */ + if (type == SL_TYPE_UNCOMPRESSED_TCP) { + LOGP(DSNDCP, LOGL_INFO, + "Uncompressed rfc1144 packet received...\n"); + + + /* Just in case the phone tags uncompressed tcp-packets + (normally this is handled by pcomp so there is + no need for tagging the packets) */ + packet[0] &= 0x4F; + packet_decompressed_len = + slhc_remember(comp, packet, packet_len); + return packet_decompressed_len; + } + + /* Uncompress compressed packets */ + else if (type == SL_TYPE_COMPRESSED_TCP) { + LOGP(DSNDCP, LOGL_INFO, + "Compressed rfc1144 packet received...\n"); + packet_decompressed_len = + slhc_uncompress(comp, packet, packet_len); + return packet_decompressed_len; + } + + + /* Regular or unknown packets will not be touched */ + return packet_len; +} + + +/* Expand header compressed packet */ +int gprs_sndcp_hdrcomp_expand(uint8_t * packet, int packet_len, int pcomp, + const struct llist_head *comp_entities) +{ + int rc; + int pcomp_index = 0; + struct gprs_sndcp_comp_entity *comp_entity; + + /* Skip on pcomp=0 */ + if (pcomp == 0) { + LOGP(DSNDCP, LOGL_INFO, + "Uncompressed packet received (pcomp=0), skipping compression...\n"); + return packet_len; + } + + /* Find out which compression entity handles the packet */ + comp_entity = + gprs_sndcp_comp_entity_find_by_comp(comp_entities, pcomp); + + /* Skip compression if no suitable compression entity can be found! */ + if (comp_entity == NULL) { + LOGP(DSNDCP, LOGL_ERROR, + "Compressed packet received (pcomp=%i) but no suitable compression entity found, skipping compression...\n", + pcomp); + return packet_len; + } + + /* Find pcomp_index */ + pcomp_index = + gprs_sndcp_comp_entity_find_comp_index_by_comp(comp_entity, + pcomp); + +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST == 1 + /* Test mode */ + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_expand(): testing compression...!\n"); + rc = gprs_sndcp_hdrcomp_test_ind(packet, packet_len); +#else + /* Normal operation: */ + rc = gprs_sndcp_hdrcomp_rfc1144_expand((struct slcompress *) + comp_entity->state, packet, + packet_len, pcomp_index); + gprs_sndcp_hdrcomp_rfc1144_stat((struct slcompress *) comp_entity-> + state); +#endif + + LOGP(DSNDCP, LOGL_DEBUG, + "Header expansion done, old length=%i, new length=%i, pcomp=%i, pcomp_index=%i\n", + packet_len, rc, pcomp, pcomp_index); + return rc; +} + + +/* Expand header compressed packet */ +int gprs_sndcp_hdrcomp_compress(uint8_t * packet, int packet_len, + int *pcomp, + const struct llist_head *comp_entities, + int nsapi) +{ + int rc; + int pcomp_index = 0; + struct gprs_sndcp_comp_entity *comp_entity; + + /* Find out which compression entity handles the packet */ + comp_entity = + gprs_sndcp_comp_entity_find_by_nsapi(comp_entities, nsapi); + + /* Skip compression if no suitable compression entity can be found! */ + if (comp_entity == NULL) { + LOGP(DSNDCP, LOGL_INFO, + "No suitable compression entity found for nsapi %i, skipping compression...\n", + nsapi); + *pcomp = 0; + return packet_len; + } +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST == 1 + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_expand(): testing compression...!\n"); + rc = gprs_sndcp_hdrcomp_test_req(packet, packet_len); + *pcomp = 0; + return rc; +#else + /* Normal operation: */ + rc = gprs_sndcp_hdrcomp_rfc1144_compress((struct slcompress *) + comp_entity->state, + packet, packet_len, + &pcomp_index); + gprs_sndcp_hdrcomp_rfc1144_stat((struct slcompress *) comp_entity-> + state); +#endif + + /* Find pcomp value */ + *pcomp = + gprs_sndcp_comp_entity_find_comp_by_comp_index(comp_entity, + pcomp_index); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header compression done, old length=%i, new length=%i, pcomp=%i, pcomp_index=%i\n", + packet_len, rc, *pcomp, pcomp_index); + return rc; +} + + + + + + + +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST == 1 + +/* + * This is a test implementation to make sure the rfc1144 compression + * implementation works as expected. All data is first compressed and + * decompressed on both directions. + */ + +/* FIXME: FOR EXPERIMENTATION ONLY! REMOVE AS SOON AS POSSIBLE */ +static uint16_t header_checksum(uint8_t * iph, unsigned int ihl) +{ + int i; + uint16_t temp; + uint32_t accumulator = 0xFFFF; + + for (i = 0; i < ihl * 2; i++) { + temp = ((*iph) << 8) & 0xFF00; + iph++; + temp |= (*iph) & 0xFF; + iph++; + + accumulator += temp; + if (accumulator > 0xFFFF) { + accumulator++; + accumulator &= 0xFFFF; + } + } + + return (uint16_t) (htons(~accumulator) & 0xFFFF); +} + +/* Check packet integrity */ +static int gprs_sndcp_hdrcomp_test_check_packet(uint8_t * packet, + uint8_t * packet_backup, + int packet_len, + int + packet_len_uncompressed) +{ + uint16_t checksum; + + if (packet_len != packet_len_uncompressed) { + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): Error: Packet length mismatch!\n"); +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST_EXITONERR == 1 + exit(1); +#endif + return -1; + } + + /* Check packet integrety */ + if (memcmp(packet, packet_backup, packet_len)) { + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): Warning: Packet content!\n"); + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): %s\n", + osmo_hexdump_nospc(packet_backup, 80)); + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): %s\n", + osmo_hexdump_nospc(packet, 80)); + + checksum = header_checksum(packet, 5); + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): %04x\n", + checksum); + + if (checksum == 0x0000) { + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): Checksum looks good!\n"); + + if (memcmp + (packet + 20, packet_backup + 20, + packet_len - 20)) + test_errors++; + else + LOGP(DSNDCP, LOGL_INFO, + "prs_sndcp_hdrcomp_test_check_packet(): Packet looks also good!\n"); + } else { + test_errors++; +#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST_EXITONERR == 1 + exit(1); +#endif + return -1; + } + } + + return 0; +} + +/* FIXME: FOR EXPERIMENTATION ONLY! REMOVE AS SOON AS POSSIBLE */ +static int gprs_sndcp_hdrcomp_test_ind(uint8_t * packet, int packet_len) +{ + int packet_len_compressed; + int packet_len_uncompressed; + int pcomp; + uint8_t *packet_backup; + + if (test_compression_state_tx == NULL) + test_compression_state_tx = slhc_init(8, 8); + if (test_compression_state_rx == NULL) + test_compression_state_rx = slhc_init(8, 8); + + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): packet_len=%i\n", packet_len); + packet_backup = talloc_zero_size(NULL, packet_len); + memcpy(packet_backup, packet, packet_len); + + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): IND: %s\n", + osmo_hexdump_nospc(packet, packet_len)); + packet_len_compressed = + gprs_sndcp_hdrcomp_rfc1144_compress(test_compression_state_rx, + packet, packet_len, + &pcomp); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): IND (COMP): %s\n", + osmo_hexdump_nospc(packet, packet_len_compressed)); + packet_len_uncompressed = + gprs_sndcp_hdrcomp_rfc1144_expand(test_compression_state_tx, + packet, + packet_len_compressed, + pcomp); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): IND (DECOMP): %s\n", + osmo_hexdump_nospc(packet, packet_len_uncompressed)); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): packet_len=%i packet_len_compressed=%i packet_len_uncompressed=%i\n", + packet_len, packet_len_compressed, packet_len_uncompressed); + + gprs_sndcp_hdrcomp_test_check_packet(packet, packet_backup, + packet_len, + packet_len_uncompressed); + talloc_free(packet_backup); + gprs_sndcp_hdrcomp_rfc1144_stat(test_compression_state_rx); + gprs_sndcp_hdrcomp_rfc1144_stat(test_compression_state_tx); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): Test errors: %i\n", + test_errors); + return packet_len; +} + +/* FIXME: FOR EXPERIMENTATION ONLY! REMOVE AS SOON AS POSSIBLE */ +static int gprs_sndcp_hdrcomp_test_req(uint8_t * packet, int packet_len) +{ + int packet_len_compressed; + int packet_len_uncompressed; + int pcomp; + uint8_t *packet_backup; + + if (test_compression_state_tx == NULL) + test_compression_state_tx = slhc_init(8, 8); + if (test_compression_state_rx == NULL) + test_compression_state_rx = slhc_init(8, 8); + + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_req(): packet_len=%i\n", packet_len); + packet_backup = talloc_zero_size(NULL, packet_len); + memcpy(packet_backup, packet, packet_len); + + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_req(): REQ: %s\n", + osmo_hexdump_nospc(packet, packet_len)); + packet_len_compressed = + gprs_sndcp_hdrcomp_rfc1144_compress(test_compression_state_tx, + packet, packet_len, + &pcomp); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_req(): REQ (COMP): %s\n", + osmo_hexdump_nospc(packet, packet_len_compressed)); + packet_len_uncompressed = + gprs_sndcp_hdrcomp_rfc1144_expand(test_compression_state_rx, + packet, + packet_len_compressed, + pcomp); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_req(): REQ (DECOMP): %s\n", + osmo_hexdump_nospc(packet, packet_len_uncompressed)); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_req(): packet_len=%i packet_len_compressed=%i packet_len_uncompressed=%i\n", + packet_len, packet_len_compressed, packet_len_uncompressed); + + gprs_sndcp_hdrcomp_test_check_packet(packet, packet_backup, + packet_len, + packet_len_uncompressed); + talloc_free(packet_backup); + gprs_sndcp_hdrcomp_rfc1144_stat(test_compression_state_rx); + gprs_sndcp_hdrcomp_rfc1144_stat(test_compression_state_tx); + LOGP(DSNDCP, LOGL_INFO, + "gprs_sndcp_hdrcomp_test_ind(): Test errors: %i\n", + test_errors); + return packet_len; +} + +#endif -- To view, visit https://gerrit.osmocom.org/642 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 Gerrit-PatchSet: 8 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte From gerrit-no-reply at lists.osmocom.org Fri Aug 5 11:28:08 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Fri, 5 Aug 2016 11:28:08 +0000 Subject: [PATCH] openbsc[master]: Adding V42BIS implementation In-Reply-To: References: Message-ID: Hello Harald Welte, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/643 to look at the new patch set (#9). Adding V42BIS implementation V42BIS is a data compression method found in modems. It has also been specified for GPRS as data compression algorithm. The implementation has been taken from SPANDSP. There are several sources around. Asterisk and Freeswitch are using SPANDSP and its also available separately. The implementation in this commit has been taken from: https://github.com/jart/spandsp.git commit 6de1983b251806d59bb3149b7a2d7ebc99ace5aa Change-Id: Iabedece9f97ca944a1e3f747bb073e532c4e9dca --- A openbsc/include/openbsc/private_v42bis.h A openbsc/include/openbsc/v42bis.h A openbsc/src/gprs/v42bis.c 3 files changed, 1,036 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/43/643/9 diff --git a/openbsc/include/openbsc/private_v42bis.h b/openbsc/include/openbsc/private_v42bis.h new file mode 100644 index 0000000..96538f2 --- /dev/null +++ b/openbsc/include/openbsc/private_v42bis.h @@ -0,0 +1,151 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * private/v42bis.h + * + * Written by Steve Underwood + * + * Copyright (C) 2005 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: v42bis.h,v 1.1 2008/11/15 14:43:08 steveu Exp $ + */ + +#if !defined(_SPANDSP_PRIVATE_V42BIS_H_) +#define _SPANDSP_PRIVATE_V42BIS_H_ + +/*! + V.42bis dictionary node. +*/ +typedef struct +{ + /*! \brief The prior code for each defined code. */ + uint16_t parent_code; + /*! \brief The number of leaf nodes this node has */ + int16_t leaves; + /*! \brief This leaf octet for each defined code. */ + uint8_t node_octet; + /*! \brief Bit map of the children which exist */ + uint32_t children[8]; +} v42bis_dict_node_t; + +/*! + V.42bis compression. This defines the working state for a single instance + of V.42bis compression. +*/ +typedef struct +{ + /*! \brief Compression mode. */ + int compression_mode; + /*! \brief Callback function to handle received frames. */ + v42bis_frame_handler_t handler; + /*! \brief An opaque pointer passed in calls to frame_handler. */ + void *user_data; + /*! \brief The maximum frame length allowed */ + int max_len; + + uint32_t string_code; + uint32_t latest_code; + int string_length; + uint32_t output_bit_buffer; + int output_bit_count; + int output_octet_count; + uint8_t output_buf[1024]; + v42bis_dict_node_t dict[V42BIS_MAX_CODEWORDS]; + /*! \brief TRUE if we are in transparent (i.e. uncompressable) mode */ + int transparent; + int change_transparency; + /*! \brief IIR filter state, used in assessing compressibility. */ + int compressibility_filter; + int compressibility_persistence; + + /*! \brief Next empty dictionary entry */ + uint32_t v42bis_parm_c1; + /*! \brief Current codeword size */ + int v42bis_parm_c2; + /*! \brief Threshold for codeword size change */ + uint32_t v42bis_parm_c3; + + /*! \brief Mark that this is the first octet/code to be processed */ + int first; + uint8_t escape_code; +} v42bis_compress_state_t; + +/*! + V.42bis decompression. This defines the working state for a single instance + of V.42bis decompression. +*/ +typedef struct +{ + /*! \brief Callback function to handle decompressed data. */ + v42bis_data_handler_t handler; + /*! \brief An opaque pointer passed in calls to data_handler. */ + void *user_data; + /*! \brief The maximum decompressed data block length allowed */ + int max_len; + + uint32_t old_code; + uint32_t last_old_code; + uint32_t input_bit_buffer; + int input_bit_count; + int octet; + int last_length; + int output_octet_count; + uint8_t output_buf[1024]; + v42bis_dict_node_t dict[V42BIS_MAX_CODEWORDS]; + /*! \brief TRUE if we are in transparent (i.e. uncompressable) mode */ + int transparent; + + int last_extra_octet; + + /*! \brief Next empty dictionary entry */ + uint32_t v42bis_parm_c1; + /*! \brief Current codeword size */ + int v42bis_parm_c2; + /*! \brief Threshold for codeword size change */ + uint32_t v42bis_parm_c3; + + /*! \brief Mark that this is the first octet/code to be processed */ + int first; + uint8_t escape_code; + int escaped; +} v42bis_decompress_state_t; + +/*! + V.42bis compression/decompression descriptor. This defines the working state for a + single instance of V.42bis compress/decompression. +*/ +struct v42bis_state_s +{ + /*! \brief V.42bis data compression directions. */ + int v42bis_parm_p0; + + /*! \brief Compression state. */ + v42bis_compress_state_t compress; + /*! \brief Decompression state. */ + v42bis_decompress_state_t decompress; + + /*! \brief Maximum codeword size (bits) */ + int v42bis_parm_n1; + /*! \brief Total number of codewords */ + uint32_t v42bis_parm_n2; + /*! \brief Maximum string length */ + int v42bis_parm_n7; +}; + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/openbsc/include/openbsc/v42bis.h b/openbsc/include/openbsc/v42bis.h new file mode 100644 index 0000000..f13e5c5 --- /dev/null +++ b/openbsc/include/openbsc/v42bis.h @@ -0,0 +1,143 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * v42bis.h + * + * Written by Steve Underwood + * + * Copyright (C) 2005 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: v42bis.h,v 1.27 2009/04/11 18:11:19 steveu Exp $ + */ + +/*! \page v42bis_page V.42bis modem data compression +\section v42bis_page_sec_1 What does it do? +The v.42bis specification defines a data compression scheme, to work in +conjunction with the error correction scheme defined in V.42. + +\section v42bis_page_sec_2 How does it work? +*/ + +#if !defined(_SPANDSP_V42BIS_H_) +#define _SPANDSP_V42BIS_H_ + +#define V42BIS_MAX_BITS 12 +#define V42BIS_MAX_CODEWORDS 4096 /* 2^V42BIS_MAX_BITS */ +#define V42BIS_TABLE_SIZE 5021 /* This should be a prime >(2^V42BIS_MAX_BITS) */ +#define V42BIS_MAX_STRING_SIZE 250 + +enum +{ + V42BIS_P0_NEITHER_DIRECTION = 0, + V42BIS_P0_INITIATOR_RESPONDER, + V42BIS_P0_RESPONDER_INITIATOR, + V42BIS_P0_BOTH_DIRECTIONS +}; + +enum +{ + V42BIS_COMPRESSION_MODE_DYNAMIC = 0, + V42BIS_COMPRESSION_MODE_ALWAYS, + V42BIS_COMPRESSION_MODE_NEVER +}; + +typedef void (*v42bis_frame_handler_t)(void *user_data, const uint8_t *pkt, int len); +typedef void (*v42bis_data_handler_t)(void *user_data, const uint8_t *buf, int len); + +/*! + V.42bis compression/decompression descriptor. This defines the working state for a + single instance of V.42bis compress/decompression. +*/ +typedef struct v42bis_state_s v42bis_state_t; + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/*! Compress a block of octets. + \param s The V.42bis context. + \param buf The data to be compressed. + \param len The length of the data buffer. + \return 0 */ +SPAN_DECLARE(int) v42bis_compress(v42bis_state_t *s, const uint8_t *buf, int len); + +/*! Flush out any data remaining in a compression buffer. + \param s The V.42bis context. + \return 0 */ +SPAN_DECLARE(int) v42bis_compress_flush(v42bis_state_t *s); + +/*! Decompress a block of octets. + \param s The V.42bis context. + \param buf The data to be decompressed. + \param len The length of the data buffer. + \return 0 */ +SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *s, const uint8_t *buf, int len); + +/*! Flush out any data remaining in the decompression buffer. + \param s The V.42bis context. + \return 0 */ +SPAN_DECLARE(int) v42bis_decompress_flush(v42bis_state_t *s); + +/*! Set the compression mode. + \param s The V.42bis context. + \param mode One of the V.42bis compression modes - + V42BIS_COMPRESSION_MODE_DYNAMIC, + V42BIS_COMPRESSION_MODE_ALWAYS, + V42BIS_COMPRESSION_MODE_NEVER */ +SPAN_DECLARE(void) v42bis_compression_control(v42bis_state_t *s, int mode); + +/*! Initialise a V.42bis context. + \param s The V.42bis context. + \param negotiated_p0 The negotiated P0 parameter, from the V.42bis spec. + \param negotiated_p1 The negotiated P1 parameter, from the V.42bis spec. + \param negotiated_p2 The negotiated P2 parameter, from the V.42bis spec. + \param frame_handler Frame callback handler. + \param frame_user_data An opaque pointer passed to the frame callback handler. + \param max_frame_len The maximum length that should be passed to the frame handler. + \param data_handler data callback handler. + \param data_user_data An opaque pointer passed to the data callback handler. + \param max_data_len The maximum length that should be passed to the data handler. + \return The V.42bis context. */ +SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, + int negotiated_p0, + int negotiated_p1, + int negotiated_p2, + v42bis_frame_handler_t frame_handler, + void *frame_user_data, + int max_frame_len, + v42bis_data_handler_t data_handler, + void *data_user_data, + int max_data_len); + +/*! Release a V.42bis context. + \param s The V.42bis context. + \return 0 if OK */ +SPAN_DECLARE(int) v42bis_release(v42bis_state_t *s); + +/*! Free a V.42bis context. + \param s The V.42bis context. + \return 0 if OK */ +SPAN_DECLARE(int) v42bis_free(v42bis_state_t *s); + +#if defined(__cplusplus) +} +#endif + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/openbsc/src/gprs/v42bis.c b/openbsc/src/gprs/v42bis.c new file mode 100644 index 0000000..6d38916 --- /dev/null +++ b/openbsc/src/gprs/v42bis.c @@ -0,0 +1,742 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * v42bis.c + * + * Written by Steve Underwood + * + * Copyright (C) 2005 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: v42bis.c,v 1.37 2009/02/10 13:06:47 steveu Exp $ + */ + +/* THIS IS A WORK IN PROGRESS. IT IS NOT FINISHED. + Currently it performs the core compression and decompression functions OK. + However, a number of the bells and whistles in V.42bis are incomplete. */ + +/*! \file */ + +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "spandsp/telephony.h" +#include "spandsp/logging.h" +#include "spandsp/bit_operations.h" +#include "spandsp/v42bis.h" + +#include "spandsp/private/logging.h" +#include "spandsp/private/v42bis.h" + +/* Fixed parameters from the spec. */ +#define V42BIS_N3 8 /* Character size (bits) */ +#define V42BIS_N4 256 /* Number of characters in the alphabet */ +#define V42BIS_N5 (V42BIS_N4 + V42BIS_N6) /* Index number of first dictionary entry used to store a string */ +#define V42BIS_N6 3 /* Number of control codewords */ + +/* Control code words in compressed mode */ +enum +{ + V42BIS_ETM = 0, /* Enter transparent mode */ + V42BIS_FLUSH = 1, /* Flush data */ + V42BIS_STEPUP = 2 /* Step up codeword size */ +}; + +/* Command codes in transparent mode */ +enum +{ + V42BIS_ECM = 0, /* Enter compression mode */ + V42BIS_EID = 1, /* Escape character in data */ + V42BIS_RESET = 2 /* Force reinitialisation */ +}; + +/*! \brief Find the bit position of the highest set bit in a word + \param bits The word to be searched + \return The bit number of the highest set bit, or -1 if the word is zero. */ +static __inline__ int top_bit(unsigned int bits) +{ +/* Note: This function was taken from spandsp/bit_operations.h */ + int res; + + if (bits == 0) + return -1; + res = 0; + if (bits & 0xFFFF0000) + { + bits &= 0xFFFF0000; + res += 16; + } + if (bits & 0xFF00FF00) + { + bits &= 0xFF00FF00; + res += 8; + } + if (bits & 0xF0F0F0F0) + { + bits &= 0xF0F0F0F0; + res += 4; + } + if (bits & 0xCCCCCCCC) + { + bits &= 0xCCCCCCCC; + res += 2; + } + if (bits & 0xAAAAAAAA) + { + bits &= 0xAAAAAAAA; + res += 1; + } + return res; +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ void push_compressed_raw_octet(v42bis_compress_state_t *ss, int octet) +{ + ss->output_buf[ss->output_octet_count++] = (uint8_t) octet; + if (ss->output_octet_count >= ss->max_len) + { + ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); + ss->output_octet_count = 0; + } +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ void push_compressed_code(v42bis_compress_state_t *ss, int code) +{ + ss->output_bit_buffer |= code << (32 - ss->v42bis_parm_c2 - ss->output_bit_count); + ss->output_bit_count += ss->v42bis_parm_c2; + while (ss->output_bit_count >= 8) + { + push_compressed_raw_octet(ss, ss->output_bit_buffer >> 24); + ss->output_bit_buffer <<= 8; + ss->output_bit_count -= 8; + } +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ void push_compressed_octet(v42bis_compress_state_t *ss, int code) +{ + ss->output_bit_buffer |= code << (32 - 8 - ss->output_bit_count); + ss->output_bit_count += 8; + while (ss->output_bit_count >= 8) + { + push_compressed_raw_octet(ss, ss->output_bit_buffer >> 24); + ss->output_bit_buffer <<= 8; + ss->output_bit_count -= 8; + } +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v42bis_compress(v42bis_state_t *s, const uint8_t *buf, int len) +{ + int ptr; + int i; + uint32_t octet; + uint32_t code; + v42bis_compress_state_t *ss; + + ss = &s->compress; + if ((s->v42bis_parm_p0 & 2) == 0) + { + /* Compression is off - just push the incoming data out */ + for (i = 0; i < len - ss->max_len; i += ss->max_len) + ss->handler(ss->user_data, buf + i, ss->max_len); + if (i < len) + ss->handler(ss->user_data, buf + i, len - i); + return 0; + } + ptr = 0; + if (ss->first && len > 0) + { + octet = buf[ptr++]; + ss->string_code = octet + V42BIS_N6; + if (ss->transparent) + push_compressed_octet(ss, octet); + ss->first = FALSE; + } + while (ptr < len) + { + octet = buf[ptr++]; + if ((ss->dict[ss->string_code].children[octet >> 5] & (1 << (octet & 0x1F)))) + { + /* The leaf exists. Now find it in the table. */ + /* TODO: This is a brute force scan for a match. We need something better. */ + for (code = 0; code < ss->v42bis_parm_c3; code++) + { + if (ss->dict[code].parent_code == ss->string_code && ss->dict[code].node_octet == octet) + break; + } + } + else + { + /* The leaf does not exist. */ + code = s->v42bis_parm_n2; + } + /* 6.3(b) If the string matches a dictionary entry, and the entry is not that entry + created by the last invocation of the string matching procedure, then the + next character shall be read and appended to the string and this step + repeated. */ + if (code < ss->v42bis_parm_c3 && code != ss->latest_code) + { + /* The string was found */ + ss->string_code = code; + ss->string_length++; + } + else + { + /* The string is not in the table. */ + if (!ss->transparent) + { + /* 7.4 Encoding - we now have the longest matchable string, and will need to output the code for it. */ + while (ss->v42bis_parm_c1 >= ss->v42bis_parm_c3 && ss->v42bis_parm_c3 <= s->v42bis_parm_n2) + { + /* We need to increase the codeword size */ + /* 7.4(a) */ + push_compressed_code(ss, V42BIS_STEPUP); + /* 7.4(b) */ + ss->v42bis_parm_c2++; + /* 7.4(c) */ + ss->v42bis_parm_c3 <<= 1; + /* 7.4(d) this might need to be repeated, so we loop */ + } + /* 7.5 Transfer - output the last state of the string */ + push_compressed_code(ss, ss->string_code); + } + /* 7.6 Dictionary updating */ + /* 6.4 Add the string to the dictionary */ + /* 6.4(b) The string is not in the table. */ + if (code != ss->latest_code && ss->string_length < s->v42bis_parm_n7) + { + ss->latest_code = ss->v42bis_parm_c1; + /* 6.4(a) The length of the string is in range for adding to the dictionary */ + /* If the last code was a leaf, it no longer is */ + ss->dict[ss->string_code].leaves++; + ss->dict[ss->string_code].children[octet >> 5] |= (1 << (octet & 0x1F)); + /* The new one is definitely a leaf */ + ss->dict[ss->v42bis_parm_c1].parent_code = (uint16_t) ss->string_code; + ss->dict[ss->v42bis_parm_c1].leaves = 0; + ss->dict[ss->v42bis_parm_c1].node_octet = (uint8_t) octet; + /* 7.7 Node recovery */ + /* 6.5 Recovering a dictionary entry to use next */ + for (;;) + { + /* 6.5(a) and (b) */ + if ((int) (++ss->v42bis_parm_c1) >= s->v42bis_parm_n2) + ss->v42bis_parm_c1 = V42BIS_N5; + /* 6.5(c) We need to reuse a leaf node */ + if (ss->dict[ss->v42bis_parm_c1].leaves) + continue; + if (ss->dict[ss->v42bis_parm_c1].parent_code == 0xFFFF) + break; + /* 6.5(d) Detach the leaf node from its parent, and re-use it */ + /* Possibly make the parent a leaf node again */ + ss->dict[ss->dict[ss->v42bis_parm_c1].parent_code].leaves--; + ss->dict[ss->dict[ss->v42bis_parm_c1].parent_code].children[ss->dict[ss->v42bis_parm_c1].node_octet >> 5] &= ~(1 << (ss->dict[ss->v42bis_parm_c1].node_octet & 0x1F)); + ss->dict[ss->v42bis_parm_c1].parent_code = 0xFFFF; + break; + } + } + else + { + ss->latest_code = 0xFFFFFFFF; + } + /* 7.8 Data compressibility test */ + /* Filter on the balance of what went into the compressor, and what came out */ + ss->compressibility_filter += ((((8*ss->string_length - ss->v42bis_parm_c2) << 20) - ss->compressibility_filter) >> 10); + if (ss->compression_mode == V42BIS_COMPRESSION_MODE_DYNAMIC) + { + /* Work out if it is appropriate to change between transparent and + compressed mode. */ + if (ss->transparent) + { + if (ss->compressibility_filter > 0) + { + if (++ss->compressibility_persistence > 1000) + { + /* Schedule a switch to compressed mode */ + ss->change_transparency = -1; + ss->compressibility_persistence = 0; + } + } + else + { + ss->compressibility_persistence = 0; + } + } + else + { + if (ss->compressibility_filter < 0) + { + if (++ss->compressibility_persistence > 1000) + { + /* Schedule a switch to transparent mode */ + ss->change_transparency = 1; + ss->compressibility_persistence = 0; + } + } + else + { + ss->compressibility_persistence = 0; + } + } + } + if (ss->change_transparency) + { + if (ss->change_transparency < 0) + { + if (ss->transparent) + { + printf("Going compressed\n"); + /* 7.8.1 Transition to compressed mode */ + /* Switch out of transparent now, between codes. We need to send the octet which did not + match, just before switching. */ + if (octet == ss->escape_code) + { + push_compressed_octet(ss, ss->escape_code++); + push_compressed_octet(ss, V42BIS_EID); + } + else + { + push_compressed_octet(ss, octet); + } + push_compressed_octet(ss, ss->escape_code++); + push_compressed_octet(ss, V42BIS_ECM); + ss->transparent = FALSE; + } + } + else + { + if (!ss->transparent) + { + printf("Going transparent\n"); + /* 7.8.2 Transition to transparent mode */ + /* Switch into transparent now, between codes, and the unmatched octet should + go out in transparent mode, just below */ + push_compressed_code(ss, V42BIS_ETM); + ss->transparent = TRUE; + } + } + ss->change_transparency = 0; + } + /* 7.8.3 Reset function - TODO */ + ss->string_code = octet + V42BIS_N6; + ss->string_length = 1; + } + if (ss->transparent) + { + if (octet == ss->escape_code) + { + push_compressed_octet(ss, ss->escape_code++); + push_compressed_octet(ss, V42BIS_EID); + } + else + { + push_compressed_octet(ss, octet); + } + } + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v42bis_compress_flush(v42bis_state_t *s) +{ + v42bis_compress_state_t *ss; + + ss = &s->compress; + if (!ss->transparent) + { + /* Output the last state of the string */ + push_compressed_code(ss, ss->string_code); + /* TODO: We use a positive FLUSH at all times. It is really needed, if the + previous step resulted in no leftover bits. */ + push_compressed_code(ss, V42BIS_FLUSH); + } + while (ss->output_bit_count > 0) + { + push_compressed_raw_octet(ss, ss->output_bit_buffer >> 24); + ss->output_bit_buffer <<= 8; + ss->output_bit_count -= 8; + } + /* Now push out anything remaining. */ + if (ss->output_octet_count > 0) + { + ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); + ss->output_octet_count = 0; + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +#if 0 +SPAN_DECLARE(int) v42bis_compress_dump(v42bis_state_t *s) +{ + int i; + + for (i = 0; i < V42BIS_MAX_CODEWORDS; i++) + { + if (s->compress.dict[i].parent_code != 0xFFFF) + { + printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); + } + } + return 0; +} +/*- End of function --------------------------------------------------------*/ +#endif + +SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *s, const uint8_t *buf, int len) +{ + int ptr; + int i; + int this_length; + uint8_t *string; + uint32_t code; + uint32_t new_code; + int code_len; + v42bis_decompress_state_t *ss; + uint8_t decode_buf[V42BIS_MAX_STRING_SIZE]; + + ss = &s->decompress; + if ((s->v42bis_parm_p0 & 1) == 0) + { + /* Compression is off - just push the incoming data out */ + for (i = 0; i < len - ss->max_len; i += ss->max_len) + ss->handler(ss->user_data, buf + i, ss->max_len); + if (i < len) + ss->handler(ss->user_data, buf + i, len - i); + return 0; + } + ptr = 0; + code_len = (ss->transparent) ? 8 : ss->v42bis_parm_c2; + for (;;) + { + /* Fill up the bit buffer. */ + while (ss->input_bit_count < 32 - 8 && ptr < len) + { + ss->input_bit_count += 8; + ss->input_bit_buffer |= (uint32_t) buf[ptr++] << (32 - ss->input_bit_count); + } + if (ss->input_bit_count < code_len) + break; + new_code = ss->input_bit_buffer >> (32 - code_len); + ss->input_bit_count -= code_len; + ss->input_bit_buffer <<= code_len; + if (ss->transparent) + { + code = new_code; + if (ss->escaped) + { + ss->escaped = FALSE; + if (code == V42BIS_ECM) + { + printf("Hit V42BIS_ECM\n"); + ss->transparent = FALSE; + code_len = ss->v42bis_parm_c2; + } + else if (code == V42BIS_EID) + { + printf("Hit V42BIS_EID\n"); + ss->output_buf[ss->output_octet_count++] = ss->escape_code - 1; + if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) + { + ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); + ss->output_octet_count = 0; + } + } + else if (code == V42BIS_RESET) + { + printf("Hit V42BIS_RESET\n"); + } + else + { + printf("Hit V42BIS_???? - %" PRIu32 "\n", code); + } + } + else if (code == ss->escape_code) + { + ss->escape_code++; + ss->escaped = TRUE; + } + else + { + ss->output_buf[ss->output_octet_count++] = (uint8_t) code; + if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) + { + ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); + ss->output_octet_count = 0; + } + } + } + else + { + if (new_code < V42BIS_N6) + { + /* We have a control code. */ + switch (new_code) + { + case V42BIS_ETM: + printf("Hit V42BIS_ETM\n"); + ss->transparent = TRUE; + code_len = 8; + break; + case V42BIS_FLUSH: + printf("Hit V42BIS_FLUSH\n"); + v42bis_decompress_flush(s); + break; + case V42BIS_STEPUP: + /* We need to increase the codeword size */ + printf("Hit V42BIS_STEPUP\n"); + if (ss->v42bis_parm_c3 >= s->v42bis_parm_n2) + { + /* Invalid condition */ + return -1; + } + code_len = ++ss->v42bis_parm_c2; + ss->v42bis_parm_c3 <<= 1; + break; + } + continue; + } + if (ss->first) + { + ss->first = FALSE; + ss->octet = new_code - V42BIS_N6; + ss->output_buf[0] = (uint8_t) ss->octet; + ss->output_octet_count = 1; + if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) + { + ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); + ss->output_octet_count = 0; + } + ss->old_code = new_code; + continue; + } + /* Start at the end of the buffer, and decode backwards */ + string = &decode_buf[V42BIS_MAX_STRING_SIZE - 1]; + /* Check the received code is valid. It can't be too big, as we pulled only the expected number + of bits from the input stream. It could, however, be unknown. */ + if (ss->dict[new_code].parent_code == 0xFFFF) + return -1; + /* Otherwise we do a straight decode of the new code. */ + code = new_code; + /* Trace back through the octets which form the string, and output them. */ + while (code >= V42BIS_N5) + { +if (code > 4095) {printf("Code is 0x%" PRIu32 "\n", code); exit(2);} + *string-- = ss->dict[code].node_octet; + code = ss->dict[code].parent_code; + } + *string = (uint8_t) (code - V42BIS_N6); + ss->octet = code - V42BIS_N6; + /* Output the decoded string. */ + this_length = V42BIS_MAX_STRING_SIZE - (int) (string - decode_buf); + memcpy(ss->output_buf + ss->output_octet_count, string, this_length); + ss->output_octet_count += this_length; + if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) + { + ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); + ss->output_octet_count = 0; + } + /* 6.4 Add the string to the dictionary */ + if (ss->last_length < s->v42bis_parm_n7) + { + /* 6.4(a) The string does not exceed N7 in length */ + if (ss->last_old_code != ss->old_code + || + ss->last_extra_octet != *string) + { + /* 6.4(b) The string is not in the table. */ + ss->dict[ss->old_code].leaves++; + /* The new one is definitely a leaf */ + ss->dict[ss->v42bis_parm_c1].parent_code = (uint16_t) ss->old_code; + ss->dict[ss->v42bis_parm_c1].leaves = 0; + ss->dict[ss->v42bis_parm_c1].node_octet = (uint8_t) ss->octet; + /* 6.5 Recovering a dictionary entry to use next */ + for (;;) + { + /* 6.5(a) and (b) */ + if (++ss->v42bis_parm_c1 >= s->v42bis_parm_n2) + ss->v42bis_parm_c1 = V42BIS_N5; + /* 6.5(c) We need to reuse a leaf node */ + if (ss->dict[ss->v42bis_parm_c1].leaves) + continue; + /* 6.5(d) This is a leaf node, so re-use it */ + /* Possibly make the parent a leaf node again */ + if (ss->dict[ss->v42bis_parm_c1].parent_code != 0xFFFF) + ss->dict[ss->dict[ss->v42bis_parm_c1].parent_code].leaves--; + ss->dict[ss->v42bis_parm_c1].parent_code = 0xFFFF; + break; + } + } + } + /* Record the addition to the dictionary, so we can check for repeat attempts + at the next code - see II.4.3 */ + ss->last_old_code = ss->old_code; + ss->last_extra_octet = *string; + + ss->old_code = new_code; + ss->last_length = this_length; + } + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v42bis_decompress_flush(v42bis_state_t *s) +{ + v42bis_decompress_state_t *ss; + + ss = &s->decompress; + /* Push out anything remaining. */ + if (ss->output_octet_count > 0) + { + ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); + ss->output_octet_count = 0; + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +#if 0 +SPAN_DECLARE(int) v42bis_decompress_dump(v42bis_state_t *s) +{ + int i; + + for (i = 0; i < V42BIS_MAX_CODEWORDS; i++) + { + if (s->decompress.dict[i].parent_code != 0xFFFF) + { + printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); + } + } + return 0; +} +/*- End of function --------------------------------------------------------*/ +#endif + +SPAN_DECLARE(void) v42bis_compression_control(v42bis_state_t *s, int mode) +{ + s->compress.compression_mode = mode; + switch (mode) + { + case V42BIS_COMPRESSION_MODE_ALWAYS: + s->compress.change_transparency = -1; + break; + case V42BIS_COMPRESSION_MODE_NEVER: + s->compress.change_transparency = 1; + break; + } +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, + int negotiated_p0, + int negotiated_p1, + int negotiated_p2, + v42bis_frame_handler_t frame_handler, + void *frame_user_data, + int max_frame_len, + v42bis_data_handler_t data_handler, + void *data_user_data, + int max_data_len) +{ + int i; + + if (negotiated_p1 < 512 || negotiated_p1 > 65535) + return NULL; + if (negotiated_p2 < 6 || negotiated_p2 > V42BIS_MAX_STRING_SIZE) + return NULL; + if (s == NULL) + { + if ((s = (v42bis_state_t *) malloc(sizeof(*s))) == NULL) + return NULL; + } + memset(s, 0, sizeof(*s)); + + s->compress.handler = frame_handler; + s->compress.user_data = frame_user_data; + s->compress.max_len = (max_frame_len < 1024) ? max_frame_len : 1024; + + s->decompress.handler = data_handler; + s->decompress.user_data = data_user_data; + s->decompress.max_len = (max_data_len < 1024) ? max_data_len : 1024; + + s->v42bis_parm_p0 = negotiated_p0; /* default is both ways off */ + + s->v42bis_parm_n1 = top_bit(negotiated_p1 - 1) + 1; + s->v42bis_parm_n2 = negotiated_p1; + s->v42bis_parm_n7 = negotiated_p2; + + /* 6.5 */ + s->compress.v42bis_parm_c1 = + s->decompress.v42bis_parm_c1 = V42BIS_N5; + + s->compress.v42bis_parm_c2 = + s->decompress.v42bis_parm_c2 = V42BIS_N3 + 1; + + s->compress.v42bis_parm_c3 = + s->decompress.v42bis_parm_c3 = 2*V42BIS_N4; + + s->compress.first = + s->decompress.first = TRUE; + for (i = 0; i < V42BIS_MAX_CODEWORDS; i++) + { + s->compress.dict[i].parent_code = + s->decompress.dict[i].parent_code = 0xFFFF; + s->compress.dict[i].leaves = + s->decompress.dict[i].leaves = 0; + } + /* Point the root nodes for decompression to themselves. It doesn't matter much what + they are set to, as long as they are considered "known" codes. */ + for (i = 0; i < V42BIS_N5; i++) + s->decompress.dict[i].parent_code = (uint16_t) i; + s->compress.string_code = 0xFFFFFFFF; + s->compress.latest_code = 0xFFFFFFFF; + + s->decompress.last_old_code = 0xFFFFFFFF; + s->decompress.last_extra_octet = -1; + + s->compress.compression_mode = V42BIS_COMPRESSION_MODE_DYNAMIC; + + return s; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v42bis_release(v42bis_state_t *s) +{ + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v42bis_free(v42bis_state_t *s) +{ + free(s); + return 0; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ -- To view, visit https://gerrit.osmocom.org/643 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Iabedece9f97ca944a1e3f747bb073e532c4e9dca Gerrit-PatchSet: 9 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte From gerrit-no-reply at lists.osmocom.org Fri Aug 5 11:28:08 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Fri, 5 Aug 2016 11:28:08 +0000 Subject: [PATCH] openbsc[master]: V42BIS integration In-Reply-To: References: Message-ID: Hello Harald Welte, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/644 to look at the new patch set (#11). V42BIS integration The previously committed SPANDSP v42bis implementation has been edited to function outside the SPANDSP library. Debug printf statements were changed into DEBUGP statements. Als removed the assembely code in top_bit(). Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d --- M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/debug.h M openbsc/include/openbsc/v42bis.h R openbsc/include/openbsc/v42bis_private.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/v42bis.c 6 files changed, 11 insertions(+), 11 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/44/644/11 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index e159db5..e404b17 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,8 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h gprs_sndcp_xid.h \ - gprs_sndcp_comp_entity.h gprs_sndcp_hdrcomp.h + gprs_sndcp_comp_entity.h gprs_sndcp_hdrcomp.h v42bis.h \ + v42bis_private.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 90ddca5..ca3d4ad 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -37,6 +37,7 @@ DGTPHUB, DRANAP, DSUA, + DV42BIS, Debug_LastEntry, }; diff --git a/openbsc/include/openbsc/v42bis.h b/openbsc/include/openbsc/v42bis.h index f13e5c5..e7592e8 100644 --- a/openbsc/include/openbsc/v42bis.h +++ b/openbsc/include/openbsc/v42bis.h @@ -36,6 +36,8 @@ #if !defined(_SPANDSP_V42BIS_H_) #define _SPANDSP_V42BIS_H_ +#define SPAN_DECLARE(x) x + #define V42BIS_MAX_BITS 12 #define V42BIS_MAX_CODEWORDS 4096 /* 2^V42BIS_MAX_BITS */ #define V42BIS_TABLE_SIZE 5021 /* This should be a prime >(2^V42BIS_MAX_BITS) */ diff --git a/openbsc/include/openbsc/private_v42bis.h b/openbsc/include/openbsc/v42bis_private.h similarity index 100% rename from openbsc/include/openbsc/private_v42bis.h rename to openbsc/include/openbsc/v42bis_private.h diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 3d6c82a..2c03a45 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -22,7 +22,7 @@ osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \ slhc.c gprs_sndcp_xid.c gprs_sndcp_comp_entity.c \ - gprs_sndcp_hdrcomp.c \ + gprs_sndcp_hdrcomp.c v42bis.c \ sgsn_main.c sgsn_vty.c sgsn_libgtp.c \ gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c \ gprs_llc_xid.c crc24.c \ diff --git a/openbsc/src/gprs/v42bis.c b/openbsc/src/gprs/v42bis.c index 6d38916..a306107 100644 --- a/openbsc/src/gprs/v42bis.c +++ b/openbsc/src/gprs/v42bis.c @@ -31,9 +31,8 @@ /*! \file */ -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif +#define FALSE 0 +#define TRUE 1 #include #include @@ -44,13 +43,9 @@ #include #include -#include "spandsp/telephony.h" -#include "spandsp/logging.h" -#include "spandsp/bit_operations.h" -#include "spandsp/v42bis.h" +#include +#include -#include "spandsp/private/logging.h" -#include "spandsp/private/v42bis.h" /* Fixed parameters from the spec. */ #define V42BIS_N3 8 /* Character size (bits) */ @@ -79,6 +74,7 @@ \return The bit number of the highest set bit, or -1 if the word is zero. */ static __inline__ int top_bit(unsigned int bits) { + /* Note: This function was taken from spandsp/bit_operations.h */ int res; -- To view, visit https://gerrit.osmocom.org/644 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d Gerrit-PatchSet: 11 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte From gerrit-no-reply at lists.osmocom.org Fri Aug 5 11:28:08 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Fri, 5 Aug 2016 11:28:08 +0000 Subject: [PATCH] openbsc[master]: Adding slhc code from kernel.org In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/634 to look at the new patch set (#3). Adding slhc code from kernel.org Slhc is an Implementation of RFC1144 TCP/IP header compression. We will need RFC1144 compression to compress GPRS TCP/IP traffic. The implementation pushed with this commit was taken from git://git.kernel.org/pub/scm/linux/kernel/git/wtarreau/linux-2.4.git commit e294a2074f0059de7c69b30fe3048fe61f971b83 Change-Id: Ied69c143678dc4a64cecc671f5c4dfebe19d8519 --- A openbsc/include/openbsc/slhc_vj.h A openbsc/src/gprs/slhc.c 2 files changed, 991 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/34/634/3 diff --git a/openbsc/include/openbsc/slhc_vj.h b/openbsc/include/openbsc/slhc_vj.h new file mode 100644 index 0000000..0a85dc0 --- /dev/null +++ b/openbsc/include/openbsc/slhc_vj.h @@ -0,0 +1,191 @@ +#ifndef _SLHC_H +#define _SLHC_H +/* + * Definitions for tcp compression routines. + * + * $Header: slcompress.h,v 1.10 89/12/31 08:53:02 van Exp $ + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van at helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + * + * + * modified for KA9Q Internet Software Package by + * Katie Stevens (dkstevens at ucdavis.edu) + * University of California, Davis + * Computing Services + * - 01-31-90 initial adaptation + * + * - Feb 1991 Bill_Simpson at um.cc.umich.edu + * variable number of conversation slots + * allow zero or one slots + * separate routines + * status display + */ + +/* + * Compressed packet format: + * + * The first octet contains the packet type (top 3 bits), TCP + * 'push' bit, and flags that indicate which of the 4 TCP sequence + * numbers have changed (bottom 5 bits). The next octet is a + * conversation number that associates a saved IP/TCP header with + * the compressed packet. The next two octets are the TCP checksum + * from the original datagram. The next 0 to 15 octets are + * sequence number changes, one change per bit set in the header + * (there may be no changes and there are two special cases where + * the receiver implicitly knows what changed -- see below). + * + * There are 5 numbers which can change (they are always inserted + * in the following order): TCP urgent pointer, window, + * acknowledgment, sequence number and IP ID. (The urgent pointer + * is different from the others in that its value is sent, not the + * change in value.) Since typical use of SLIP links is biased + * toward small packets (see comments on MTU/MSS below), changes + * use a variable length coding with one octet for numbers in the + * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the + * range 256 - 65535 or 0. (If the change in sequence number or + * ack is more than 65535, an uncompressed packet is sent.) + */ + +/* + * Packet types (must not conflict with IP protocol version) + * + * The top nibble of the first octet is the packet type. There are + * three possible types: IP (not proto TCP or tcp with one of the + * control flags set); uncompressed TCP (a normal IP/TCP packet but + * with the 8-bit protocol field replaced by an 8-bit connection id -- + * this type of packet syncs the sender & receiver); and compressed + * TCP (described above). + * + * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and + * is logically part of the 4-bit "changes" field that follows. Top + * three bits are actual packet type. For backward compatibility + * and in the interest of conserving bits, numbers are chosen so the + * IP protocol version number (4) which normally appears in this nibble + * means "IP packet". + */ + + +#include +#include + +/* SLIP compression masks for len/vers byte */ +#define SL_TYPE_IP 0x40 +#define SL_TYPE_UNCOMPRESSED_TCP 0x70 +#define SL_TYPE_COMPRESSED_TCP 0x80 +#define SL_TYPE_ERROR 0x00 + +/* Bits in first octet of compressed packet */ +#define NEW_C 0x40 /* flag bits for what changed in a packet */ +#define NEW_I 0x20 +#define NEW_S 0x08 +#define NEW_A 0x04 +#define NEW_W 0x02 +#define NEW_U 0x01 + +/* reserved, special-case values of above */ +#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */ +#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */ +#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U) + +#define TCP_PUSH_BIT 0x10 + +/* + * data type and sizes conversion assumptions: + * + * VJ code KA9Q style generic + * u_char byte_t unsigned char 8 bits + * u_short int16 unsigned short 16 bits + * u_int int16 unsigned short 16 bits + * u_long unsigned long unsigned long 32 bits + * int int32 long 32 bits + */ + +typedef __u8 byte_t; +typedef __u32 int32; + +/* + * "state" data for each active tcp conversation on the wire. This is + * basically a copy of the entire IP/TCP header from the last packet + * we saw from the conversation together with a small identifier + * the transmit & receive ends of the line use to locate saved header. + */ +struct cstate { + byte_t cs_this; /* connection id number (xmit) */ + struct cstate *next; /* next in ring (xmit) */ + struct iphdr cs_ip; /* ip/tcp hdr from most recent packet */ + struct tcphdr cs_tcp; + unsigned char cs_ipopt[64]; + unsigned char cs_tcpopt[64]; + int cs_hsize; +}; +#define NULLSLSTATE (struct cstate *)0 + +/* + * all the state data for one serial line (we need one of these per line). + */ +struct slcompress { + struct cstate *tstate; /* transmit connection states (array)*/ + struct cstate *rstate; /* receive connection states (array)*/ + + byte_t tslot_limit; /* highest transmit slot id (0-l)*/ + byte_t rslot_limit; /* highest receive slot id (0-l)*/ + + byte_t xmit_oldest; /* oldest xmit in ring */ + byte_t xmit_current; /* most recent xmit id */ + byte_t recv_current; /* most recent rcvd id */ + + byte_t flags; +#define SLF_TOSS 0x01 /* tossing rcvd frames until id received */ + + int32 sls_o_nontcp; /* outbound non-TCP packets */ + int32 sls_o_tcp; /* outbound TCP packets */ + int32 sls_o_uncompressed; /* outbound uncompressed packets */ + int32 sls_o_compressed; /* outbound compressed packets */ + int32 sls_o_searches; /* searches for connection state */ + int32 sls_o_misses; /* times couldn't find conn. state */ + + int32 sls_i_uncompressed; /* inbound uncompressed packets */ + int32 sls_i_compressed; /* inbound compressed packets */ + int32 sls_i_error; /* inbound error packets */ + int32 sls_i_tossed; /* inbound packets tossed because of error */ + + int32 sls_i_runt; + int32 sls_i_badcheck; +}; +#define NULLSLCOMPR (struct slcompress *)0 + +#define __ARGS(x) x + +/* In slhc.c: */ +struct slcompress *slhc_init __ARGS((int rslots, int tslots)); +void slhc_free __ARGS((struct slcompress *comp)); + +int slhc_compress __ARGS((struct slcompress *comp, unsigned char *icp, + int isize, unsigned char *ocp, unsigned char **cpp, + int compress_cid)); +int slhc_uncompress __ARGS((struct slcompress *comp, unsigned char *icp, + int isize)); +int slhc_remember __ARGS((struct slcompress *comp, unsigned char *icp, + int isize)); +int slhc_toss __ARGS((struct slcompress *comp)); + +void slhc_i_status __ARGS((struct slcompress *comp)); +void slhc_o_status __ARGS((struct slcompress *comp)); + +#endif /* _SLHC_H */ diff --git a/openbsc/src/gprs/slhc.c b/openbsc/src/gprs/slhc.c new file mode 100644 index 0000000..b1a855c --- /dev/null +++ b/openbsc/src/gprs/slhc.c @@ -0,0 +1,800 @@ +/* + * Routines to compress and uncompress tcp packets (for transmission + * over low speed serial lines). + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van at helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + * + * + * modified for KA9Q Internet Software Package by + * Katie Stevens (dkstevens at ucdavis.edu) + * University of California, Davis + * Computing Services + * - 01-31-90 initial adaptation (from 1.19) + * PPP.05 02-15-90 [ks] + * PPP.08 05-02-90 [ks] use PPP protocol field to signal compression + * PPP.15 09-90 [ks] improve mbuf handling + * PPP.16 11-02 [karn] substantially rewritten to use NOS facilities + * + * - Feb 1991 Bill_Simpson at um.cc.umich.edu + * variable number of conversation slots + * allow zero or one slots + * separate routines + * status display + * - Jul 1994 Dmitry Gorodchanin + * Fixes for memory leaks. + * - Oct 1994 Dmitry Gorodchanin + * Modularization. + * - Jan 1995 Bjorn Ekwall + * Use ip_fast_csum from ip.h + * - July 1995 Christos A. Polyzols + * Spotted bug in tcp option checking + * + * + * This module is a difficult issue. It's clearly inet code but it's also clearly + * driver code belonging close to PPP and SLIP + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_INET +/* Entire module is for IP only */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned char *encode(unsigned char *cp, unsigned short n); +static long decode(unsigned char **cpp); +static unsigned char * put16(unsigned char *cp, unsigned short x); +static unsigned short pull16(unsigned char **cpp); + +/* Initialize compression data structure + * slots must be in range 0 to 255 (zero meaning no compression) + */ +struct slcompress * +slhc_init(int rslots, int tslots) +{ + register short i; + register struct cstate *ts; + struct slcompress *comp; + + MOD_INC_USE_COUNT; + comp = (struct slcompress *)kmalloc(sizeof(struct slcompress), + GFP_KERNEL); + if (! comp) + goto out_fail; + memset(comp, 0, sizeof(struct slcompress)); + + if ( rslots > 0 && rslots < 256 ) { + size_t rsize = rslots * sizeof(struct cstate); + comp->rstate = (struct cstate *) kmalloc(rsize, GFP_KERNEL); + if (! comp->rstate) + goto out_free; + memset(comp->rstate, 0, rsize); + comp->rslot_limit = rslots - 1; + } + + if ( tslots > 0 && tslots < 256 ) { + size_t tsize = tslots * sizeof(struct cstate); + comp->tstate = (struct cstate *) kmalloc(tsize, GFP_KERNEL); + if (! comp->tstate) + goto out_free2; + memset(comp->tstate, 0, tsize); + comp->tslot_limit = tslots - 1; + } + + comp->xmit_oldest = 0; + comp->xmit_current = 255; + comp->recv_current = 255; + /* + * don't accept any packets with implicit index until we get + * one with an explicit index. Otherwise the uncompress code + * will try to use connection 255, which is almost certainly + * out of range + */ + comp->flags |= SLF_TOSS; + + if ( tslots > 0 ) { + ts = comp->tstate; + for(i = comp->tslot_limit; i > 0; --i){ + ts[i].cs_this = i; + ts[i].next = &(ts[i - 1]); + } + ts[0].next = &(ts[comp->tslot_limit]); + ts[0].cs_this = 0; + } + return comp; + +out_free2: + kfree((unsigned char *)comp->rstate); +out_free: + kfree((unsigned char *)comp); +out_fail: + MOD_DEC_USE_COUNT; + return NULL; +} + + +/* Free a compression data structure */ +void +slhc_free(struct slcompress *comp) +{ + if ( comp == NULLSLCOMPR ) + return; + + if ( comp->tstate != NULLSLSTATE ) + kfree( comp->tstate ); + + if ( comp->rstate != NULLSLSTATE ) + kfree( comp->rstate ); + + kfree( comp ); + MOD_DEC_USE_COUNT; +} + + +/* Put a short in host order into a char array in network order */ +static inline unsigned char * +put16(unsigned char *cp, unsigned short x) +{ + *cp++ = x >> 8; + *cp++ = x; + + return cp; +} + + +/* Encode a number */ +unsigned char * +encode(unsigned char *cp, unsigned short n) +{ + if(n >= 256 || n == 0){ + *cp++ = 0; + cp = put16(cp,n); + } else { + *cp++ = n; + } + return cp; +} + +/* Pull a 16-bit integer in host order from buffer in network byte order */ +static unsigned short +pull16(unsigned char **cpp) +{ + short rval; + + rval = *(*cpp)++; + rval <<= 8; + rval |= *(*cpp)++; + return rval; +} + +/* Decode a number */ +long +decode(unsigned char **cpp) +{ + register int x; + + x = *(*cpp)++; + if(x == 0){ + return pull16(cpp) & 0xffff; /* pull16 returns -1 on error */ + } else { + return x & 0xff; /* -1 if PULLCHAR returned error */ + } +} + +/* + * icp and isize are the original packet. + * ocp is a place to put a copy if necessary. + * cpp is initially a pointer to icp. If the copy is used, + * change it to ocp. + */ + +int +slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, + unsigned char *ocp, unsigned char **cpp, int compress_cid) +{ + register struct cstate *ocs = &(comp->tstate[comp->xmit_oldest]); + register struct cstate *lcs = ocs; + register struct cstate *cs = lcs->next; + register unsigned long deltaS, deltaA; + register short changes = 0; + int hlen; + unsigned char new_seq[16]; + register unsigned char *cp = new_seq; + struct iphdr *ip; + struct tcphdr *th, *oth; + + + /* + * Don't play with runt packets. + */ + + if(isizeprotocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x3fff)) { + /* Send as regular IP */ + if(ip->protocol != IPPROTO_TCP) + comp->sls_o_nontcp++; + else + comp->sls_o_tcp++; + return isize; + } + /* Extract TCP header */ + + th = (struct tcphdr *)(((unsigned char *)ip) + ip->ihl*4); + hlen = ip->ihl*4 + th->doff*4; + + /* Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or + * some other control bit is set). Also uncompressible if + * its a runt. + */ + if(hlen > isize || th->syn || th->fin || th->rst || + ! (th->ack)){ + /* TCP connection stuff; send as regular IP */ + comp->sls_o_tcp++; + return isize; + } + /* + * Packet is compressible -- we're going to send either a + * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way, + * we need to locate (or create) the connection state. + * + * States are kept in a circularly linked list with + * xmit_oldest pointing to the end of the list. The + * list is kept in lru order by moving a state to the + * head of the list whenever it is referenced. Since + * the list is short and, empirically, the connection + * we want is almost always near the front, we locate + * states via linear search. If we don't find a state + * for the datagram, the oldest state is (re-)used. + */ + for ( ; ; ) { + if( ip->saddr == cs->cs_ip.saddr + && ip->daddr == cs->cs_ip.daddr + && th->source == cs->cs_tcp.source + && th->dest == cs->cs_tcp.dest) + goto found; + + /* if current equal oldest, at end of list */ + if ( cs == ocs ) + break; + lcs = cs; + cs = cs->next; + comp->sls_o_searches++; + }; + /* + * Didn't find it -- re-use oldest cstate. Send an + * uncompressed packet that tells the other side what + * connection number we're using for this conversation. + * + * Note that since the state list is circular, the oldest + * state points to the newest and we only need to set + * xmit_oldest to update the lru linkage. + */ + comp->sls_o_misses++; + comp->xmit_oldest = lcs->cs_this; + goto uncompressed; + +found: + /* + * Found it -- move to the front on the connection list. + */ + if(lcs == ocs) { + /* found at most recently used */ + } else if (cs == ocs) { + /* found at least recently used */ + comp->xmit_oldest = lcs->cs_this; + } else { + /* more than 2 elements */ + lcs->next = cs->next; + cs->next = ocs->next; + ocs->next = cs; + } + + /* + * Make sure that only what we expect to change changed. + * Check the following: + * IP protocol version, header length & type of service. + * The "Don't fragment" bit. + * The time-to-live field. + * The TCP header length. + * IP options, if any. + * TCP options, if any. + * If any of these things are different between the previous & + * current datagram, we send the current datagram `uncompressed'. + */ + oth = &cs->cs_tcp; + + if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl + || ip->tos != cs->cs_ip.tos + || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000)) + || ip->ttl != cs->cs_ip.ttl + || th->doff != cs->cs_tcp.doff + || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) + || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){ + goto uncompressed; + } + + /* + * Figure out which of the changing fields changed. The + * receiver expects changes in the order: urgent, window, + * ack, seq (the order minimizes the number of temporaries + * needed in this section of code). + */ + if(th->urg){ + deltaS = ntohs(th->urg_ptr); + cp = encode(cp,deltaS); + changes |= NEW_U; + } else if(th->urg_ptr != oth->urg_ptr){ + /* argh! URG not set but urp changed -- a sensible + * implementation should never do this but RFC793 + * doesn't prohibit the change so we have to deal + * with it. */ + goto uncompressed; + } + if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){ + cp = encode(cp,deltaS); + changes |= NEW_W; + } + if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){ + if(deltaA > 0x0000ffff) + goto uncompressed; + cp = encode(cp,deltaA); + changes |= NEW_A; + } + if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){ + if(deltaS > 0x0000ffff) + goto uncompressed; + cp = encode(cp,deltaS); + changes |= NEW_S; + } + + switch(changes){ + case 0: /* Nothing changed. If this packet contains data and the + * last one didn't, this is probably a data packet following + * an ack (normal on an interactive connection) and we send + * it compressed. Otherwise it's probably a retransmit, + * retransmitted ack or window probe. Send it uncompressed + * in case the other side missed the compressed version. + */ + if(ip->tot_len != cs->cs_ip.tot_len && + ntohs(cs->cs_ip.tot_len) == hlen) + break; + goto uncompressed; + break; + case SPECIAL_I: + case SPECIAL_D: + /* actual changes match one of our special case encodings -- + * send packet uncompressed. + */ + goto uncompressed; + case NEW_S|NEW_A: + if(deltaS == deltaA && + deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ + /* special case for echoed terminal traffic */ + changes = SPECIAL_I; + cp = new_seq; + } + break; + case NEW_S: + if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ + /* special case for data xfer */ + changes = SPECIAL_D; + cp = new_seq; + } + break; + } + deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id); + if(deltaS != 1){ + cp = encode(cp,deltaS); + changes |= NEW_I; + } + if(th->psh) + changes |= TCP_PUSH_BIT; + /* Grab the cksum before we overwrite it below. Then update our + * state with this packet's header. + */ + deltaA = ntohs(th->check); + memcpy(&cs->cs_ip,ip,20); + memcpy(&cs->cs_tcp,th,20); + /* We want to use the original packet as our compressed packet. + * (cp - new_seq) is the number of bytes we need for compressed + * sequence numbers. In addition we need one byte for the change + * mask, one for the connection id and two for the tcp checksum. + * So, (cp - new_seq) + 4 bytes of header are needed. + */ + deltaS = cp - new_seq; + if(compress_cid == 0 || comp->xmit_current != cs->cs_this){ + cp = ocp; + *cpp = ocp; + *cp++ = changes | NEW_C; + *cp++ = cs->cs_this; + comp->xmit_current = cs->cs_this; + } else { + cp = ocp; + *cpp = ocp; + *cp++ = changes; + } + cp = put16(cp,(short)deltaA); /* Write TCP checksum */ +/* deltaS is now the size of the change section of the compressed header */ + memcpy(cp,new_seq,deltaS); /* Write list of deltas */ + memcpy(cp+deltaS,icp+hlen,isize-hlen); + comp->sls_o_compressed++; + ocp[0] |= SL_TYPE_COMPRESSED_TCP; + return isize - hlen + deltaS + (cp - ocp); + + /* Update connection state cs & send uncompressed packet (i.e., + * a regular ip/tcp packet but with the 'conversation id' we hope + * to use on future compressed packets in the protocol field). + */ +uncompressed: + memcpy(&cs->cs_ip,ip,20); + memcpy(&cs->cs_tcp,th,20); + if (ip->ihl > 5) + memcpy(cs->cs_ipopt, ip+1, ((ip->ihl) - 5) * 4); + if (th->doff > 5) + memcpy(cs->cs_tcpopt, th+1, ((th->doff) - 5) * 4); + comp->xmit_current = cs->cs_this; + comp->sls_o_uncompressed++; + memcpy(ocp, icp, isize); + *cpp = ocp; + ocp[9] = cs->cs_this; + ocp[0] |= SL_TYPE_UNCOMPRESSED_TCP; + return isize; +} + + +int +slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) +{ + register int changes; + long x; + register struct tcphdr *thp; + register struct iphdr *ip; + register struct cstate *cs; + int len, hdrlen; + unsigned char *cp = icp; + + /* We've got a compressed packet; read the change byte */ + comp->sls_i_compressed++; + if(isize < 3){ + comp->sls_i_error++; + return 0; + } + changes = *cp++; + if(changes & NEW_C){ + /* Make sure the state index is in range, then grab the state. + * If we have a good state index, clear the 'discard' flag. + */ + x = *cp++; /* Read conn index */ + if(x < 0 || x > comp->rslot_limit) + goto bad; + + comp->flags &=~ SLF_TOSS; + comp->recv_current = x; + } else { + /* this packet has an implicit state index. If we've + * had a line error since the last time we got an + * explicit state index, we have to toss the packet. */ + if(comp->flags & SLF_TOSS){ + comp->sls_i_tossed++; + return 0; + } + } + cs = &comp->rstate[comp->recv_current]; + thp = &cs->cs_tcp; + ip = &cs->cs_ip; + + if((x = pull16(&cp)) == -1) { /* Read the TCP checksum */ + goto bad; + } + thp->check = htons(x); + + thp->psh = (changes & TCP_PUSH_BIT) ? 1 : 0; +/* + * we can use the same number for the length of the saved header and + * the current one, because the packet wouldn't have been sent + * as compressed unless the options were the same as the previous one + */ + + hdrlen = ip->ihl * 4 + thp->doff * 4; + + switch(changes & SPECIALS_MASK){ + case SPECIAL_I: /* Echoed terminal traffic */ + { + register short i; + i = ntohs(ip->tot_len) - hdrlen; + thp->ack_seq = htonl( ntohl(thp->ack_seq) + i); + thp->seq = htonl( ntohl(thp->seq) + i); + } + break; + + case SPECIAL_D: /* Unidirectional data */ + thp->seq = htonl( ntohl(thp->seq) + + ntohs(ip->tot_len) - hdrlen); + break; + + default: + if(changes & NEW_U){ + thp->urg = 1; + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->urg_ptr = htons(x); + } else + thp->urg = 0; + if(changes & NEW_W){ + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->window = htons( ntohs(thp->window) + x); + } + if(changes & NEW_A){ + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->ack_seq = htonl( ntohl(thp->ack_seq) + x); + } + if(changes & NEW_S){ + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->seq = htonl( ntohl(thp->seq) + x); + } + break; + } + if(changes & NEW_I){ + if((x = decode(&cp)) == -1) { + goto bad; + } + ip->id = htons (ntohs (ip->id) + x); + } else + ip->id = htons (ntohs (ip->id) + 1); + + /* + * At this point, cp points to the first byte of data in the + * packet. Put the reconstructed TCP and IP headers back on the + * packet. Recalculate IP checksum (but not TCP checksum). + */ + + len = isize - (cp - icp); + if (len < 0) + goto bad; + len += hdrlen; + ip->tot_len = htons(len); + ip->check = 0; + + memmove(icp + hdrlen, cp, len - hdrlen); + + cp = icp; + memcpy(cp, ip, 20); + cp += 20; + + if (ip->ihl > 5) { + memcpy(cp, cs->cs_ipopt, (ip->ihl - 5) * 4); + cp += (ip->ihl - 5) * 4; + } + + put_unaligned(ip_fast_csum(icp, ip->ihl), + &((struct iphdr *)icp)->check); + + memcpy(cp, thp, 20); + cp += 20; + + if (thp->doff > 5) { + memcpy(cp, cs->cs_tcpopt, ((thp->doff) - 5) * 4); + cp += ((thp->doff) - 5) * 4; + } + + return len; +bad: + comp->sls_i_error++; + return slhc_toss( comp ); +} + + +int +slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +{ + register struct cstate *cs; + unsigned ihl; + + unsigned char index; + + if(isize < 20) { + /* The packet is shorter than a legal IP header */ + comp->sls_i_runt++; + return slhc_toss( comp ); + } + /* Peek at the IP header's IHL field to find its length */ + ihl = icp[0] & 0xf; + if(ihl < 20 / 4){ + /* The IP header length field is too small */ + comp->sls_i_runt++; + return slhc_toss( comp ); + } + index = icp[9]; + icp[9] = IPPROTO_TCP; + + if (ip_fast_csum(icp, ihl)) { + /* Bad IP header checksum; discard */ + comp->sls_i_badcheck++; + return slhc_toss( comp ); + } + if(index > comp->rslot_limit) { + comp->sls_i_error++; + return slhc_toss(comp); + } + + /* Update local state */ + cs = &comp->rstate[comp->recv_current = index]; + comp->flags &=~ SLF_TOSS; + memcpy(&cs->cs_ip,icp,20); + memcpy(&cs->cs_tcp,icp + ihl*4,20); + if (ihl > 5) + memcpy(cs->cs_ipopt, icp + sizeof(struct iphdr), (ihl - 5) * 4); + if (cs->cs_tcp.doff > 5) + memcpy(cs->cs_tcpopt, icp + ihl*4 + sizeof(struct tcphdr), (cs->cs_tcp.doff - 5) * 4); + cs->cs_hsize = ihl*2 + cs->cs_tcp.doff*2; + /* Put headers back on packet + * Neither header checksum is recalculated + */ + comp->sls_i_uncompressed++; + return isize; +} + + +int +slhc_toss(struct slcompress *comp) +{ + if ( comp == NULLSLCOMPR ) + return 0; + + comp->flags |= SLF_TOSS; + return 0; +} + + +void slhc_i_status(struct slcompress *comp) +{ + if (comp != NULLSLCOMPR) { + printk("\t%d Cmp, %d Uncmp, %d Bad, %d Tossed\n", + comp->sls_i_compressed, + comp->sls_i_uncompressed, + comp->sls_i_error, + comp->sls_i_tossed); + } +} + + +void slhc_o_status(struct slcompress *comp) +{ + if (comp != NULLSLCOMPR) { + printk("\t%d Cmp, %d Uncmp, %d AsIs, %d NotTCP\n", + comp->sls_o_compressed, + comp->sls_o_uncompressed, + comp->sls_o_tcp, + comp->sls_o_nontcp); + printk("\t%10d Searches, %10d Misses\n", + comp->sls_o_searches, + comp->sls_o_misses); + } +} + +/* Should this be surrounded with "#ifdef CONFIG_MODULES" ? */ +/* VJ header compression */ +EXPORT_SYMBOL(slhc_init); +EXPORT_SYMBOL(slhc_free); +EXPORT_SYMBOL(slhc_remember); +EXPORT_SYMBOL(slhc_compress); +EXPORT_SYMBOL(slhc_uncompress); +EXPORT_SYMBOL(slhc_toss); + +#ifdef MODULE + +int init_module(void) +{ + printk(KERN_INFO "CSLIP: code copyright 1989 Regents of the University of California\n"); + return 0; +} + +void cleanup_module(void) +{ + return; +} + +#endif /* MODULE */ +#else /* CONFIG_INET */ + + +int +slhc_toss(struct slcompress *comp) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss"); + return -EINVAL; +} +int +slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress"); + return -EINVAL; +} +int +slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, + unsigned char *ocp, unsigned char **cpp, int compress_cid) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress"); + return -EINVAL; +} + +int +slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember"); + return -EINVAL; +} + +void +slhc_free(struct slcompress *comp) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free"); + return; +} +struct slcompress * +slhc_init(int rslots, int tslots) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init"); + return NULL; +} +EXPORT_SYMBOL(slhc_init); +EXPORT_SYMBOL(slhc_free); +EXPORT_SYMBOL(slhc_remember); +EXPORT_SYMBOL(slhc_compress); +EXPORT_SYMBOL(slhc_uncompress); +EXPORT_SYMBOL(slhc_toss); + +#endif /* CONFIG_INET */ +MODULE_LICENSE("Dual BSD/GPL"); -- To view, visit https://gerrit.osmocom.org/634 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ied69c143678dc4a64cecc671f5c4dfebe19d8519 Gerrit-PatchSet: 3 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Fri Aug 5 11:28:08 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Fri, 5 Aug 2016 11:28:08 +0000 Subject: [PATCH] openbsc[master]: Modifed version of slhc (RFC1144 implementation) In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/635 to look at the new patch set (#3). Modifed version of slhc (RFC1144 implementation) The previously pushed slhc implementation has been modified to compile and function outside of the kernel. Also debug log messages were added and datatypes ware matched. The implementation is now ready to be used Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 --- M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/debug.h R openbsc/include/openbsc/slhc.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/slhc.c 5 files changed, 128 insertions(+), 177 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/35/635/3 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index c272b14..9ef8a15 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,7 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h + gtphub.h gprs_sndcp.h slhc.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 43ebb19..90ddca5 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -29,6 +29,7 @@ DBSSGP, DLLC, DSNDCP, + DSLHC, DNAT, DCTRL, DSMPP, diff --git a/openbsc/include/openbsc/slhc_vj.h b/openbsc/include/openbsc/slhc.h similarity index 89% rename from openbsc/include/openbsc/slhc_vj.h rename to openbsc/include/openbsc/slhc.h index 0a85dc0..2e926dd 100644 --- a/openbsc/include/openbsc/slhc_vj.h +++ b/openbsc/include/openbsc/slhc.h @@ -80,7 +80,6 @@ * means "IP packet". */ - #include #include @@ -109,7 +108,7 @@ * data type and sizes conversion assumptions: * * VJ code KA9Q style generic - * u_char byte_t unsigned char 8 bits + * u_char byte_t uint8_t 8 bits * u_short int16 unsigned short 16 bits * u_int int16 unsigned short 16 bits * u_long unsigned long unsigned long 32 bits @@ -130,8 +129,8 @@ struct cstate *next; /* next in ring (xmit) */ struct iphdr cs_ip; /* ip/tcp hdr from most recent packet */ struct tcphdr cs_tcp; - unsigned char cs_ipopt[64]; - unsigned char cs_tcpopt[64]; + uint8_t cs_ipopt[64]; + uint8_t cs_tcpopt[64]; int cs_hsize; }; #define NULLSLSTATE (struct cstate *)0 @@ -173,19 +172,16 @@ #define __ARGS(x) x /* In slhc.c: */ -struct slcompress *slhc_init __ARGS((int rslots, int tslots)); -void slhc_free __ARGS((struct slcompress *comp)); +struct slcompress *slhc_init(int rslots, int tslots); -int slhc_compress __ARGS((struct slcompress *comp, unsigned char *icp, - int isize, unsigned char *ocp, unsigned char **cpp, - int compress_cid)); -int slhc_uncompress __ARGS((struct slcompress *comp, unsigned char *icp, - int isize)); -int slhc_remember __ARGS((struct slcompress *comp, unsigned char *icp, - int isize)); -int slhc_toss __ARGS((struct slcompress *comp)); +void slhc_free(struct slcompress *comp); -void slhc_i_status __ARGS((struct slcompress *comp)); -void slhc_o_status __ARGS((struct slcompress *comp)); +int slhc_compress(struct slcompress *comp, uint8_t *icp, int isize, uint8_t *ocp, uint8_t **cpp, int compress_cid); +int slhc_uncompress(struct slcompress *comp, uint8_t *icp, int isize); +int slhc_remember(struct slcompress *comp, uint8_t *icp, int isize); +int slhc_toss(struct slcompress *comp); + +void slhc_i_status(struct slcompress *comp); +void slhc_o_status(struct slcompress *comp); #endif /* _SLHC_H */ diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 6dc7e16..548b38c 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -23,6 +23,7 @@ $(OSMO_LIBS) $(LIBCRYPTO_LIBS) -lrt osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \ + slhc.c \ sgsn_main.c sgsn_vty.c sgsn_libgtp.c \ gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c crc24.c \ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ diff --git a/openbsc/src/gprs/slhc.c b/openbsc/src/gprs/slhc.c index b1a855c..b201ddb 100644 --- a/openbsc/src/gprs/slhc.c +++ b/openbsc/src/gprs/slhc.c @@ -50,62 +50,71 @@ * driver code belonging close to PPP and SLIP */ -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#ifdef CONFIG_INET -/* Entire module is for IP only */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +static uint8_t *encode(uint8_t *cp, uint16_t n); +static long decode(uint8_t **cpp); +static uint8_t * put16(uint8_t *cp, uint16_t x); +static uint16_t pull16(uint8_t **cpp); -static unsigned char *encode(unsigned char *cp, unsigned short n); -static long decode(unsigned char **cpp); -static unsigned char * put16(unsigned char *cp, unsigned short x); -static unsigned short pull16(unsigned char **cpp); + +/* Replacement for kernel space function ip_fast_csum() */ +static uint16_t ip_fast_csum(uint8_t *iph, int ihl) +{ + int i; + uint16_t temp; + uint32_t accumulator = 0xFFFF; + + for(i=0;i0xFFFF) + { + accumulator++; + accumulator&=0xFFFF; + } + } + + return (uint16_t)(htons(~accumulator)&0xFFFF); +} + +/* Replacement for kernel space function put_unaligned() */ +static void put_unaligned(uint16_t val, void *ptr) +{ + memcpy(ptr,&val,sizeof(val)); +} + /* Initialize compression data structure * slots must be in range 0 to 255 (zero meaning no compression) */ -struct slcompress * -slhc_init(int rslots, int tslots) +struct slcompress *slhc_init(int rslots, int tslots) { register short i; register struct cstate *ts; struct slcompress *comp; - MOD_INC_USE_COUNT; - comp = (struct slcompress *)kmalloc(sizeof(struct slcompress), - GFP_KERNEL); + comp = (struct slcompress *)talloc_zero_size(NULL,sizeof(struct slcompress)); if (! comp) goto out_fail; memset(comp, 0, sizeof(struct slcompress)); if ( rslots > 0 && rslots < 256 ) { size_t rsize = rslots * sizeof(struct cstate); - comp->rstate = (struct cstate *) kmalloc(rsize, GFP_KERNEL); + comp->rstate = (struct cstate *) talloc_zero_size(NULL, rsize); if (! comp->rstate) goto out_free; memset(comp->rstate, 0, rsize); @@ -114,7 +123,7 @@ if ( tslots > 0 && tslots < 256 ) { size_t tsize = tslots * sizeof(struct cstate); - comp->tstate = (struct cstate *) kmalloc(tsize, GFP_KERNEL); + comp->tstate = (struct cstate *) talloc_zero_size(NULL, tsize); if (! comp->tstate) goto out_free2; memset(comp->tstate, 0, tsize); @@ -144,36 +153,34 @@ return comp; out_free2: - kfree((unsigned char *)comp->rstate); + talloc_free((uint8_t *)comp->rstate); out_free: - kfree((unsigned char *)comp); + talloc_free((uint8_t *)comp); out_fail: - MOD_DEC_USE_COUNT; + + return NULL; } - /* Free a compression data structure */ -void -slhc_free(struct slcompress *comp) +void slhc_free(struct slcompress *comp) { + LOGP(DSLHC, LOGL_DEBUG, "slhc_free(): Freeing compression states...\n"); + if ( comp == NULLSLCOMPR ) return; if ( comp->tstate != NULLSLSTATE ) - kfree( comp->tstate ); + talloc_free(comp->tstate ); if ( comp->rstate != NULLSLSTATE ) - kfree( comp->rstate ); + talloc_free( comp->rstate ); - kfree( comp ); - MOD_DEC_USE_COUNT; + talloc_free( comp ); } - /* Put a short in host order into a char array in network order */ -static inline unsigned char * -put16(unsigned char *cp, unsigned short x) +static inline uint8_t *put16(uint8_t *cp, uint16_t x) { *cp++ = x >> 8; *cp++ = x; @@ -183,8 +190,7 @@ /* Encode a number */ -unsigned char * -encode(unsigned char *cp, unsigned short n) +uint8_t *encode(uint8_t *cp, uint16_t n) { if(n >= 256 || n == 0){ *cp++ = 0; @@ -196,8 +202,7 @@ } /* Pull a 16-bit integer in host order from buffer in network byte order */ -static unsigned short -pull16(unsigned char **cpp) +static uint16_t pull16(uint8_t **cpp) { short rval; @@ -208,8 +213,7 @@ } /* Decode a number */ -long -decode(unsigned char **cpp) +long decode(uint8_t **cpp) { register int x; @@ -228,9 +232,7 @@ * change it to ocp. */ -int -slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, - unsigned char *ocp, unsigned char **cpp, int compress_cid) +int slhc_compress(struct slcompress *comp, uint8_t *icp, int isize, uint8_t *ocp, uint8_t **cpp, int compress_cid) { register struct cstate *ocs = &(comp->tstate[comp->xmit_oldest]); register struct cstate *lcs = ocs; @@ -238,11 +240,10 @@ register unsigned long deltaS, deltaA; register short changes = 0; int hlen; - unsigned char new_seq[16]; - register unsigned char *cp = new_seq; + uint8_t new_seq[16]; + register uint8_t *cp = new_seq; struct iphdr *ip; struct tcphdr *th, *oth; - /* * Don't play with runt packets. @@ -260,11 +261,12 @@ comp->sls_o_nontcp++; else comp->sls_o_tcp++; + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Not a TCP packat, will not touch...\n"); return isize; } - /* Extract TCP header */ - th = (struct tcphdr *)(((unsigned char *)ip) + ip->ihl*4); + /* Extract TCP header */ + th = (struct tcphdr *)(((uint8_t *)ip) + ip->ihl*4); hlen = ip->ihl*4 + th->doff*4; /* Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or @@ -275,8 +277,10 @@ ! (th->ack)){ /* TCP connection stuff; send as regular IP */ comp->sls_o_tcp++; + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Packet is part of a TCP connection, will not touch...\n"); return isize; } + /* * Packet is compressible -- we're going to send either a * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way, @@ -291,6 +295,9 @@ * states via linear search. If we don't find a state * for the datagram, the oldest state is (re-)used. */ + + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Compressible packet detected!\n"); + for ( ; ; ) { if( ip->saddr == cs->cs_ip.saddr && ip->daddr == cs->cs_ip.daddr @@ -314,11 +321,14 @@ * state points to the newest and we only need to set * xmit_oldest to update the lru linkage. */ + + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Header not yet seen, will memorize header for the next turn...\n"); comp->sls_o_misses++; comp->xmit_oldest = lcs->cs_this; goto uncompressed; found: + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Header already seen, trying to compress...\n"); /* * Found it -- move to the front on the connection list. */ @@ -348,6 +358,7 @@ */ oth = &cs->cs_tcp; + if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl || ip->tos != cs->cs_ip.tos || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000)) @@ -355,6 +366,7 @@ || th->doff != cs->cs_tcp.doff || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){ + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): The header contains unexpected changes, can't compress...\n"); goto uncompressed; } @@ -373,6 +385,7 @@ * implementation should never do this but RFC793 * doesn't prohibit the change so we have to deal * with it. */ + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): URG not set but urp changed, can't compress...\n"); goto uncompressed; } if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){ @@ -381,13 +394,19 @@ } if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){ if(deltaA > 0x0000ffff) + { + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): (deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L, can't compress...\n"); goto uncompressed; + } cp = encode(cp,deltaA); changes |= NEW_A; } if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){ if(deltaS > 0x0000ffff) + { + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): (deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L, can't compress...\n"); goto uncompressed; + } cp = encode(cp,deltaS); changes |= NEW_S; } @@ -403,6 +422,7 @@ if(ip->tot_len != cs->cs_ip.tot_len && ntohs(cs->cs_ip.tot_len) == hlen) break; + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Retransmitted packet detected, can't compress...\n"); goto uncompressed; break; case SPECIAL_I: @@ -410,6 +430,7 @@ /* actual changes match one of our special case encodings -- * send packet uncompressed. */ + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Special case detected, can't compress...\n"); goto uncompressed; case NEW_S|NEW_A: if(deltaS == deltaA && @@ -438,7 +459,6 @@ * state with this packet's header. */ deltaA = ntohs(th->check); - memcpy(&cs->cs_ip,ip,20); memcpy(&cs->cs_tcp,th,20); /* We want to use the original packet as our compressed packet. * (cp - new_seq) is the number of bytes we need for compressed @@ -471,6 +491,7 @@ * to use on future compressed packets in the protocol field). */ uncompressed: + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Packet will be sent uncompressed...\n"); memcpy(&cs->cs_ip,ip,20); memcpy(&cs->cs_tcp,th,20); if (ip->ihl > 5) @@ -487,8 +508,7 @@ } -int -slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) +int slhc_uncompress(struct slcompress *comp, uint8_t *icp, int isize) { register int changes; long x; @@ -496,7 +516,7 @@ register struct iphdr *ip; register struct cstate *cs; int len, hdrlen; - unsigned char *cp = icp; + uint8_t *cp = icp; /* We've got a compressed packet; read the change byte */ comp->sls_i_compressed++; @@ -544,6 +564,8 @@ switch(changes & SPECIALS_MASK){ case SPECIAL_I: /* Echoed terminal traffic */ + LOGP(DSLHC, LOGL_DEBUG, "slhc_uncompress(): Echoed terminal traffic detected\n"); + { register short i; i = ntohs(ip->tot_len) - hdrlen; @@ -553,11 +575,13 @@ break; case SPECIAL_D: /* Unidirectional data */ + LOGP(DSLHC, LOGL_DEBUG, "slhc_uncompress(): Unidirectional data detected\n"); thp->seq = htonl( ntohl(thp->seq) + ntohs(ip->tot_len) - hdrlen); break; default: + LOGP(DSLHC, LOGL_DEBUG, "slhc_uncompress(): default packet type detected\n"); if(changes & NEW_U){ thp->urg = 1; if((x = decode(&cp)) == -1) { @@ -607,6 +631,7 @@ ip->tot_len = htons(len); ip->check = 0; + LOGP(DSLHC, LOGL_DEBUG, "slhc_uncompress(): making space for the reconstructed header...\n"); memmove(icp + hdrlen, cp, len - hdrlen); cp = icp; @@ -618,8 +643,7 @@ cp += (ip->ihl - 5) * 4; } - put_unaligned(ip_fast_csum(icp, ip->ihl), - &((struct iphdr *)icp)->check); + put_unaligned(ip_fast_csum(icp, ip->ihl), &((struct iphdr *)icp)->check); memcpy(cp, thp, 20); cp += 20; @@ -631,22 +655,24 @@ return len; bad: + LOGP(DSLHC, LOGL_DEBUG, "slhc_uncompress(): bad packet detected!\n"); comp->sls_i_error++; return slhc_toss( comp ); } -int -slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +int slhc_remember(struct slcompress *comp, uint8_t *icp, int isize) { register struct cstate *cs; unsigned ihl; - unsigned char index; + uint8_t index; + uint16_t checksum; if(isize < 20) { /* The packet is shorter than a legal IP header */ comp->sls_i_runt++; + LOGP(DSLHC, LOGL_DEBUG, "slhc_remember(): The packet is shorter than a legal IP header ==> slhc_toss()\n"); return slhc_toss( comp ); } /* Peek at the IP header's IHL field to find its length */ @@ -654,18 +680,23 @@ if(ihl < 20 / 4){ /* The IP header length field is too small */ comp->sls_i_runt++; + LOGP(DSLHC, LOGL_DEBUG, "slhc_remember(): The IP header length field is too small ==> slhc_toss()\n"); return slhc_toss( comp ); } + index = icp[9]; icp[9] = IPPROTO_TCP; + checksum = ip_fast_csum(icp, ihl); - if (ip_fast_csum(icp, ihl)) { + if (checksum) { /* Bad IP header checksum; discard */ comp->sls_i_badcheck++; + LOGP(DSLHC, LOGL_DEBUG, "slhc_remember(): Bad IP header checksum; discard ==> slhc_toss()\n"); return slhc_toss( comp ); } if(index > comp->rslot_limit) { comp->sls_i_error++; + LOGP(DSLHC, LOGL_DEBUG, "slhc_remember(): index > comp->rslot_limit ==> slhc_toss()\n"); return slhc_toss(comp); } @@ -686,10 +717,9 @@ return isize; } - -int -slhc_toss(struct slcompress *comp) +int slhc_toss(struct slcompress *comp) { + LOGP(DSLHC, LOGL_DEBUG, "slhc_toss(): Reset compression state...\n"); if ( comp == NULLSLCOMPR ) return 0; @@ -697,11 +727,10 @@ return 0; } - void slhc_i_status(struct slcompress *comp) { if (comp != NULLSLCOMPR) { - printk("\t%d Cmp, %d Uncmp, %d Bad, %d Tossed\n", + LOGP(DSLHC, LOGL_DEBUG, "slhc_i_status(): %d Cmp, %d Uncmp, %d Bad, %d Tossed\n", comp->sls_i_compressed, comp->sls_i_uncompressed, comp->sls_i_error, @@ -709,92 +738,16 @@ } } - void slhc_o_status(struct slcompress *comp) { if (comp != NULLSLCOMPR) { - printk("\t%d Cmp, %d Uncmp, %d AsIs, %d NotTCP\n", + LOGP(DSLHC, LOGL_DEBUG, "slhc_o_status(): %d Cmp, %d Uncmp, %d AsIs, %d NotTCP %d Searches, %d Misses\n", comp->sls_o_compressed, comp->sls_o_uncompressed, comp->sls_o_tcp, - comp->sls_o_nontcp); - printk("\t%10d Searches, %10d Misses\n", + comp->sls_o_nontcp, comp->sls_o_searches, comp->sls_o_misses); } } -/* Should this be surrounded with "#ifdef CONFIG_MODULES" ? */ -/* VJ header compression */ -EXPORT_SYMBOL(slhc_init); -EXPORT_SYMBOL(slhc_free); -EXPORT_SYMBOL(slhc_remember); -EXPORT_SYMBOL(slhc_compress); -EXPORT_SYMBOL(slhc_uncompress); -EXPORT_SYMBOL(slhc_toss); - -#ifdef MODULE - -int init_module(void) -{ - printk(KERN_INFO "CSLIP: code copyright 1989 Regents of the University of California\n"); - return 0; -} - -void cleanup_module(void) -{ - return; -} - -#endif /* MODULE */ -#else /* CONFIG_INET */ - - -int -slhc_toss(struct slcompress *comp) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss"); - return -EINVAL; -} -int -slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress"); - return -EINVAL; -} -int -slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, - unsigned char *ocp, unsigned char **cpp, int compress_cid) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress"); - return -EINVAL; -} - -int -slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember"); - return -EINVAL; -} - -void -slhc_free(struct slcompress *comp) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free"); - return; -} -struct slcompress * -slhc_init(int rslots, int tslots) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init"); - return NULL; -} -EXPORT_SYMBOL(slhc_init); -EXPORT_SYMBOL(slhc_free); -EXPORT_SYMBOL(slhc_remember); -EXPORT_SYMBOL(slhc_compress); -EXPORT_SYMBOL(slhc_uncompress); -EXPORT_SYMBOL(slhc_toss); - -#endif /* CONFIG_INET */ -MODULE_LICENSE("Dual BSD/GPL"); -- To view, visit https://gerrit.osmocom.org/635 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 Gerrit-PatchSet: 3 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Fri Aug 5 11:28:08 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Fri, 5 Aug 2016 11:28:08 +0000 Subject: [PATCH] openbsc[master]: For some reason gprs_sndcp.h was located in src/gprs. It has... In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/636 to look at the new patch set (#3). For some reason gprs_sndcp.h was located in src/gprs. It has now been moved to include Change-Id: If4e4f1252c81d7907c1b4d738c982bb172b128c9 --- R openbsc/include/openbsc/gprs_sndcp.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/gprs_sndcp.c M openbsc/src/gprs/gprs_sndcp_vty.c 4 files changed, 2 insertions(+), 6 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/36/636/3 diff --git a/openbsc/src/gprs/gprs_sndcp.h b/openbsc/include/openbsc/gprs_sndcp.h similarity index 100% rename from openbsc/src/gprs/gprs_sndcp.h rename to openbsc/include/openbsc/gprs_sndcp.h diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 548b38c..a118a19 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -6,8 +6,6 @@ OSMO_LIBS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) \ $(LIBOSMOCTRL_LIBS) $(LIBOSMOGB_LIBS) -noinst_HEADERS = gprs_sndcp.h - bin_PROGRAMS = osmo-gbproxy if HAVE_LIBGTP diff --git a/openbsc/src/gprs/gprs_sndcp.c b/openbsc/src/gprs/gprs_sndcp.c index 75f95c9..4f71121 100644 --- a/openbsc/src/gprs/gprs_sndcp.c +++ b/openbsc/src/gprs/gprs_sndcp.c @@ -34,8 +34,7 @@ #include #include #include - -#include "gprs_sndcp.h" +#include /* Chapter 7.2: SN-PDU Formats */ struct sndcp_common_hdr { diff --git a/openbsc/src/gprs/gprs_sndcp_vty.c b/openbsc/src/gprs/gprs_sndcp_vty.c index deeef07..430881f 100644 --- a/openbsc/src/gprs/gprs_sndcp_vty.c +++ b/openbsc/src/gprs/gprs_sndcp_vty.c @@ -35,8 +35,7 @@ #include #include #include - -#include "gprs_sndcp.h" +#include #include #include -- To view, visit https://gerrit.osmocom.org/636 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: If4e4f1252c81d7907c1b4d738c982bb172b128c9 Gerrit-PatchSet: 3 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Fri Aug 5 11:28:08 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Fri, 5 Aug 2016 11:28:08 +0000 Subject: [PATCH] openbsc[master]: XID related modifications in LLC In-Reply-To: References: Message-ID: Hello Harald Welte, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/652 to look at the new patch set (#6). XID related modifications in LLC With this commit the already existing XID mechanism has been modified to suit the needs for the upcomming SNDCP-XID patches. The SNDCP-XID related calls are currently disabled since the necessary patches for gprs_sndcp.c are not yet pushed. This commit should not break anything since it does not alter the current behaviour (incoming XID is still just echoed, on GMM-Reset a basic XID message is still echoed) Change-Id: I65b9d625e72d3d61c99abdc7041773701d694d52 --- M openbsc/include/openbsc/gprs_llc.h M openbsc/src/gprs/gprs_llc.c M openbsc/src/gprs/v42bis.c M openbsc/tests/sgsn/Makefile.am 4 files changed, 359 insertions(+), 74 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/52/652/6 diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h index 39d17f4..8b93784 100644 --- a/openbsc/include/openbsc/gprs_llc.h +++ b/openbsc/include/openbsc/gprs_llc.h @@ -4,6 +4,7 @@ #include #include #include +#include /* Section 4.7 LLC Layer Structure */ enum gprs_llc_sapi { @@ -148,10 +149,8 @@ /* Lists holding the compression entities */ struct comp_ent { - /* - * In this two list_heads we will store the data and protocol - * compression entities, together with their compression states - */ + /* In this two list_heads we will store the data and protocol + * compression entities, together with their compression states */ struct llist_head proto; struct llist_head data; }; @@ -235,6 +234,10 @@ int gprs_llgmm_reset_oldmsg(struct msgb* oldmsg, uint8_t sapi, struct gprs_llc_llme *llme); +/* Set of LL-XID negotiation (See also: TS 101 351, Section 7.2.2.4) */ +int gprs_ll_xid_req(struct gprs_llc_lle *lle, + struct gprs_llc_xid_field *l3_xid_field); + /* 04.64 Chapter 7.2.1.1 LLGMM-ASSIGN */ int gprs_llgmm_assign(struct gprs_llc_llme *llme, uint32_t old_tlli, uint32_t new_tlli); diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c index 7724ebb..9e85f63 100644 --- a/openbsc/src/gprs/gprs_llc.c +++ b/openbsc/src/gprs/gprs_llc.c @@ -38,8 +38,312 @@ #include #include #include +#include +#include +#include + + +/* FIXME: Remove this switch as soon as the XID integration in + * gprs_sndcp.c h is done */ +#define WITH_SNDCP_XID 1 static struct gprs_llc_llme *llme_alloc(uint32_t tlli); +static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg, + int command); +static int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi, + int command, enum gprs_llc_u_cmd u_cmd, int pf_bit); + +/* BEGIN XID RELATED */ + +/* Generate XID message */ +static int gprs_llc_generate_xid(uint8_t *bytes, int bytes_len, + struct gprs_llc_xid_field *l3_xid_field, + struct gprs_llc_llme *llme) +{ + /* Note: Called by gprs_ll_xid_req() */ + + LLIST_HEAD(xid_fields); + + struct gprs_llc_xid_field xid_version; + struct gprs_llc_xid_field xid_n201u; + struct gprs_llc_xid_field xid_n201i; + + xid_version.type = GPRS_LLC_XID_T_VERSION; + xid_version.data = (uint8_t *) "\x00"; + xid_version.data_len = 1; + + xid_n201u.type = GPRS_LLC_XID_T_N201_U; + xid_n201u.data = (uint8_t *) "\x05\xf0"; + xid_n201u.data_len = 2; + + xid_n201i.type = GPRS_LLC_XID_T_N201_I; + xid_n201i.data = (uint8_t *) "\x05\xf0"; + xid_n201i.data_len = 2; + + /* Add layer 3 XID field (if present) */ + if (l3_xid_field) { + /* Enforce layer 3 XID type (just to be sure) */ + l3_xid_field->type = GPRS_LLC_XID_T_L3_PAR; + + /* Add Layer 3 XID field to the list */ + llist_add(&l3_xid_field->list, &xid_fields); + } + + /* Add locally managed XID Fields */ + llist_add(&xid_n201i.list, &xid_fields); + llist_add(&xid_n201u.list, &xid_fields); + llist_add(&xid_version.list, &xid_fields); + + gprs_llc_copy_xid(&llme->xid, &xid_fields); + + return gprs_llc_compile_xid(&xid_fields, bytes, bytes_len); +} + +/* Generate XID message that will cause the GMM to reset */ +static int gprs_llc_generate_xid_for_gmm_reset(uint8_t *bytes, + int bytes_len, uint32_t iov_ui, + struct gprs_llc_llme *llme) +{ + /* Called by gprs_llgmm_reset() and + * gprs_llgmm_reset_oldmsg() */ + + LLIST_HEAD(xid_fields); + + struct gprs_llc_xid_field xid_reset; + struct gprs_llc_xid_field xid_iovui; + + /* First XID component must be RESET */ + xid_reset.type = GPRS_LLC_XID_T_RESET; + xid_reset.data = NULL; + xid_reset.data_len = 0; + + /* Add new IOV-UI */ + xid_iovui.type = GPRS_LLC_XID_T_IOV_UI; + xid_iovui.data = (uint8_t *) & iov_ui; + xid_iovui.data_len = 4; + + /* Add locally managed XID Fields */ + llist_add(&xid_iovui.list, &xid_fields); + llist_add(&xid_reset.list, &xid_fields); + + gprs_llc_copy_xid(&llme->xid, &xid_fields); + + return gprs_llc_compile_xid(&xid_fields, bytes, bytes_len); +} + +/* Process an incoming XID confirmation */ +static int gprs_llc_process_xid_conf(uint8_t *bytes, int bytes_len, + struct gprs_llc_lle *lle) +{ + /* Note: This function handles the response of a network originated + * XID-Request. There XID messages reflected by the phone are analyzed + * and processed here. The caller is called by rx_llc_xid(). */ + + int rc; + LLIST_HEAD(xid_fields); + struct gprs_llc_xid_field *xid_field; + struct gprs_llc_xid_field *xid_field_request; + struct gprs_llc_xid_field *xid_field_request_l3 = NULL; + + /* Pick layer3 XID from the XID request we have sent last */ + llist_for_each_entry(xid_field_request, &lle->llme->xid, list) { + if (xid_field_request->type == GPRS_LLC_XID_T_L3_PAR) + xid_field_request_l3 = xid_field_request; + } + + /* Parse and analyze XID-Response */ + rc = gprs_llc_parse_xid(&xid_fields, bytes, bytes_len); + if (rc == 0) { + gprs_llc_dump_xid_fields(&xid_fields, LOGL_DEBUG); + + llist_for_each_entry(xid_field, &xid_fields, list) { + + /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { +#if WITH_SNDCP_XID == 1 + sndcp_sn_xid_conf(xid_field, + xid_field_request_l3, + lle); +#endif + } + + /* Process LLC-XID fields: */ + else { + + /* FIXME: Do something more useful with the + * echoed XID-Information. Currently we + * just ignore the response completely and + * by doing so we blindly accept any changes + * the MS might have done to the our XID + * inquiry. There is a remainig risk of + * malfunction! */ + LOGP(DLLC, LOGL_NOTICE, + "Ignoring XID-Field: XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + xid_field->data); + + } + } + } + + /* Flush pending XID fields */ + gprs_llc_free_xid(&lle->llme->xid); + + return 0; +} + + +/* Process an incoming XID indication and generate an appropiate response */ +static int gprs_llc_process_xid_ind(uint8_t *bytes_request, + int bytes_request_len, + uint8_t *bytes_response, + int bytes_response_maxlen, + struct gprs_llc_lle *lle) +{ + /* Note: This function computes the response that is sent back to the + * phone when a phone originated XID is received. The function is + * called by rx_llc_xid() */ + + int rc; + LLIST_HEAD(xid_fields); + LLIST_HEAD(xid_fields_response); + + struct gprs_llc_xid_field *xid_field; + struct gprs_llc_xid_field *xid_field_response; + + /* Flush eventually pending XID fields */ + gprs_llc_free_xid(&lle->llme->xid); + + /* Parse and analyze XID-Request */ + rc = gprs_llc_parse_xid(&xid_fields, bytes_request, + bytes_request_len); + if (rc == 0) { + gprs_llc_dump_xid_fields(&xid_fields, LOGL_DEBUG); + + llist_for_each_entry(xid_field, &xid_fields, list) { + /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { +#if WITH_SNDCP_XID == 1 + xid_field_response = + talloc_zero(NULL, + struct gprs_llc_xid_field); + rc = sndcp_sn_xid_ind(xid_field, + xid_field_response, + lle); + if (rc == 0) + llist_add(&xid_field_response-> + list, + &xid_fields_response); + else + talloc_free(xid_field_response); +#endif + } + + /* Process LLC-XID fields: */ + else { + /* FIXME: Check the incoming XID parameters for + * for validity. Currently we just blindly + * accept all XID fields by just echoing them. + * There is a remaining risk of malfunction + * when a phone submits values which defer from + * the default! */ + LOGP(DLLC, LOGL_NOTICE, + "Echoing XID-Field: XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + osmo_hexdump_nospc(xid_field->data, + xid_field-> + data_len)); + xid_field_response = + gprs_llc_duplicate_xid_field + (xid_field); + llist_add(&xid_field_response->list, + &xid_fields_response); + } + } + + rc = gprs_llc_compile_xid(&xid_fields_response, + bytes_response, + bytes_response_maxlen); + gprs_llc_free_xid(&xid_fields_response); + } + gprs_llc_free_xid(&xid_fields); + + return rc; +} + +/* Dispatch XID indications and responses comming from the Phone */ +static void rx_llc_xid(struct gprs_llc_lle *lle, + struct gprs_llc_hdr_parsed *gph) +{ + uint8_t response[1024]; + int response_len; + + /* FIXME: 8.5.3.3: check if XID is invalid */ + if (gph->is_cmd) { + LOGP(DLLC, LOGL_NOTICE, + "Received XID indication from phone.\n"); + + struct msgb *resp; + uint8_t *xid; + resp = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + + response_len = + gprs_llc_process_xid_ind(gph->data, gph->data_len, + response, sizeof(response), + lle); + xid = msgb_put(resp, response_len); + memcpy(xid, response, response_len); + + gprs_llc_tx_xid(lle, resp, 0); + } else { + LOGP(DLLC, LOGL_NOTICE, + "Received XID confirmation from phone.\n"); + gprs_llc_process_xid_conf(gph->data, gph->data_len, lle); + /* FIXME: if we had sent a XID reset, send + * LLGMM-RESET.conf to GMM */ + } +} + + +/* Set of LL-XID negotiation (See also: TS 101 351, Section 7.2.2.4) */ +int gprs_ll_xid_req(struct gprs_llc_lle *lle, + struct gprs_llc_xid_field *l3_xid_field) +{ + /* Note: This functions is calle from gprs_sndcp.c */ + + uint8_t xid_bytes[1024];; + int xid_bytes_len; + uint8_t *xid; + struct msgb *msg; + + /* Generate XID */ + xid_bytes_len = + gprs_llc_generate_xid(xid_bytes, sizeof(xid_bytes), + l3_xid_field, lle->llme); + + + /* Only perform XID sending if the XID message contains something */ + if (xid_bytes_len > 0) { + /* Transmit XID bytes */ + msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); + LOGP(DLLC, LOGL_NOTICE, + "Sending XID request to phone...\n"); + gprs_llc_tx_xid(lle, msg, 1); + } else { + LOGP(DLLC, LOGL_ERROR, + "XID-Message generation failed, XID not sent!\n"); + return -EINVAL; + } + + return 0; +} + +/* END XID RELATED */ + + + /* Entry function from upper level (LLC), asking us to transmit a BSSGP PDU * to a remote MS (identified by TLLI) at a BTS identified by its BVCI and NSEI */ @@ -51,7 +355,7 @@ memset(&dup, 0, sizeof(dup)); /* before we have received some identity from the MS, we might * not yet have a MMC context (e.g. XID negotiation of primarly - * LLC connection fro GMM sapi). */ + * LLC connection from GMM sapi). */ if (mmctx) { dup.imsi = mmctx->imsi; dup.drx_parms = mmctx->drx_parms; @@ -246,11 +550,18 @@ llist_add(&llme->list, &gprs_llc_llmes); + INIT_LLIST_HEAD(&llme->comp.proto); + INIT_LLIST_HEAD(&llme->comp.data); + INIT_LLIST_HEAD(&llme->xid); + return llme; } static void llme_free(struct gprs_llc_llme *llme) { + gprs_sndcp_comp_entities_free(&llme->comp.proto); + gprs_sndcp_comp_entities_free(&llme->comp.data); + gprs_llc_free_xid(&llme->xid); llist_del(&llme->list); talloc_free(llme); } @@ -464,54 +775,6 @@ /* Send BSSGP-DL-UNITDATA.req */ return _bssgp_tx_dl_ud(msg, mmctx); -} - -/* According to 6.4.1.6 / Figure 11 */ -static int msgb_put_xid_par(struct msgb *msg, uint8_t type, uint8_t length, uint8_t *data) -{ - uint8_t header_len = 1; - uint8_t *cur; - - /* type is a 5-bit field... */ - if (type > 0x1f) - return -EINVAL; - - if (length > 3) - header_len = 2; - - cur = msgb_put(msg, length + header_len); - - /* build the header without or with XL bit */ - if (length <= 3) { - *cur++ = (type << 2) | (length & 3); - } else { - *cur++ = 0x80 | (type << 2) | (length >> 6); - *cur++ = (length << 2); - } - - /* copy over the payload of the parameter*/ - memcpy(cur, data, length); - - return length + header_len; -} - -static void rx_llc_xid(struct gprs_llc_lle *lle, - struct gprs_llc_hdr_parsed *gph) -{ - /* FIXME: 8.5.3.3: check if XID is invalid */ - if (gph->is_cmd) { - /* FIXME: implement XID negotiation using SNDCP */ - struct msgb *resp; - uint8_t *xid; - resp = msgb_alloc_headroom(4096, 1024, "LLC_XID"); - xid = msgb_put(resp, gph->data_len); - memcpy(xid, gph->data, gph->data_len); - gprs_llc_tx_xid(lle, resp, 0); - } else { - /* FIXME: if we had sent a XID reset, send - * LLGMM-RESET.conf to GMM */ - /* FIXME: implement XID negotiation using SNDCP */ - } } static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph, @@ -784,17 +1047,24 @@ { struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); struct gprs_llc_lle *lle = &llme->lle[1]; + uint8_t xid_bytes[1024]; + int xid_bytes_len; + uint8_t *xid; + LOGP(DLLC, LOGL_NOTICE, "LLGM Reset\n"); if (RAND_bytes((uint8_t *) &llme->iov_ui, 4) != 1) { LOGP(DLLC, LOGL_NOTICE, "RAND_bytes failed for LLC XID reset, " "falling back to rand()\n"); llme->iov_ui = rand(); } - /* First XID component must be RESET */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL); - /* randomly select new IOV-UI */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &llme->iov_ui); + /* Generate XID message */ + xid_bytes_len = gprs_llc_generate_xid_for_gmm_reset(xid_bytes, + sizeof(xid_bytes),llme->iov_ui,llme); + if(xid_bytes_len < 0) + return -EINVAL; + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); /* Reset some of the LLC parameters. See GSM 04.64, 8.5.3.1 */ lle->vu_recv = 0; @@ -810,17 +1080,24 @@ struct gprs_llc_llme *llme) { struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + uint8_t xid_bytes[1024]; + int xid_bytes_len; + uint8_t *xid; + LOGP(DLLC, LOGL_NOTICE, "LLGM Reset\n"); if (RAND_bytes((uint8_t *) &llme->iov_ui, 4) != 1) { LOGP(DLLC, LOGL_NOTICE, "RAND_bytes failed for LLC XID reset, " "falling back to rand()\n"); llme->iov_ui = rand(); } - /* First XID component must be RESET */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL); - /* randomly select new IOV-UI */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &llme->iov_ui); + /* Generate XID message */ + xid_bytes_len = gprs_llc_generate_xid_for_gmm_reset(xid_bytes, + sizeof(xid_bytes),llme->iov_ui,llme); + if(xid_bytes_len < 0) + return -EINVAL; + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); /* FIXME: Start T200, wait for XID response */ diff --git a/openbsc/src/gprs/v42bis.c b/openbsc/src/gprs/v42bis.c index a306107..65d8814 100644 --- a/openbsc/src/gprs/v42bis.c +++ b/openbsc/src/gprs/v42bis.c @@ -306,7 +306,7 @@ { if (ss->transparent) { - printf("Going compressed\n"); + DEBUGP(DV42BIS,"Going compressed\n"); /* 7.8.1 Transition to compressed mode */ /* Switch out of transparent now, between codes. We need to send the octet which did not match, just before switching. */ @@ -328,7 +328,7 @@ { if (!ss->transparent) { - printf("Going transparent\n"); + DEBUGP(DV42BIS,"Going transparent\n"); /* 7.8.2 Transition to transparent mode */ /* Switch into transparent now, between codes, and the unmatched octet should go out in transparent mode, just below */ @@ -397,7 +397,7 @@ { if (s->compress.dict[i].parent_code != 0xFFFF) { - printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); + DEBUGP(DV42BIS,"Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); } } return 0; @@ -450,13 +450,13 @@ ss->escaped = FALSE; if (code == V42BIS_ECM) { - printf("Hit V42BIS_ECM\n"); + DEBUGP(DV42BIS,"Hit V42BIS_ECM\n"); ss->transparent = FALSE; code_len = ss->v42bis_parm_c2; } else if (code == V42BIS_EID) { - printf("Hit V42BIS_EID\n"); + DEBUGP(DV42BIS,"Hit V42BIS_EID\n"); ss->output_buf[ss->output_octet_count++] = ss->escape_code - 1; if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) { @@ -466,11 +466,11 @@ } else if (code == V42BIS_RESET) { - printf("Hit V42BIS_RESET\n"); + DEBUGP(DV42BIS,"Hit V42BIS_RESET\n"); } else { - printf("Hit V42BIS_???? - %" PRIu32 "\n", code); + DEBUGP(DV42BIS,"Hit V42BIS_???? - %" PRIu32 "\n", code); } } else if (code == ss->escape_code) @@ -496,17 +496,17 @@ switch (new_code) { case V42BIS_ETM: - printf("Hit V42BIS_ETM\n"); + DEBUGP(DV42BIS,"Hit V42BIS_ETM\n"); ss->transparent = TRUE; code_len = 8; break; case V42BIS_FLUSH: - printf("Hit V42BIS_FLUSH\n"); + DEBUGP(DV42BIS,"Hit V42BIS_FLUSH\n"); v42bis_decompress_flush(s); break; case V42BIS_STEPUP: /* We need to increase the codeword size */ - printf("Hit V42BIS_STEPUP\n"); + DEBUGP(DV42BIS,"Hit V42BIS_STEPUP\n"); if (ss->v42bis_parm_c3 >= s->v42bis_parm_n2) { /* Invalid condition */ @@ -543,7 +543,7 @@ /* Trace back through the octets which form the string, and output them. */ while (code >= V42BIS_N5) { -if (code > 4095) {printf("Code is 0x%" PRIu32 "\n", code); exit(2);} +if (code > 4095) {DEBUGP(DV42BIS,"Code is 0x%" PRIu32 "\n", code); exit(2);} *string-- = ss->dict[code].node_octet; code = ss->dict[code].parent_code; } @@ -627,7 +627,7 @@ { if (s->decompress.dict[i].parent_code != 0xFFFF) { - printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); + DEBUGP(DV42BIS,"Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); } } return 0; diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index b6036c7..3b34452 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -30,6 +30,11 @@ $(top_builddir)/src/gprs/gprs_gb_parse.o \ $(top_builddir)/src/gprs/oap.o \ $(top_builddir)/src/gprs/oap_messages.o \ + $(top_builddir)/src/gprs/gprs_llc_xid.o \ + $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ + $(top_builddir)/src/gprs/gprs_sndcp_comp_entity.o \ + $(top_builddir)/src/gprs/gprs_sndcp_hdrcomp.o \ + $(top_builddir)/src/gprs/slhc.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ @@ -37,5 +42,5 @@ $(LIBOSMOGB_LIBS) \ $(LIBCARES_LIBS) \ $(LIBCRYPTO_LIBS) \ - -lgtp -lrt + -lgtp -lrt -lm -- To view, visit https://gerrit.osmocom.org/652 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I65b9d625e72d3d61c99abdc7041773701d694d52 Gerrit-PatchSet: 6 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte From gerrit-no-reply at lists.osmocom.org Fri Aug 5 11:28:08 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Fri, 5 Aug 2016 11:28:08 +0000 Subject: [PATCH] openbsc[master]: Adding LLC-XID encoder / decoder In-Reply-To: References: Message-ID: Hello Harald Welte, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/638 to look at the new patch set (#5). Adding LLC-XID encoder / decoder The lle-xid encoder/decoder is needed to encode and decode llc xid parameter messages. We need this to exchange sndcp-parameters (SNDCP-XID) and also simple parameters such as encryption IOVs Change-Id: Ia06e4cb08bf9b48c2a4682606d1b1a91d19a9d37 --- M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_llc_xid.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_llc_xid.c A openbsc/src/gprs/gprs_sndcp_comp_entity.c 5 files changed, 678 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/38/638/5 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 9ef8a15..9e8c554 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,7 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_sndcp.h slhc.h + gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_llc_xid.h b/openbsc/include/openbsc/gprs_llc_xid.h new file mode 100644 index 0000000..a4104ec --- /dev/null +++ b/openbsc/include/openbsc/gprs_llc_xid.h @@ -0,0 +1,63 @@ +/* GPRS LLC XID field encoding/decoding as per 3GPP TS 04.64 */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_LLC_XID_H +#define _GPRS_LLC_XID_H + +#include +#include + +/* TS 101 351 6.4.1.6 Exchange Identification (XID) + command/response parameter field */ +struct gprs_llc_xid_field { + struct llist_head list; + uint8_t type; /* See also Table 6: LLC layer parameter + negotiation */ + uint8_t *data; /* Payload data (octets) */ + unsigned int data_len; /* Payload length */ +}; + +/* Transform a list with XID fields into a XID message (dst) */ +int gprs_llc_compile_xid(const struct llist_head *xid_fields, uint8_t *dst, + int bytes_maxlen); + +/* Transform a XID message (dst) into a list of XID fields */ +int gprs_llc_parse_xid(struct llist_head *xid_fields, const uint8_t *src, + int bytes_len); + +/* Free llist with xid fields */ +void gprs_llc_free_xid(struct llist_head *xid_fields); + +/* Create a duplicate of an XID-Field */ +struct gprs_llc_xid_field *gprs_llc_duplicate_xid_field(const struct + gprs_llc_xid_field + *xid_field); + +/* Copy an llist with xid fields */ +void gprs_llc_copy_xid(struct llist_head *xid_fields_copy, + const struct llist_head *xid_fields_orig); + +/* Dump a list with XID fields (Debug) */ +void gprs_llc_dump_xid_fields(const struct llist_head *xid_fields, + unsigned int logl); + +#endif diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index a118a19..b3a5137 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -23,7 +23,8 @@ osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \ slhc.c \ sgsn_main.c sgsn_vty.c sgsn_libgtp.c \ - gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c crc24.c \ + gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c \ + gprs_llc_xid.c crc24.c \ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ diff --git a/openbsc/src/gprs/gprs_llc_xid.c b/openbsc/src/gprs/gprs_llc_xid.c new file mode 100644 index 0000000..e2ec163 --- /dev/null +++ b/openbsc/src/gprs/gprs_llc_xid.c @@ -0,0 +1,281 @@ +/* GPRS LLC XID field encoding/decoding as per 3GPP TS 04.64 */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +/* Parse XID parameter field */ +static int +decode_xid_field(const uint8_t *src, uint8_t src_len, + struct gprs_llc_xid_field *xid_field) +{ + uint8_t xl; + uint8_t type; + uint8_t len; + int src_counter = 0; + + /* Exit immediately if it is clear that no + parseable data is present */ + if ((src_len < 1) || !src) + return -EINVAL; + + /* Exit immediately if no result can be stored */ + if (!xid_field) + return -EINVAL; + + /* Extract header info */ + xl = (*src >> 7) & 1; + type = (*src >> 2) & 0x1F; + + /* Extract length field */ + len = (*src) & 0x3; + src++; + src_counter++; + if (xl) { + if (src_len < 2) + return -EINVAL; + len = (len << 6) & 0xC0; + len |= ((*src) >> 2) & 0x3F; + src++; + src_counter++; + } + + /* Fill out struct */ + xid_field->type = type; + xid_field->data_len = len; + if (len > 0) { + if (src_len < src_counter + len) + return -EINVAL; + xid_field->data = + talloc_zero_size(NULL, xid_field->data_len); + memcpy(xid_field->data, src, xid_field->data_len); + } else + xid_field->data = NULL; + + /* Return consumed length */ + return src_counter + len; +} + + +/* Encode XID parameter field */ +static int +encode_xid_field(uint8_t *dst, int dst_maxlen, + const struct gprs_llc_xid_field *xid_field) +{ + int xl = 0; + + /* Exit immediately if no source struct is available */ + if (!xid_field) + return -EINVAL; + + /* When the length does not fit into 2 bits, + we need extended length fields */ + if (xid_field->data_len > 3) + xl = 1; + + /* Exit immediately if it is clear that no + encoding result can be stored */ + if (dst_maxlen < xid_field->data_len + 1 + xl) + return -EINVAL; + + /* There are only 5 bits reserved for the type, exit on exceed */ + if (xid_field->type > 31) + return -EINVAL; + + /* Encode header */ + memset(dst, 0, dst_maxlen); + if (xl) + dst[0] |= 0x80; + dst[0] |= (((xid_field->type) & 0x1F) << 2); + + if (xl) { + dst[0] |= (((xid_field->data_len) >> 6) & 0x03); + dst[1] = ((xid_field->data_len) << 2) & 0xFC; + } else + dst[0] |= ((xid_field->data_len) & 0x03); + + /* Append payload data */ + if ((xid_field->data) && (xid_field->data_len)) + memcpy(dst + 1 + xl, xid_field->data, + xid_field->data_len); + + /* Return generated length */ + return xid_field->data_len + 1 + xl; +} + + +/* Transform a list with XID fields into a XID message (dst) */ +int +gprs_llc_compile_xid(const struct llist_head *xid_fields, uint8_t *dst, + int dst_maxlen) +{ + struct gprs_llc_xid_field *xid_field; + int rc; + int byte_counter = 0; + + llist_for_each_entry(xid_field, xid_fields, list) { + /* Encode XID-Field */ + rc = encode_xid_field(dst, dst_maxlen, xid_field); + if (rc < 0) + return -EINVAL; + + /* Advance pointer and lower maxlen for the + next encoding round */ + dst += rc; + byte_counter += rc; + dst_maxlen -= rc; + } + + /* Return generated length */ + return byte_counter; +} + + +/* Transform a XID message (dst) into a list of XID fields */ +int +gprs_llc_parse_xid(struct llist_head *xid_fields, const uint8_t *src, + int src_len) +{ + struct gprs_llc_xid_field *xid_field; + int rc; + int max_loops = src_len; + + while (1) { + /* Bail in case decode_xid_field() constantly returns zero */ + if (max_loops <= 0) { + gprs_llc_free_xid(xid_fields); + return -EINVAL; + } + + /* Decode XID field */ + xid_field = talloc_zero(NULL, struct gprs_llc_xid_field); + rc = decode_xid_field(src, src_len, xid_field); + + /* Immediately stop on error */ + if (rc < 0) { + gprs_llc_free_xid(xid_fields); + return -EINVAL; + } + + /* Add parsed XID field to list */ + llist_add(&xid_field->list, xid_fields); + + /* Advance pointer and lower dst_len for the next + decoding round */ + src += rc; + src_len -= rc; + + /* We are (scuccessfully) done when no further byes are left */ + if (src_len == 0) + return 0; + + max_loops--; + } +} + + +/* Free llist with xid fields */ +void gprs_llc_free_xid(struct llist_head *xid_fields) +{ + struct gprs_llc_xid_field *xid_field; + struct llist_head *lh, *lh2; + + if (xid_fields) { + llist_for_each_entry(xid_field, xid_fields, list) { + if ((xid_field->data) && (xid_field->data_len)) + talloc_free(xid_field->data); + } + + llist_for_each_safe(lh, lh2, xid_fields) { + llist_del(lh); + talloc_free(lh); + } + } +} + + +/* Create a duplicate of an XID-Field */ +struct gprs_llc_xid_field *gprs_llc_duplicate_xid_field(const struct + gprs_llc_xid_field + *xid_field) +{ + struct gprs_llc_xid_field *duplicate_of_xid_field; + + /* Create a copy of the XID field in memory */ + duplicate_of_xid_field = + talloc_zero(NULL, struct gprs_llc_xid_field); + memcpy(duplicate_of_xid_field, xid_field, + sizeof(struct gprs_llc_xid_field)); + duplicate_of_xid_field->data = + talloc_zero_size(NULL, xid_field->data_len); + memcpy(duplicate_of_xid_field->data, xid_field->data, + xid_field->data_len); + + /* Wipeout all llist information in the duplicate (just to be sure) */ + memset(&duplicate_of_xid_field->list, 0, + sizeof(struct llist_head)); + + return duplicate_of_xid_field; +} + +/* Copy an llist with xid fields */ +void gprs_llc_copy_xid(struct llist_head *xid_fields_copy, + const struct llist_head *xid_fields_orig) +{ + struct gprs_llc_xid_field *xid_field; + + /* Make sure that the target list is empty */ + gprs_llc_free_xid(xid_fields_copy); + + /* Create duplicates and add them to the target list */ + llist_for_each_entry(xid_field, xid_fields_orig, list) { + llist_add(&gprs_llc_duplicate_xid_field(xid_field)->list, xid_fields_copy); + } +} + +/* Dump a list with XID fields (Debug) */ +void gprs_llc_dump_xid_fields(const struct llist_head *xid_fields, unsigned int logl) +{ + struct gprs_llc_xid_field *xid_field; + + llist_for_each_entry(xid_field, xid_fields, list) { + LOGP(DSNDCP, logl, + "XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + osmo_hexdump_nospc(xid_field->data, + xid_field->data_len)); + } +} diff --git a/openbsc/src/gprs/gprs_sndcp_comp_entity.c b/openbsc/src/gprs/gprs_sndcp_comp_entity.c new file mode 100644 index 0000000..095a32a --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_comp_entity.c @@ -0,0 +1,331 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +/* Create a new compression entity from a XID-Field */ +static struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_create (struct gprs_sndcp_comp_field *comp_field) +{ + struct gprs_sndcp_comp_entity *comp_entity; + comp_entity = talloc_zero (NULL, struct gprs_sndcp_comp_entity); + + /* Copy relevant information from the SNDCP-XID field */ + comp_entity->entity = comp_field->entity; + comp_entity->comp_len = comp_field->comp_len; + memcpy (comp_entity->comp, comp_field->comp, + comp_field->comp_len * sizeof (int)); + + if (comp_field->rfc1144_params) { + comp_entity->nsapi_len = + comp_field->rfc1144_params->nsapi_len; + memcpy (comp_entity->nsapi, + comp_field->rfc1144_params->nsapi, + comp_entity->nsapi_len * sizeof (int)); + } + else if (comp_field->rfc2507_params) { + comp_entity->nsapi_len = + comp_field->rfc2507_params->nsapi_len; + memcpy (comp_entity->nsapi, + comp_field->rfc2507_params->nsapi, + comp_entity->nsapi_len * sizeof (int)); + } + else if (comp_field->rohc_params) { + comp_entity->nsapi_len = comp_field->rohc_params->nsapi_len; + memcpy (comp_entity->nsapi, comp_field->rohc_params->nsapi, + comp_entity->nsapi_len * sizeof (int)); + } + else if (comp_field->v42bis_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy (comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + comp_entity->nsapi_len * sizeof (int)); + } + else if (comp_field->v44_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy (comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + comp_entity->nsapi_len * sizeof (int)); + } + else { + talloc_free (comp_entity); + LOGP (DSNDCP, LOGL_ERROR, + "Comp field contained invalid parameters, compression entity not created!\n"); + return NULL; + } + + comp_entity->algo = comp_field->algo; + comp_entity->state = NULL; + + /* Determine of which class our compression entity will be + (Protocol or Data compresson ?) */ + comp_entity->compclass = + gprs_sndcp_get_compression_class (comp_field); + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + if (gprs_sndcp_hdrcomp_init (comp_entity, comp_field) == 0) + LOGP (DSNDCP, LOGL_INFO, + "New header compression entity (%i) created.\n", + comp_entity->entity); + else { + talloc_free (comp_entity); + LOGP (DSNDCP, LOGL_ERROR, + "Header compression entity (%i) creation failed!\n", + comp_entity->entity); + return NULL; + } + } + else + LOGP (DSNDCP, LOGL_INFO, + "New data compression entity (%i) created.\n", + comp_entity->entity); + + return comp_entity; +} + +/* Free a list with compression entities */ +void +gprs_sndcp_comp_entities_free (struct llist_head *comp_entities) +{ + if (comp_entities) { + struct gprs_sndcp_comp_entity *comp_entity; + + llist_for_each_entry (comp_entity, comp_entities, list) { + /* Free compression entity */ + if (comp_entity->compclass == + SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP (DSNDCP, LOGL_INFO, + "Deleting (free) header compression entity %i ...\n", + comp_entity->entity); + gprs_sndcp_hdrcomp_term (comp_entity); + } + else + LOGP (DSNDCP, LOGL_INFO, + "Deleting (free) data compression entity %i ...\n", + comp_entity->entity); + + talloc_free (comp_entity); + } + + } +} + +/* Delete a compression entity */ +void +gprs_sndcp_comp_entities_delete (struct llist_head *comp_entities, int entity) +{ + struct gprs_sndcp_comp_entity *comp_entity; + struct gprs_sndcp_comp_entity *comp_entity_to_delete = NULL; + + if (comp_entities) { + + llist_for_each_entry (comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) + comp_entity_to_delete = comp_entity; + } + + if (comp_entity_to_delete) { + if (comp_entity_to_delete->compclass == + SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP (DSNDCP, LOGL_INFO, + "Deleting header compression entity %i ...\n", + comp_entity_to_delete->entity); + gprs_sndcp_hdrcomp_term + (comp_entity_to_delete); + } + else + LOGP (DSNDCP, LOGL_INFO, + "Deleting data compression entity %i ...\n", + comp_entity_to_delete->entity); + + /* Delete compression entity */ + llist_del (&comp_entity_to_delete->list); + talloc_free (comp_entity_to_delete); + } + } +} + +/* Create and Add a new compression entity +(returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entities_add (struct + llist_head + *comp_entities, struct + gprs_sndcp_comp_field *comp_field) +{ + struct gprs_sndcp_comp_entity *comp_entity; + + /* Just to be sure, if the entity is already in + the list it will be deleted now */ + gprs_sndcp_comp_entities_delete (comp_entities, comp_field->entity); + + /* Create and add a new entity to the list */ + comp_entity = gprs_sndcp_comp_entity_create (comp_field); + + if (comp_entity) { + llist_add (&comp_entity->list, comp_entities); + return comp_entity; + } + + return NULL; +} + +/* Find compression entity by its entity number */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_entity (struct + llist_head *comp_entities, int entity) +{ + struct gprs_sndcp_comp_entity *comp_entity; + + if (comp_entities) { + llist_for_each_entry (comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) + return comp_entity; + } + } + + LOGP (DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given entity number %i.\n", + entity); + return NULL; +} + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_comp (struct + llist_head *comp_entities, int comp) +{ + struct gprs_sndcp_comp_entity *comp_entity; + int i; + + if (comp_entities) { + llist_for_each_entry (comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return comp_entity; + } + } + } + + LOGP (DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given pcomp/dcomp value %i.\n", + comp); + return NULL; +} + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_nsapi (struct + llist_head *comp_entities, int nsapi) +{ + struct gprs_sndcp_comp_entity *comp_entity; + int i; + + if (comp_entities) { + llist_for_each_entry (comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->nsapi_len; i++) { + if (comp_entity->nsapi[i] == nsapi) + return comp_entity; + } + } + + LOGP (DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given nsapi value %i\n", + nsapi); + return NULL; + } + + LOGP (DSNDCP, LOGL_ERROR, + "Compression entity list contained null-pointer!\n"); + return NULL; +} + +/* Find a comp_index for a given pcomp/dcomp value */ +int +gprs_sndcp_comp_entity_find_comp_index_by_comp (struct + gprs_sndcp_comp_entity + *comp_entity, int comp) +{ + int i; + + if (comp_entity) { + /* A pcomp/dcomp field set to zero always disables + all sort of compression and is assigned fix. So we + just return zero in this case */ + if (comp == 0) + return 0; + + /* Look in the pcomp/dcomp list for the index */ + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return i + 1; + } + + LOGP (DSNDCP, LOGL_ERROR, + "Could not find a matching comp_index for given pcomp/dcomp value %i\n", + comp); + return 0; + } + + LOGP (DSNDCP, LOGL_ERROR, + "Compression entity contained null-pointer!\n"); + return 0; +} + +/* Find a pcomp/dcomp value for a given comp_index */ +int +gprs_sndcp_comp_entity_find_comp_by_comp_index (struct + gprs_sndcp_comp_entity + *comp_entity, int comp_index) +{ + if (comp_entity) { + /* A comp_index of zero translates to zero right away. */ + if (comp_index == 0) + return 0; + + if (comp_index > comp_entity->comp_len) { + LOGP (DSNDCP, LOGL_ERROR, + "Could not find a matching pcomp/dcomp value for given comp_index value %i.\n", + comp_index); + return 0; + } + + /* Look in the pcomp/dcomp list for the comp_index */ + return comp_entity->comp[comp_index - 1]; + } + + LOGP (DSNDCP, LOGL_ERROR, + "Compression entity contained null-pointer!\n"); + return 0; +} -- To view, visit https://gerrit.osmocom.org/638 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia06e4cb08bf9b48c2a4682606d1b1a91d19a9d37 Gerrit-PatchSet: 5 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Fri Aug 5 11:41:27 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Fri, 5 Aug 2016 11:41:27 +0000 Subject: [PATCH] openbsc[master]: i Message-ID: Review at https://gerrit.osmocom.org/653 i Change-Id: I3ea5051fdbb26b48eb442fd219477930fa474ca6 --- M openbsc/src/gprs/v42bis.c 1 file changed, 0 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/53/653/1 diff --git a/openbsc/src/gprs/v42bis.c b/openbsc/src/gprs/v42bis.c index a306107..ddffa4a 100644 --- a/openbsc/src/gprs/v42bis.c +++ b/openbsc/src/gprs/v42bis.c @@ -74,7 +74,6 @@ \return The bit number of the highest set bit, or -1 if the word is zero. */ static __inline__ int top_bit(unsigned int bits) { - /* Note: This function was taken from spandsp/bit_operations.h */ int res; -- To view, visit https://gerrit.osmocom.org/653 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I3ea5051fdbb26b48eb442fd219477930fa474ca6 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter From gerrit-no-reply at lists.osmocom.org Fri Aug 5 11:46:44 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Fri, 5 Aug 2016 11:46:44 +0000 Subject: [PATCH] openbsc[master]: V42BIS integration In-Reply-To: References: Message-ID: Hello Harald Welte, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/644 to look at the new patch set (#12). V42BIS integration The previously committed SPANDSP v42bis implementation has been edited to function outside the SPANDSP library. Debug printf statements were changed into DEBUGP statements. Als removed the assembely code in top_bit(). Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d --- M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/debug.h M openbsc/include/openbsc/v42bis.h R openbsc/include/openbsc/v42bis_private.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/v42bis.c 6 files changed, 10 insertions(+), 11 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/44/644/12 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index e159db5..e404b17 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,8 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h gprs_sndcp_xid.h \ - gprs_sndcp_comp_entity.h gprs_sndcp_hdrcomp.h + gprs_sndcp_comp_entity.h gprs_sndcp_hdrcomp.h v42bis.h \ + v42bis_private.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 90ddca5..ca3d4ad 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -37,6 +37,7 @@ DGTPHUB, DRANAP, DSUA, + DV42BIS, Debug_LastEntry, }; diff --git a/openbsc/include/openbsc/v42bis.h b/openbsc/include/openbsc/v42bis.h index f13e5c5..e7592e8 100644 --- a/openbsc/include/openbsc/v42bis.h +++ b/openbsc/include/openbsc/v42bis.h @@ -36,6 +36,8 @@ #if !defined(_SPANDSP_V42BIS_H_) #define _SPANDSP_V42BIS_H_ +#define SPAN_DECLARE(x) x + #define V42BIS_MAX_BITS 12 #define V42BIS_MAX_CODEWORDS 4096 /* 2^V42BIS_MAX_BITS */ #define V42BIS_TABLE_SIZE 5021 /* This should be a prime >(2^V42BIS_MAX_BITS) */ diff --git a/openbsc/include/openbsc/private_v42bis.h b/openbsc/include/openbsc/v42bis_private.h similarity index 100% rename from openbsc/include/openbsc/private_v42bis.h rename to openbsc/include/openbsc/v42bis_private.h diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 3d6c82a..2c03a45 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -22,7 +22,7 @@ osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \ slhc.c gprs_sndcp_xid.c gprs_sndcp_comp_entity.c \ - gprs_sndcp_hdrcomp.c \ + gprs_sndcp_hdrcomp.c v42bis.c \ sgsn_main.c sgsn_vty.c sgsn_libgtp.c \ gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c \ gprs_llc_xid.c crc24.c \ diff --git a/openbsc/src/gprs/v42bis.c b/openbsc/src/gprs/v42bis.c index 6d38916..ddffa4a 100644 --- a/openbsc/src/gprs/v42bis.c +++ b/openbsc/src/gprs/v42bis.c @@ -31,9 +31,8 @@ /*! \file */ -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif +#define FALSE 0 +#define TRUE 1 #include #include @@ -44,13 +43,9 @@ #include #include -#include "spandsp/telephony.h" -#include "spandsp/logging.h" -#include "spandsp/bit_operations.h" -#include "spandsp/v42bis.h" +#include +#include -#include "spandsp/private/logging.h" -#include "spandsp/private/v42bis.h" /* Fixed parameters from the spec. */ #define V42BIS_N3 8 /* Character size (bits) */ -- To view, visit https://gerrit.osmocom.org/644 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d Gerrit-PatchSet: 12 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte From gerrit-no-reply at lists.osmocom.org Fri Aug 5 11:46:44 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Fri, 5 Aug 2016 11:46:44 +0000 Subject: [PATCH] openbsc[master]: XID related modifications in LLC In-Reply-To: References: Message-ID: Hello Harald Welte, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/652 to look at the new patch set (#8). XID related modifications in LLC With this commit the already existing XID mechanism has been modified to suit the needs for the upcomming SNDCP-XID patches. The SNDCP-XID related calls are currently disabled since the necessary patches for gprs_sndcp.c are not yet pushed. This commit should not break anything since it does not alter the current behaviour (incoming XID is still just echoed, on GMM-Reset a basic XID message is still echoed) Change-Id: I65b9d625e72d3d61c99abdc7041773701d694d52 --- M openbsc/include/openbsc/gprs_llc.h M openbsc/src/gprs/gprs_llc.c M openbsc/src/gprs/v42bis.c M openbsc/tests/sgsn/Makefile.am 4 files changed, 359 insertions(+), 74 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/52/652/8 diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h index 39d17f4..8b93784 100644 --- a/openbsc/include/openbsc/gprs_llc.h +++ b/openbsc/include/openbsc/gprs_llc.h @@ -4,6 +4,7 @@ #include #include #include +#include /* Section 4.7 LLC Layer Structure */ enum gprs_llc_sapi { @@ -148,10 +149,8 @@ /* Lists holding the compression entities */ struct comp_ent { - /* - * In this two list_heads we will store the data and protocol - * compression entities, together with their compression states - */ + /* In this two list_heads we will store the data and protocol + * compression entities, together with their compression states */ struct llist_head proto; struct llist_head data; }; @@ -235,6 +234,10 @@ int gprs_llgmm_reset_oldmsg(struct msgb* oldmsg, uint8_t sapi, struct gprs_llc_llme *llme); +/* Set of LL-XID negotiation (See also: TS 101 351, Section 7.2.2.4) */ +int gprs_ll_xid_req(struct gprs_llc_lle *lle, + struct gprs_llc_xid_field *l3_xid_field); + /* 04.64 Chapter 7.2.1.1 LLGMM-ASSIGN */ int gprs_llgmm_assign(struct gprs_llc_llme *llme, uint32_t old_tlli, uint32_t new_tlli); diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c index 7724ebb..9e85f63 100644 --- a/openbsc/src/gprs/gprs_llc.c +++ b/openbsc/src/gprs/gprs_llc.c @@ -38,8 +38,312 @@ #include #include #include +#include +#include +#include + + +/* FIXME: Remove this switch as soon as the XID integration in + * gprs_sndcp.c h is done */ +#define WITH_SNDCP_XID 1 static struct gprs_llc_llme *llme_alloc(uint32_t tlli); +static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg, + int command); +static int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi, + int command, enum gprs_llc_u_cmd u_cmd, int pf_bit); + +/* BEGIN XID RELATED */ + +/* Generate XID message */ +static int gprs_llc_generate_xid(uint8_t *bytes, int bytes_len, + struct gprs_llc_xid_field *l3_xid_field, + struct gprs_llc_llme *llme) +{ + /* Note: Called by gprs_ll_xid_req() */ + + LLIST_HEAD(xid_fields); + + struct gprs_llc_xid_field xid_version; + struct gprs_llc_xid_field xid_n201u; + struct gprs_llc_xid_field xid_n201i; + + xid_version.type = GPRS_LLC_XID_T_VERSION; + xid_version.data = (uint8_t *) "\x00"; + xid_version.data_len = 1; + + xid_n201u.type = GPRS_LLC_XID_T_N201_U; + xid_n201u.data = (uint8_t *) "\x05\xf0"; + xid_n201u.data_len = 2; + + xid_n201i.type = GPRS_LLC_XID_T_N201_I; + xid_n201i.data = (uint8_t *) "\x05\xf0"; + xid_n201i.data_len = 2; + + /* Add layer 3 XID field (if present) */ + if (l3_xid_field) { + /* Enforce layer 3 XID type (just to be sure) */ + l3_xid_field->type = GPRS_LLC_XID_T_L3_PAR; + + /* Add Layer 3 XID field to the list */ + llist_add(&l3_xid_field->list, &xid_fields); + } + + /* Add locally managed XID Fields */ + llist_add(&xid_n201i.list, &xid_fields); + llist_add(&xid_n201u.list, &xid_fields); + llist_add(&xid_version.list, &xid_fields); + + gprs_llc_copy_xid(&llme->xid, &xid_fields); + + return gprs_llc_compile_xid(&xid_fields, bytes, bytes_len); +} + +/* Generate XID message that will cause the GMM to reset */ +static int gprs_llc_generate_xid_for_gmm_reset(uint8_t *bytes, + int bytes_len, uint32_t iov_ui, + struct gprs_llc_llme *llme) +{ + /* Called by gprs_llgmm_reset() and + * gprs_llgmm_reset_oldmsg() */ + + LLIST_HEAD(xid_fields); + + struct gprs_llc_xid_field xid_reset; + struct gprs_llc_xid_field xid_iovui; + + /* First XID component must be RESET */ + xid_reset.type = GPRS_LLC_XID_T_RESET; + xid_reset.data = NULL; + xid_reset.data_len = 0; + + /* Add new IOV-UI */ + xid_iovui.type = GPRS_LLC_XID_T_IOV_UI; + xid_iovui.data = (uint8_t *) & iov_ui; + xid_iovui.data_len = 4; + + /* Add locally managed XID Fields */ + llist_add(&xid_iovui.list, &xid_fields); + llist_add(&xid_reset.list, &xid_fields); + + gprs_llc_copy_xid(&llme->xid, &xid_fields); + + return gprs_llc_compile_xid(&xid_fields, bytes, bytes_len); +} + +/* Process an incoming XID confirmation */ +static int gprs_llc_process_xid_conf(uint8_t *bytes, int bytes_len, + struct gprs_llc_lle *lle) +{ + /* Note: This function handles the response of a network originated + * XID-Request. There XID messages reflected by the phone are analyzed + * and processed here. The caller is called by rx_llc_xid(). */ + + int rc; + LLIST_HEAD(xid_fields); + struct gprs_llc_xid_field *xid_field; + struct gprs_llc_xid_field *xid_field_request; + struct gprs_llc_xid_field *xid_field_request_l3 = NULL; + + /* Pick layer3 XID from the XID request we have sent last */ + llist_for_each_entry(xid_field_request, &lle->llme->xid, list) { + if (xid_field_request->type == GPRS_LLC_XID_T_L3_PAR) + xid_field_request_l3 = xid_field_request; + } + + /* Parse and analyze XID-Response */ + rc = gprs_llc_parse_xid(&xid_fields, bytes, bytes_len); + if (rc == 0) { + gprs_llc_dump_xid_fields(&xid_fields, LOGL_DEBUG); + + llist_for_each_entry(xid_field, &xid_fields, list) { + + /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { +#if WITH_SNDCP_XID == 1 + sndcp_sn_xid_conf(xid_field, + xid_field_request_l3, + lle); +#endif + } + + /* Process LLC-XID fields: */ + else { + + /* FIXME: Do something more useful with the + * echoed XID-Information. Currently we + * just ignore the response completely and + * by doing so we blindly accept any changes + * the MS might have done to the our XID + * inquiry. There is a remainig risk of + * malfunction! */ + LOGP(DLLC, LOGL_NOTICE, + "Ignoring XID-Field: XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + xid_field->data); + + } + } + } + + /* Flush pending XID fields */ + gprs_llc_free_xid(&lle->llme->xid); + + return 0; +} + + +/* Process an incoming XID indication and generate an appropiate response */ +static int gprs_llc_process_xid_ind(uint8_t *bytes_request, + int bytes_request_len, + uint8_t *bytes_response, + int bytes_response_maxlen, + struct gprs_llc_lle *lle) +{ + /* Note: This function computes the response that is sent back to the + * phone when a phone originated XID is received. The function is + * called by rx_llc_xid() */ + + int rc; + LLIST_HEAD(xid_fields); + LLIST_HEAD(xid_fields_response); + + struct gprs_llc_xid_field *xid_field; + struct gprs_llc_xid_field *xid_field_response; + + /* Flush eventually pending XID fields */ + gprs_llc_free_xid(&lle->llme->xid); + + /* Parse and analyze XID-Request */ + rc = gprs_llc_parse_xid(&xid_fields, bytes_request, + bytes_request_len); + if (rc == 0) { + gprs_llc_dump_xid_fields(&xid_fields, LOGL_DEBUG); + + llist_for_each_entry(xid_field, &xid_fields, list) { + /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { +#if WITH_SNDCP_XID == 1 + xid_field_response = + talloc_zero(NULL, + struct gprs_llc_xid_field); + rc = sndcp_sn_xid_ind(xid_field, + xid_field_response, + lle); + if (rc == 0) + llist_add(&xid_field_response-> + list, + &xid_fields_response); + else + talloc_free(xid_field_response); +#endif + } + + /* Process LLC-XID fields: */ + else { + /* FIXME: Check the incoming XID parameters for + * for validity. Currently we just blindly + * accept all XID fields by just echoing them. + * There is a remaining risk of malfunction + * when a phone submits values which defer from + * the default! */ + LOGP(DLLC, LOGL_NOTICE, + "Echoing XID-Field: XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + osmo_hexdump_nospc(xid_field->data, + xid_field-> + data_len)); + xid_field_response = + gprs_llc_duplicate_xid_field + (xid_field); + llist_add(&xid_field_response->list, + &xid_fields_response); + } + } + + rc = gprs_llc_compile_xid(&xid_fields_response, + bytes_response, + bytes_response_maxlen); + gprs_llc_free_xid(&xid_fields_response); + } + gprs_llc_free_xid(&xid_fields); + + return rc; +} + +/* Dispatch XID indications and responses comming from the Phone */ +static void rx_llc_xid(struct gprs_llc_lle *lle, + struct gprs_llc_hdr_parsed *gph) +{ + uint8_t response[1024]; + int response_len; + + /* FIXME: 8.5.3.3: check if XID is invalid */ + if (gph->is_cmd) { + LOGP(DLLC, LOGL_NOTICE, + "Received XID indication from phone.\n"); + + struct msgb *resp; + uint8_t *xid; + resp = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + + response_len = + gprs_llc_process_xid_ind(gph->data, gph->data_len, + response, sizeof(response), + lle); + xid = msgb_put(resp, response_len); + memcpy(xid, response, response_len); + + gprs_llc_tx_xid(lle, resp, 0); + } else { + LOGP(DLLC, LOGL_NOTICE, + "Received XID confirmation from phone.\n"); + gprs_llc_process_xid_conf(gph->data, gph->data_len, lle); + /* FIXME: if we had sent a XID reset, send + * LLGMM-RESET.conf to GMM */ + } +} + + +/* Set of LL-XID negotiation (See also: TS 101 351, Section 7.2.2.4) */ +int gprs_ll_xid_req(struct gprs_llc_lle *lle, + struct gprs_llc_xid_field *l3_xid_field) +{ + /* Note: This functions is calle from gprs_sndcp.c */ + + uint8_t xid_bytes[1024];; + int xid_bytes_len; + uint8_t *xid; + struct msgb *msg; + + /* Generate XID */ + xid_bytes_len = + gprs_llc_generate_xid(xid_bytes, sizeof(xid_bytes), + l3_xid_field, lle->llme); + + + /* Only perform XID sending if the XID message contains something */ + if (xid_bytes_len > 0) { + /* Transmit XID bytes */ + msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); + LOGP(DLLC, LOGL_NOTICE, + "Sending XID request to phone...\n"); + gprs_llc_tx_xid(lle, msg, 1); + } else { + LOGP(DLLC, LOGL_ERROR, + "XID-Message generation failed, XID not sent!\n"); + return -EINVAL; + } + + return 0; +} + +/* END XID RELATED */ + + + /* Entry function from upper level (LLC), asking us to transmit a BSSGP PDU * to a remote MS (identified by TLLI) at a BTS identified by its BVCI and NSEI */ @@ -51,7 +355,7 @@ memset(&dup, 0, sizeof(dup)); /* before we have received some identity from the MS, we might * not yet have a MMC context (e.g. XID negotiation of primarly - * LLC connection fro GMM sapi). */ + * LLC connection from GMM sapi). */ if (mmctx) { dup.imsi = mmctx->imsi; dup.drx_parms = mmctx->drx_parms; @@ -246,11 +550,18 @@ llist_add(&llme->list, &gprs_llc_llmes); + INIT_LLIST_HEAD(&llme->comp.proto); + INIT_LLIST_HEAD(&llme->comp.data); + INIT_LLIST_HEAD(&llme->xid); + return llme; } static void llme_free(struct gprs_llc_llme *llme) { + gprs_sndcp_comp_entities_free(&llme->comp.proto); + gprs_sndcp_comp_entities_free(&llme->comp.data); + gprs_llc_free_xid(&llme->xid); llist_del(&llme->list); talloc_free(llme); } @@ -464,54 +775,6 @@ /* Send BSSGP-DL-UNITDATA.req */ return _bssgp_tx_dl_ud(msg, mmctx); -} - -/* According to 6.4.1.6 / Figure 11 */ -static int msgb_put_xid_par(struct msgb *msg, uint8_t type, uint8_t length, uint8_t *data) -{ - uint8_t header_len = 1; - uint8_t *cur; - - /* type is a 5-bit field... */ - if (type > 0x1f) - return -EINVAL; - - if (length > 3) - header_len = 2; - - cur = msgb_put(msg, length + header_len); - - /* build the header without or with XL bit */ - if (length <= 3) { - *cur++ = (type << 2) | (length & 3); - } else { - *cur++ = 0x80 | (type << 2) | (length >> 6); - *cur++ = (length << 2); - } - - /* copy over the payload of the parameter*/ - memcpy(cur, data, length); - - return length + header_len; -} - -static void rx_llc_xid(struct gprs_llc_lle *lle, - struct gprs_llc_hdr_parsed *gph) -{ - /* FIXME: 8.5.3.3: check if XID is invalid */ - if (gph->is_cmd) { - /* FIXME: implement XID negotiation using SNDCP */ - struct msgb *resp; - uint8_t *xid; - resp = msgb_alloc_headroom(4096, 1024, "LLC_XID"); - xid = msgb_put(resp, gph->data_len); - memcpy(xid, gph->data, gph->data_len); - gprs_llc_tx_xid(lle, resp, 0); - } else { - /* FIXME: if we had sent a XID reset, send - * LLGMM-RESET.conf to GMM */ - /* FIXME: implement XID negotiation using SNDCP */ - } } static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph, @@ -784,17 +1047,24 @@ { struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); struct gprs_llc_lle *lle = &llme->lle[1]; + uint8_t xid_bytes[1024]; + int xid_bytes_len; + uint8_t *xid; + LOGP(DLLC, LOGL_NOTICE, "LLGM Reset\n"); if (RAND_bytes((uint8_t *) &llme->iov_ui, 4) != 1) { LOGP(DLLC, LOGL_NOTICE, "RAND_bytes failed for LLC XID reset, " "falling back to rand()\n"); llme->iov_ui = rand(); } - /* First XID component must be RESET */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL); - /* randomly select new IOV-UI */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &llme->iov_ui); + /* Generate XID message */ + xid_bytes_len = gprs_llc_generate_xid_for_gmm_reset(xid_bytes, + sizeof(xid_bytes),llme->iov_ui,llme); + if(xid_bytes_len < 0) + return -EINVAL; + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); /* Reset some of the LLC parameters. See GSM 04.64, 8.5.3.1 */ lle->vu_recv = 0; @@ -810,17 +1080,24 @@ struct gprs_llc_llme *llme) { struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + uint8_t xid_bytes[1024]; + int xid_bytes_len; + uint8_t *xid; + LOGP(DLLC, LOGL_NOTICE, "LLGM Reset\n"); if (RAND_bytes((uint8_t *) &llme->iov_ui, 4) != 1) { LOGP(DLLC, LOGL_NOTICE, "RAND_bytes failed for LLC XID reset, " "falling back to rand()\n"); llme->iov_ui = rand(); } - /* First XID component must be RESET */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL); - /* randomly select new IOV-UI */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &llme->iov_ui); + /* Generate XID message */ + xid_bytes_len = gprs_llc_generate_xid_for_gmm_reset(xid_bytes, + sizeof(xid_bytes),llme->iov_ui,llme); + if(xid_bytes_len < 0) + return -EINVAL; + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); /* FIXME: Start T200, wait for XID response */ diff --git a/openbsc/src/gprs/v42bis.c b/openbsc/src/gprs/v42bis.c index ddffa4a..fd88b53 100644 --- a/openbsc/src/gprs/v42bis.c +++ b/openbsc/src/gprs/v42bis.c @@ -305,7 +305,7 @@ { if (ss->transparent) { - printf("Going compressed\n"); + DEBUGP(DV42BIS,"Going compressed\n"); /* 7.8.1 Transition to compressed mode */ /* Switch out of transparent now, between codes. We need to send the octet which did not match, just before switching. */ @@ -327,7 +327,7 @@ { if (!ss->transparent) { - printf("Going transparent\n"); + DEBUGP(DV42BIS,"Going transparent\n"); /* 7.8.2 Transition to transparent mode */ /* Switch into transparent now, between codes, and the unmatched octet should go out in transparent mode, just below */ @@ -396,7 +396,7 @@ { if (s->compress.dict[i].parent_code != 0xFFFF) { - printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); + DEBUGP(DV42BIS,"Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); } } return 0; @@ -449,13 +449,13 @@ ss->escaped = FALSE; if (code == V42BIS_ECM) { - printf("Hit V42BIS_ECM\n"); + DEBUGP(DV42BIS,"Hit V42BIS_ECM\n"); ss->transparent = FALSE; code_len = ss->v42bis_parm_c2; } else if (code == V42BIS_EID) { - printf("Hit V42BIS_EID\n"); + DEBUGP(DV42BIS,"Hit V42BIS_EID\n"); ss->output_buf[ss->output_octet_count++] = ss->escape_code - 1; if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) { @@ -465,11 +465,11 @@ } else if (code == V42BIS_RESET) { - printf("Hit V42BIS_RESET\n"); + DEBUGP(DV42BIS,"Hit V42BIS_RESET\n"); } else { - printf("Hit V42BIS_???? - %" PRIu32 "\n", code); + DEBUGP(DV42BIS,"Hit V42BIS_???? - %" PRIu32 "\n", code); } } else if (code == ss->escape_code) @@ -495,17 +495,17 @@ switch (new_code) { case V42BIS_ETM: - printf("Hit V42BIS_ETM\n"); + DEBUGP(DV42BIS,"Hit V42BIS_ETM\n"); ss->transparent = TRUE; code_len = 8; break; case V42BIS_FLUSH: - printf("Hit V42BIS_FLUSH\n"); + DEBUGP(DV42BIS,"Hit V42BIS_FLUSH\n"); v42bis_decompress_flush(s); break; case V42BIS_STEPUP: /* We need to increase the codeword size */ - printf("Hit V42BIS_STEPUP\n"); + DEBUGP(DV42BIS,"Hit V42BIS_STEPUP\n"); if (ss->v42bis_parm_c3 >= s->v42bis_parm_n2) { /* Invalid condition */ @@ -542,7 +542,7 @@ /* Trace back through the octets which form the string, and output them. */ while (code >= V42BIS_N5) { -if (code > 4095) {printf("Code is 0x%" PRIu32 "\n", code); exit(2);} +if (code > 4095) {DEBUGP(DV42BIS,"Code is 0x%" PRIu32 "\n", code); exit(2);} *string-- = ss->dict[code].node_octet; code = ss->dict[code].parent_code; } @@ -626,7 +626,7 @@ { if (s->decompress.dict[i].parent_code != 0xFFFF) { - printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); + DEBUGP(DV42BIS,"Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); } } return 0; diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index b6036c7..3b34452 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -30,6 +30,11 @@ $(top_builddir)/src/gprs/gprs_gb_parse.o \ $(top_builddir)/src/gprs/oap.o \ $(top_builddir)/src/gprs/oap_messages.o \ + $(top_builddir)/src/gprs/gprs_llc_xid.o \ + $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ + $(top_builddir)/src/gprs/gprs_sndcp_comp_entity.o \ + $(top_builddir)/src/gprs/gprs_sndcp_hdrcomp.o \ + $(top_builddir)/src/gprs/slhc.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ @@ -37,5 +42,5 @@ $(LIBOSMOGB_LIBS) \ $(LIBCARES_LIBS) \ $(LIBCRYPTO_LIBS) \ - -lgtp -lrt + -lgtp -lrt -lm -- To view, visit https://gerrit.osmocom.org/652 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I65b9d625e72d3d61c99abdc7041773701d694d52 Gerrit-PatchSet: 8 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte From gerrit-no-reply at lists.osmocom.org Fri Aug 5 11:48:50 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Fri, 5 Aug 2016 11:48:50 +0000 Subject: [ABANDON] openbsc[master]: i In-Reply-To: References: Message-ID: dexter has abandoned this change. Change subject: i ...................................................................... Abandoned -- To view, visit https://gerrit.osmocom.org/653 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: abandon Gerrit-Change-Id: I3ea5051fdbb26b48eb442fd219477930fa474ca6 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter From gerrit-no-reply at lists.osmocom.org Fri Aug 5 12:32:11 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Fri, 5 Aug 2016 12:32:11 +0000 Subject: [PATCH] osmo-pcu[master]: Add data structure to handle SPB for EGPRS DL Message-ID: Review at https://gerrit.osmocom.org/654 Add data structure to handle SPB for EGPRS DL Modify the header files with necessary data structure to handle Split block for EGPRS DL TBF. The EGPRS resegmentation feature allows PCU to retransmit RLC blocks of HeaderType1, HeaderType2 by segmenting them to 2 HeaderType3 blocks(Example MCS5 will be retransmitted as 2 MCS2 blocks). Table 10.4.8b.2 of 44.060 explains the possible values of SPB in HeadrType3 for DL direction. The PCU decides to retransmit the blocks by resegmenting it based on Table 8.1.1.1 of 44.060. The retransmission MCS is calculated based on current MCS of the Block and demanded MCS by PCU. Section 10.3a.3.3 of 44.060 shows the HeadrType3 with SPB field present in it Change-Id: I57673e53a9da2affa7e8aaa6551ac4b271c3d525 --- M src/bts.h M src/rlc.h 2 files changed, 38 insertions(+), 4 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/54/654/1 diff --git a/src/bts.h b/src/bts.h index 807ce08..38896c8 100644 --- a/src/bts.h +++ b/src/bts.h @@ -186,6 +186,10 @@ uint8_t alpha, gamma; uint8_t egprs_enabled; uint32_t dl_tbf_idle_msec; /* hold time for idle DL TBFs */ + + /* 0 to support resegmentation in DL, 1 for no reseg */ + uint8_t dl_arq_type; + uint32_t ms_idle_sec; uint8_t cs_adj_enabled; uint8_t cs_adj_upper_limit; diff --git a/src/rlc.h b/src/rlc.h index bf2d70a..539b30b 100644 --- a/src/rlc.h +++ b/src/rlc.h @@ -84,6 +84,32 @@ }; /* + * EGPRS resegment status information for DL + * When only first segment is sent, bsn state + * will be set to EGPRS_RESEG_FIRST_SEG_SENT and when + * second segment is sent the state will be + * set to EGPRS_RESEG_SECOND_SEG_SENT. + * EGPRS_RESEG_DL_INVALID is set to 8 considering there is a scope for + * 3rd segment according to Table 10.4.8b.2 of 44.060 + * The EGPRS resegmentation feature allows PCU to retransmit + * RLC blocks of HeaderType1, HeaderType2 by segmenting + * them to 2 HeaderType3 blocks(Example MCS5 will be + * retransmitted as 2 MCS2 blocks). Table 10.4.8b.2 of 44.060 + * explains the possible values of SPB in HeadrType3 for DL + * direction.The PCU decides to retransmit the + * blocks by resegmenting it based on Table 8.1.1.1 of 44.060. + * The retransmission MCS is calculated based on current MCS of + * the Block and demanded MCS by PCU. Section 10.3a.3.3 of 44.060 + * shows the HeadrType3 with SPB field present in it +*/ +enum egprs_rlc_dl_reseg_bsn_state { + EGPRS_RESEG_DL_DEFAULT = 0, + EGPRS_RESEG_FIRST_SEG_SENT = 0x01, + EGPRS_RESEG_SECOND_SEG_SENT = 0x02, + EGPRS_RESEG_DL_INVALID = 0x08 +}; + +/* * Valid puncturing scheme values * TS 44.060 10.4.8a.3.1, 10.4.8a.2.1, 10.4.8a.1.1 */ @@ -140,10 +166,7 @@ /* holds the current status of the block w.r.t UL/DL split blocks */ union split_block_status { egprs_rlc_ul_reseg_bsn_state block_status_ul; - /* - * TODO: DL split block status need to be supported - * for EGPRS DL - */ + egprs_rlc_dl_reseg_bsn_state block_status_dl; }; struct gprs_rlc_data { @@ -168,6 +191,13 @@ GprsCodingScheme cs_current_trans; GprsCodingScheme cs_last; + /* + * The MCS of initial transmission of a BSN + * This variable is used for split block + * processing in DL + */ + GprsCodingScheme cs_init; + /* puncturing scheme value to be used for next transmission*/ enum egprs_puncturing_values next_ps; -- To view, visit https://gerrit.osmocom.org/654 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I57673e53a9da2affa7e8aaa6551ac4b271c3d525 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Fri Aug 5 12:32:11 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Fri, 5 Aug 2016 12:32:11 +0000 Subject: [PATCH] osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB Message-ID: Review at https://gerrit.osmocom.org/655 Modify EGPRS DL TBF flow to support SPB Modify the EGPRS DL TBF flow to support Split block during Retx. This patch will also Upgrade the test suite with test cases to validate the EGPRS Downlink SPB for Retransmission Scenarios like MCS6->MCS3, MCS4->MCS1, MCS5->MCS2, MCS9->MCS3 MCS7->MCS2, MCS8->MCS3 have been simulated and Integration tested in NuRAN 1.0 hardware thoroughly. Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 --- M src/gprs_coding_scheme.h M src/pcu_main.cpp M src/pcu_vty.c M src/rlc.cpp M src/rlc.h M src/tbf.h M src/tbf_dl.cpp M tests/edge/EdgeTest.cpp M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 11 files changed, 887 insertions(+), 77 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/55/655/1 diff --git a/src/gprs_coding_scheme.h b/src/gprs_coding_scheme.h index 60a8e79..3b15372 100644 --- a/src/gprs_coding_scheme.h +++ b/src/gprs_coding_scheme.h @@ -113,7 +113,8 @@ static const char *modeName(Mode mode); static Scheme get_retx_mcs(const GprsCodingScheme mcs, - const GprsCodingScheme retx_mcs); + const GprsCodingScheme retx_mcs, + const unsigned arq_type); static enum Scheme egprs_mcs_retx_tbl[MAX_NUM_ARQ] [MAX_NUM_MCS][MAX_NUM_MCS]; @@ -232,8 +233,9 @@ } inline GprsCodingScheme::Scheme GprsCodingScheme::get_retx_mcs( const GprsCodingScheme mcs, - const GprsCodingScheme demanded_mcs) + const GprsCodingScheme demanded_mcs, + const unsigned arq_type) { - return egprs_mcs_retx_tbl[EGPRS_ARQ2][mcs.to_num() - 1] + return egprs_mcs_retx_tbl[arq_type][mcs.to_num() - 1] [demanded_mcs.to_num() - 1]; } diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2d86cda..e34d534 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -210,6 +210,12 @@ bts->dl_tbf_idle_msec = 2000; bts->llc_idle_ack_csec = 10; + /* + * By default resegmentation is supported in DL + * can also be configured through VTY + */ + bts->dl_arq_type = EGPRS_ARQ1; + msgb_set_talloc_ctx(tall_pcu_ctx); osmo_init_logging(&gprs_log_info); diff --git a/src/pcu_vty.c b/src/pcu_vty.c index 58fea99..81fdb88 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -129,6 +129,9 @@ vty_out(vty, " window-size %d %d%s", bts->ws_base, bts->ws_pdch, VTY_NEWLINE); + if (bts->dl_arq_type) + vty_out(vty, " arq %d %s", bts->dl_arq_type, VTY_NEWLINE); + if (bts->force_llc_lifetime == 0xffff) vty_out(vty, " queue lifetime infinite%s", VTY_NEWLINE); else if (bts->force_llc_lifetime) @@ -477,6 +480,22 @@ bts->max_mcs_dl = 0; bts->max_mcs_ul = 0; + return CMD_SUCCESS; +} + +#define EGPRS_DL_ARQ_STR "DL ARQ TYPE (EGPRS)\n" + +DEFUN(cfg_pcu_dl_arq_type, + cfg_pcu_dl_arq_cmd, + "dl arq <0-1> [<0-1>]", + EGPRS_DL_ARQ_STR + "Initial ARQ value to be used is (default 0:Reseg)\n" + "0:Reseg, 1:no Reseg") +{ + struct gprs_rlcmac_bts *bts = bts_main_data(); + uint8_t dl_arq_type = atoi(argv[0]); + + bts->dl_arq_type = dl_arq_type; return CMD_SUCCESS; } @@ -954,6 +973,7 @@ install_element(PCU_NODE, &cfg_pcu_no_cs_downgrade_thrsh_cmd); install_element(PCU_NODE, &cfg_pcu_cs_lqual_ranges_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_cmd); + install_element(PCU_NODE, &cfg_pcu_dl_arq_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_max_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_max_cmd); diff --git a/src/rlc.cpp b/src/rlc.cpp index 6770043..8da96f7 100644 --- a/src/rlc.cpp +++ b/src/rlc.cpp @@ -285,7 +285,8 @@ } static void gprs_rlc_data_header_init(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding, unsigned int header_bits) + GprsCodingScheme cs, bool with_padding, unsigned int header_bits, + const unsigned int spb) { unsigned int i; unsigned int padding_bits = with_padding ? cs.optionalPaddingBits() : 0; @@ -300,7 +301,7 @@ for (i = 0; i < rlc->num_data_blocks; i++) { gprs_rlc_data_block_info_init(&rlc->block_info[i], cs, - with_padding); + with_padding, spb); rlc->data_offs_bits[i] = header_bits + padding_bits + @@ -310,21 +311,25 @@ } void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsDL()); + cs.numDataHeaderBitsDL(), spb); } void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding) { + /* + * last parameter is sent as 0 since common function used + * for both DL and UL + */ return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsUL()); + cs.numDataHeaderBitsUL(), 0); } void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { unsigned int data_len = cs.maxDataBlockBytes(); if (with_padding) @@ -336,7 +341,7 @@ rdbi->e = 1; rdbi->cv = 15; rdbi->pi = 0; - rdbi->spb = 0; + rdbi->spb = spb; } unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, @@ -411,8 +416,17 @@ enum egprs_puncturing_values gprs_get_punct_scheme( enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current) + const GprsCodingScheme &cs_current, + const unsigned int spb) { + + /* + * If it is second segment of the block + * dont change the puncturing scheme + */ + if (spb == 3) + return punct; + /* TS 44.060 9.3.2.1.1 */ if ((GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS9) && (GprsCodingScheme::Scheme(cs_current) == GprsCodingScheme::MCS6)) { diff --git a/src/rlc.h b/src/rlc.h index 539b30b..66faf6f 100644 --- a/src/rlc.h +++ b/src/rlc.h @@ -206,18 +206,19 @@ }; void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding); void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, enum egprs_puncturing_values punct, enum egprs_puncturing_values punct2, int with_padding); void gprs_rlc_mcs_cps_decode(unsigned int cps, GprsCodingScheme cs, int *punct, int *punct2, int *with_padding); enum egprs_puncturing_values gprs_get_punct_scheme(enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current_trans); + const GprsCodingScheme &cs_current_trans, + const unsigned int spb); void gprs_update_punct_scheme(enum egprs_puncturing_values *punct, const GprsCodingScheme &cs); /* diff --git a/src/tbf.h b/src/tbf.h index 1bd7878..969836b 100644 --- a/src/tbf.h +++ b/src/tbf.h @@ -421,6 +421,11 @@ int analyse_errors(char *show_rbb, uint8_t ssn, ana_result *res); void schedule_next_frame(); + enum egprs_rlc_dl_reseg_bsn_state egprs_dl_get_data_buffer + (int bsn, uint8_t **block_data); + unsigned int get_egprs_dl_spb_status(int bsn); + unsigned int get_egprs_dl_spb_value(int bsn); + struct osmo_timer_list m_llc_timer; }; diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp index 07a747a..0395ed0 100644 --- a/src/tbf_dl.cpp +++ b/src/tbf_dl.cpp @@ -375,21 +375,27 @@ return -1; if (is_egprs_enabled()) { + /* Table 8.1.1.2 and Table 8.1.1.1 of 44.060 */ m_rlc.block(bsn)->cs_current_trans = - GprsCodingScheme::get_retx_mcs( - m_rlc.block(bsn)->cs_last, ms()->current_cs_dl()); + GprsCodingScheme::get_retx_mcs( + m_rlc.block(bsn)->cs_init, + ms()->current_cs_dl(), + bts->bts_data()->dl_arq_type); LOGP(DRLCMACDL, LOGL_DEBUG, - "- current_cs_dl(%d) demanded_mcs(%d) cs_trans(%d)\n", + "- initial_cs_dl(%d) last_mcs(%d) demanded_mcs(%d)" + "cs_trans(%d) arq_type(%d) bsn(%d)\n", + m_rlc.block(bsn)->cs_init.to_num(), m_rlc.block(bsn)->cs_last.to_num(), ms()->current_cs_dl().to_num(), - m_rlc.block(bsn)->cs_current_trans.to_num()); + m_rlc.block(bsn)->cs_current_trans.to_num(), + bts->bts_data()->dl_arq_type, bsn); /* TODO: Need to remove this check when MCS-8 -> MCS-6 * transistion is handled. * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 */ - if (m_rlc.block(bsn)->cs_last == GprsCodingScheme::MCS8) + if (m_rlc.block(bsn)->cs_init == GprsCodingScheme::MCS8) m_rlc.block(bsn)->cs_current_trans = GprsCodingScheme::MCS8; } else @@ -523,6 +529,11 @@ data = rlc_data->prepare(block_data_len); rlc_data->cs_last = cs; rlc_data->cs_current_trans = cs; + + /* Initialise the variable related to DL SPB */ + rlc_data->spb_status.block_status_dl = EGPRS_RESEG_DL_DEFAULT; + rlc_data->cs_init = cs; + rlc_data->len = block_data_len; rdbi = &(rlc_data->block_info); @@ -616,6 +627,7 @@ unsigned num_bsns; enum egprs_puncturing_values punct[ARRAY_SIZE(rlc.block_info)]; bool need_padding = false; + unsigned int spb = 0; /* * TODO: This is an experimental work-around to put 2 BSN into @@ -626,6 +638,7 @@ * the current limit. */ cs = m_rlc.block(index)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(index)->cs_init; bsns[0] = index; num_bsns = 1; @@ -634,7 +647,19 @@ num_bsns += 1; } - if (num_bsns == 1) { + /* + * if the intial mcs is 8 and retransmission mcs is either 6 or 3 + * we have to include the padding of 6 octets in first segment + */ + if ((GprsCodingScheme::Scheme(cs_init) == GprsCodingScheme::MCS8) && + (GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS6 || + GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS3)) { + if ((get_egprs_dl_spb_status(index) == + EGPRS_RESEG_DL_DEFAULT) || + (get_egprs_dl_spb_status(index) == + EGPRS_RESEG_SECOND_SEG_SENT)) + need_padding = true; + } else if (num_bsns == 1) { /* TODO: remove the conditional when MCS-6 padding isn't * failing to be decoded by MEs anymore */ /* TODO: support of MCS-8 -> MCS-6 transition should be @@ -646,7 +671,14 @@ cs.decToSingleBlock(&need_padding); } - gprs_rlc_data_info_init_dl(&rlc, cs, need_padding); + spb = get_egprs_dl_spb_value(index); + + LOGP(DRLCMACDL, LOGL_DEBUG, "- need_padding %d spb_status %d spb %d" + "(BSN1 %d BSN2 %d)\n", + need_padding, + get_egprs_dl_spb_status(index), spb, index, index2); + + gprs_rlc_data_info_init_dl(&rlc, cs, need_padding, spb); rlc.usf = 7; /* will be set at scheduler */ rlc.pr = 0; /* FIXME: power reduction */ @@ -665,10 +697,9 @@ data_block_idx++) { int bsn; - GprsCodingScheme cs_enc; uint8_t *block_data; gprs_rlc_data_block_info *rdbi, *block_info; - enum egprs_puncturing_values punct_scheme; + enum egprs_rlc_dl_reseg_bsn_state reseg_status; /* Check if there are more blocks than BSNs */ if (data_block_idx < num_bsns) @@ -676,38 +707,43 @@ else bsn = bsns[0]; - cs_enc = m_rlc.block(bsn)->cs_current_trans; - /* get data and header from current block */ - block_data = m_rlc.block(bsn)->block; - /* Get current puncturing scheme from block */ - punct_scheme = gprs_get_punct_scheme( + + m_rlc.block(bsn)->next_ps = gprs_get_punct_scheme( m_rlc.block(bsn)->next_ps, - m_rlc.block(bsn)->cs_last, cs); + m_rlc.block(bsn)->cs_last, cs, spb); if (cs.isEgprs()) { - OSMO_ASSERT(punct_scheme >= EGPRS_PS_1); - OSMO_ASSERT(punct_scheme <= EGPRS_PS_3); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps >= EGPRS_PS_1); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps <= EGPRS_PS_3); } - punct[data_block_idx] = punct_scheme; + punct[data_block_idx] = m_rlc.block(bsn)->next_ps; rdbi = &rlc.block_info[data_block_idx]; block_info = &m_rlc.block(bsn)->block_info; - if(rdbi->data_len != m_rlc.block(bsn)->len) { - LOGP(DRLCMACDL, LOGL_ERROR, - "ERROR: Expected len = %d for %s instead of " - "%d in data unit %d (BSN %d, %s)\n", - rdbi->data_len, cs.name(), m_rlc.block(bsn)->len, - data_block_idx, bsn, cs_enc.name()); - OSMO_ASSERT(rdbi->data_len == m_rlc.block(bsn)->len); - } - - /* TODO: Need to handle 2 same bsns - * in header type 1 + /* + * get data and header from current block + * function returns the reseg status */ - gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, - cs); + reseg_status = egprs_dl_get_data_buffer(bsn, &block_data); + m_rlc.block(bsn)->spb_status.block_status_dl = reseg_status; + + /* + * If it is first segment of the split block set the state of + * bsn to nacked. If it is the first segment dont update the + * next ps value of bsn. since next segment also needs same cps + */ + if (spb == 2) + m_window.m_v_b.mark_nacked(bsn); + else { + /* + * TODO: Need to handle 2 same bsns + * in header type 1 + */ + gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, + cs); + } m_rlc.block(bsn)->cs_last = cs; rdbi->e = block_info->e; @@ -1169,3 +1205,119 @@ keep_time_frames = msecs_to_frames(bts_data()->dl_tbf_idle_msec); return frames_since_last_drain(fn) <= keep_time_frames; } + +/* + * This function returns the pointer to data which needs + * to be copied. Also updates the status of the block related to + * Split block handling in the RLC/MAC block. + */ +enum egprs_rlc_dl_reseg_bsn_state + gprs_rlcmac_dl_tbf::egprs_dl_get_data_buffer(int bsn, + uint8_t **block_data) +{ + gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state *block_status_dl = + &rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + *block_data = &rlc_data->block[0]; + + /* + * Table 10.3a.0.1 of 44.060 + * MCS6,9: second segment starts at 74/2 = 37 + * MCS5,7: second segment starts at 56/2 = 28 + * MCS8: second segment starts at 31 + * MCS4: second segment starts at 44/2 = 22 + */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + if (*block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + switch (GprsCodingScheme::Scheme(cs_init)) { + case GprsCodingScheme::MCS6 : + case GprsCodingScheme::MCS9 : + *block_data = &rlc_data->block[37]; + break; + case GprsCodingScheme::MCS7 : + case GprsCodingScheme::MCS5 : + *block_data = &rlc_data->block[28]; + break; + case GprsCodingScheme::MCS8 : + *block_data = &rlc_data->block[31]; + break; + case GprsCodingScheme::MCS4 : + *block_data = &rlc_data->block[22]; + break; + default: + LOGP(DRLCMACDL, LOGL_ERROR, "Software error: " + "--%s hit invalid condition. headerType(%d) " + " blockstatus(%d) cs(%s) PLEASE FIX!\n", name(), + cs_current_trans.headerTypeData(), + *block_status_dl, cs_init.name()); + break; + + } + return EGPRS_RESEG_SECOND_SEG_SENT; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } + } + return EGPRS_RESEG_DL_DEFAULT; +} + +/* + * This function returns the status of split block + * for RLC/MAC block. + */ +unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_status(const int bsn) +{ + const gprs_rlc_data *rlc_data = m_rlc.block(bsn); + + return rlc_data->spb_status.block_status_dl; +} + +/* + * This function returns the spb value to be sent OTA + * for RLC/MAC block. + */ +unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_value(const int bsn) +{ + struct gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state block_status_dl = + rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + + /* Table 10.4.8b.1 of 44.060 */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + /* + * if we are sending the second segment the spb should be 3 + * other wise it should be 2 + */ + if (block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + return 3; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return 2; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return 2; + } + } + /* Non SPB cases 0 is reurned */ + return 0; +} diff --git a/tests/edge/EdgeTest.cpp b/tests/edge/EdgeTest.cpp index 807102c..9081d4d 100644 --- a/tests/edge/EdgeTest.cpp +++ b/tests/edge/EdgeTest.cpp @@ -517,7 +517,7 @@ /* TS 44.060, B.1 */ cs = GprsCodingScheme::CS4; - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -570,7 +570,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -592,7 +592,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -630,7 +630,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -669,7 +669,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -694,7 +694,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -719,7 +719,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -740,7 +740,7 @@ OSMO_ASSERT(data[0] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -777,7 +777,7 @@ cs = GprsCodingScheme::MCS4; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -835,7 +835,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -872,7 +872,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -923,7 +923,7 @@ OSMO_ASSERT(data[3] == 0); /* Block 3 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -967,7 +967,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -993,7 +993,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1020,7 +1020,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1074,7 +1074,7 @@ block_idx++) { struct gprs_rlc_data_info rlc; - gprs_rlc_data_info_init_dl(&rlc, cs, false); + gprs_rlc_data_info_init_dl(&rlc, cs, false, 0); memset(bits, pattern, sizeof(bits)); Decoding::rlc_copy_to_aligned_buffer( @@ -1118,12 +1118,14 @@ struct gprs_rlc_data_info rlc; printf("=== start %s ===\n", __func__); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::CS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::CS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 24); OSMO_ASSERT(rlc.block_info[0].data_len == 20); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::MCS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::MCS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 33); OSMO_ASSERT(rlc.block_info[0].data_len == 22); diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..18cc5cb 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -1814,6 +1814,201 @@ } +static void egprs_spb_to_normal_validation(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + uint16_t bsn1, bsn2, bsn3; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + struct gprs_rlc_dl_header_egprs_2 *egprs2; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + if ((mcs == 6) && (demanded_mcs == 3)) { + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + bsn1 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) + || (egprs2->bsn1_lo); + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(bsn1 == 0); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + bsn2 = (egprs3->bsn1_hi << 9) || (egprs3->bsn1_mid << 1) || + (egprs3->bsn1_lo); + OSMO_ASSERT(bsn2 == bsn1); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Handle (MCS3, MCS3) -> MCS6 case */ + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + mcs)); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs2->cps == 0); + bsn3 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) || + (egprs2->bsn1_lo); + OSMO_ASSERT(bsn3 == bsn2); + + tbf_cleanup(dl_tbf); + } +} +static void establish_and_use_egprs_dl_tbf_for_spb(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + /* TODO: Need to support of MCS8 -> MCS6 ->MCS3 transistion + * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 + * dated 2016-02-07 23:45:40 (UTC) + */ + if (((mcs == 5) && (demanded_mcs == 2)) || + ((mcs == 6) && (demanded_mcs == 3)) || + ((mcs == 4) && (demanded_mcs == 1))) { + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + tbf_cleanup(dl_tbf); + } +} + static void establish_and_use_egprs_dl_tbf_for_retx(BTS *the_bts, int mcs, int demanded_mcs) { @@ -1972,6 +2167,9 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; + /* First parameter is current MCS, second one is demanded_mcs */ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 6); @@ -1981,6 +2179,38 @@ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 9); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 7, 5); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 9, 6); + + printf("=== end %s ===\n", __func__); +} + +static void test_tbf_egprs_spb_dl(void) +{ + BTS the_bts; + gprs_rlcmac_bts *bts; + uint8_t ts_no = 4; + int i, j; + + printf("=== start %s ===\n", __func__); + + bts = the_bts.bts_data(); + bts->cs_downgrade_threshold = 0; + setup_bts(&the_bts, ts_no); + bts->dl_tbf_idle_msec = 200; + bts->egprs_enabled = 1; + + /* ARQ I resegmentation support */ + bts->dl_arq_type = EGPRS_ARQ1; + + /* + * First parameter is current MCS, second one is demanded_mcs + * currently only MCS5->MCS2, MCS6->3, MCS4->MCS1 is tested in UT + * rest scenarios has been integration tested + */ + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 6, 3); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 5, 2); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 4, 1); + /* check MCS6->(MCS3+MCS3)->MCS6 case */ + egprs_spb_to_normal_validation(&the_bts, 6, 3); printf("=== end %s ===\n", __func__); } @@ -1999,6 +2229,8 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; for (i = 1; i <= 9; i++) establish_and_use_egprs_dl_tbf(&the_bts, i); @@ -2071,6 +2303,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_egprs_spb_dl(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..0ced2fc 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -72,6 +72,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -81,6 +82,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -157,6 +159,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -166,6 +169,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -242,6 +246,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -251,6 +256,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -259,6 +265,7 @@ - Sending new block at BSN 2, CS=CS-1 -- Chunk with length 160 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=13 block=3 data=07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b @@ -267,6 +274,7 @@ - Sending new block at BSN 3, CS=CS-1 -- Chunk with length 140 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=17 block=4 data=07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @@ -275,6 +283,7 @@ - Sending new block at BSN 4, CS=CS-1 -- Chunk with length 120 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=21 block=5 data=07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 @@ -283,6 +292,7 @@ - Sending new block at BSN 5, CS=CS-1 -- Chunk with length 100 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=26 block=6 data=07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 @@ -291,6 +301,7 @@ - Sending new block at BSN 6, CS=CS-1 -- Chunk with length 80 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=30 block=7 data=07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b @@ -299,6 +310,7 @@ - Sending new block at BSN 7, CS=CS-1 -- Chunk with length 60 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=34 block=8 data=07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f @@ -307,6 +319,7 @@ - Sending new block at BSN 8, CS=CS-1 -- Chunk with length 40 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=39 block=9 data=07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 @@ -315,6 +328,7 @@ - Sending new block at BSN 9, CS=CS-1 -- Chunk with length 20 would exactly fit into space (20): add length header with LI=0, to make frame extend to next block, and we are done data block (BSN 9, CS-1): 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=43 block=10 data=07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 @@ -326,6 +340,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=47 block=11 data=07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 @@ -334,6 +349,7 @@ - Sending new block at BSN 11, CS=CS-1 -- Chunk with length 182 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=52 block=0 data=07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 @@ -342,6 +358,7 @@ - Sending new block at BSN 12, CS=CS-1 -- Chunk with length 162 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=56 block=1 data=07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 @@ -350,6 +367,7 @@ - Sending new block at BSN 13, CS=CS-1 -- Chunk with length 142 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 13, CS-1): 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=60 block=2 data=07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d @@ -358,6 +376,7 @@ - Sending new block at BSN 14, CS=CS-1 -- Chunk with length 122 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=65 block=3 data=07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 @@ -366,6 +385,7 @@ - Sending new block at BSN 15, CS=CS-1 -- Chunk with length 102 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=69 block=4 data=07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 @@ -374,6 +394,7 @@ - Sending new block at BSN 16, CS=CS-1 -- Chunk with length 82 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=73 block=5 data=07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 @@ -382,6 +403,7 @@ - Sending new block at BSN 17, CS=CS-1 -- Chunk with length 62 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=78 block=6 data=07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d @@ -390,6 +412,7 @@ - Sending new block at BSN 18, CS=CS-1 -- Chunk with length 42 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=82 block=7 data=07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 @@ -398,6 +421,7 @@ - Sending new block at BSN 19, CS=CS-1 -- Chunk with length 22 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=86 block=8 data=07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 @@ -411,6 +435,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=16 data block (BSN 20, CS-1): 0a 41 c6 c7 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -449,6 +474,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 data block (BSN 21, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -468,6 +494,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 22, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FINISHED) @@ -1481,6 +1508,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 0, CS-1): 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 MSG = 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 @@ -1491,6 +1519,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 1, CS-1): 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 MSG = 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 @@ -1501,6 +1530,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FINISHED data block (BSN 2, CS-1): 4d 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling cannot be scheduled in this TS 7 (first control TS 4) @@ -1784,6 +1814,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=10 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 0, CS-4): 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654292 TS 7 @@ -1797,6 +1828,7 @@ TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) downlink (V(A)==0 .. V(S)==1) - Restarting at BSN 0, because all blocks have been transmitted. - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-4): 07 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 @@ -2365,6 +2397,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654279 block=10 data=00 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 @@ -2384,6 +2417,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -2406,6 +2440,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654288 block=0 data=00 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 @@ -2425,6 +2460,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654292 block=1 data=00 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2447,6 +2483,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654296 block=2 data=00 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c @@ -2466,6 +2503,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654301 block=3 data=00 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b @@ -2488,6 +2526,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 6, CS-1): 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654305 block=4 data=00 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 @@ -2507,6 +2546,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654309 block=5 data=00 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 @@ -2526,6 +2566,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654314 block=6 data=00 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 @@ -2548,6 +2589,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654318 block=7 data=00 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 @@ -2567,6 +2609,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654322 block=8 data=00 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2589,6 +2632,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654327 block=9 data=00 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c @@ -2608,6 +2652,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654331 block=10 data=00 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b @@ -2630,6 +2675,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 13, CS-1): 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654335 block=11 data=00 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 @@ -2649,6 +2695,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654340 block=0 data=00 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 @@ -2668,6 +2715,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654344 block=1 data=00 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 @@ -2690,6 +2738,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654348 block=2 data=00 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 @@ -2709,6 +2758,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654353 block=3 data=00 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2731,6 +2781,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654357 block=4 data=00 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c @@ -2750,6 +2801,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654361 block=5 data=00 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b @@ -2772,6 +2824,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 20, CS-1): 16 35 45 54 20 32 38 4c 4c 43 20 50 41 43 4b 45 54 20 32 39 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because 20 blocks sent. TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW): Scheduling polling at FN 2654379 TS 7 @@ -2795,6 +2848,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 21, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) msg block (BSN 21, CS-1): 07 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654370 block=7 data=00 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 @@ -2814,6 +2868,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 22, CS-1): 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) msg block (BSN 22, CS-1): 07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654374 block=8 data=07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 @@ -2836,6 +2891,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 23, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) msg block (BSN 23, CS-1): 07 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654379 block=9 data=00 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 @@ -2855,6 +2911,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 24, CS-1): 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) msg block (BSN 24, CS-1): 07 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654383 block=10 data=00 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2877,6 +2934,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 25, CS-1): 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 25 BSN2 -1) - Copying data unit 0 (BSN 25) msg block (BSN 25, CS-1): 07 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654387 block=11 data=00 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c @@ -2896,6 +2954,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 26, CS-1): 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 26 BSN2 -1) - Copying data unit 0 (BSN 26) msg block (BSN 26, CS-1): 07 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654392 block=0 data=00 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b @@ -2918,6 +2977,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 27, CS-1): 16 35 45 54 20 33 38 4c 4c 43 20 50 41 43 4b 45 54 20 33 39 +- need_padding 0 spb_status 0 spb 0(BSN1 27 BSN2 -1) - Copying data unit 0 (BSN 27) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) @@ -3028,6 +3088,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654405 block=3 data=00 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 @@ -3047,6 +3108,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654409 block=4 data=00 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 @@ -3066,6 +3128,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (16) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654413 block=5 data=00 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 @@ -3085,6 +3148,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (14) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654418 block=6 data=00 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 @@ -3104,6 +3168,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654422 block=7 data=00 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -3123,6 +3188,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654426 block=8 data=00 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 @@ -3142,6 +3208,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654431 block=9 data=00 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b @@ -3161,6 +3228,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654435 block=10 data=00 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 @@ -3180,6 +3248,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654439 block=11 data=00 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 @@ -3199,6 +3268,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654444 block=0 data=00 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c @@ -3218,6 +3288,7 @@ Complete DL frame for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=21 TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 10, CS-1): 4d 43 20 50 41 43 4b 45 54 20 30 39 20 28 54 42 46 20 32 29 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654461 TS 7 @@ -3698,6 +3769,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 0, MCS-1): 14 15 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3711,6 +3783,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3721,6 +3794,7 @@ - Sending new block at BSN 2, CS=MCS-1 -- Chunk with length 490 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3731,6 +3805,7 @@ - Sending new block at BSN 3, CS=MCS-1 -- Chunk with length 468 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3741,6 +3816,7 @@ - Sending new block at BSN 4, CS=MCS-1 -- Chunk with length 446 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3751,6 +3827,7 @@ - Sending new block at BSN 5, CS=MCS-1 -- Chunk with length 424 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3761,6 +3838,7 @@ - Sending new block at BSN 6, CS=MCS-1 -- Chunk with length 402 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3771,6 +3849,7 @@ - Sending new block at BSN 7, CS=MCS-1 -- Chunk with length 380 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3781,6 +3860,7 @@ - Sending new block at BSN 8, CS=MCS-1 -- Chunk with length 358 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3791,6 +3871,7 @@ - Sending new block at BSN 9, CS=MCS-1 -- Chunk with length 336 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3801,6 +3882,7 @@ - Sending new block at BSN 10, CS=MCS-1 -- Chunk with length 314 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3811,6 +3893,7 @@ - Sending new block at BSN 11, CS=MCS-1 -- Chunk with length 292 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3821,6 +3904,7 @@ - Sending new block at BSN 12, CS=MCS-1 -- Chunk with length 270 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3831,6 +3915,7 @@ - Sending new block at BSN 13, CS=MCS-1 -- Chunk with length 248 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3841,6 +3926,7 @@ - Sending new block at BSN 14, CS=MCS-1 -- Chunk with length 226 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3851,6 +3937,7 @@ - Sending new block at BSN 15, CS=MCS-1 -- Chunk with length 204 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3861,6 +3948,7 @@ - Sending new block at BSN 16, CS=MCS-1 -- Chunk with length 182 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3871,6 +3959,7 @@ - Sending new block at BSN 17, CS=MCS-1 -- Chunk with length 160 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3881,6 +3970,7 @@ - Sending new block at BSN 18, CS=MCS-1 -- Chunk with length 138 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3891,6 +3981,7 @@ - Sending new block at BSN 19, CS=MCS-1 -- Chunk with length 116 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 19, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3901,6 +3992,7 @@ - Sending new block at BSN 20, CS=MCS-1 -- Chunk with length 94 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 20, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3911,6 +4003,7 @@ - Sending new block at BSN 21, CS=MCS-1 -- Chunk with length 72 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 21, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3921,6 +4014,7 @@ - Sending new block at BSN 22, CS=MCS-1 -- Chunk with length 50 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 22, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3931,6 +4025,7 @@ - Sending new block at BSN 23, CS=MCS-1 -- Chunk with length 28 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 23, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3946,6 +4041,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 24, MCS-1): 0c 1d 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4006,6 +4102,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=16 data block (BSN 0, MCS-2): 14 21 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4019,6 +4116,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4029,6 +4127,7 @@ - Sending new block at BSN 2, CS=MCS-2 -- Chunk with length 484 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4039,6 +4138,7 @@ - Sending new block at BSN 3, CS=MCS-2 -- Chunk with length 456 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4049,6 +4149,7 @@ - Sending new block at BSN 4, CS=MCS-2 -- Chunk with length 428 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4059,6 +4160,7 @@ - Sending new block at BSN 5, CS=MCS-2 -- Chunk with length 400 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4069,6 +4171,7 @@ - Sending new block at BSN 6, CS=MCS-2 -- Chunk with length 372 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4079,6 +4182,7 @@ - Sending new block at BSN 7, CS=MCS-2 -- Chunk with length 344 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4089,6 +4193,7 @@ - Sending new block at BSN 8, CS=MCS-2 -- Chunk with length 316 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4099,6 +4204,7 @@ - Sending new block at BSN 9, CS=MCS-2 -- Chunk with length 288 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4109,6 +4215,7 @@ - Sending new block at BSN 10, CS=MCS-2 -- Chunk with length 260 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4119,6 +4226,7 @@ - Sending new block at BSN 11, CS=MCS-2 -- Chunk with length 232 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4129,6 +4237,7 @@ - Sending new block at BSN 12, CS=MCS-2 -- Chunk with length 204 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4139,6 +4248,7 @@ - Sending new block at BSN 13, CS=MCS-2 -- Chunk with length 176 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4149,6 +4259,7 @@ - Sending new block at BSN 14, CS=MCS-2 -- Chunk with length 148 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4159,6 +4270,7 @@ - Sending new block at BSN 15, CS=MCS-2 -- Chunk with length 120 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4169,6 +4281,7 @@ - Sending new block at BSN 16, CS=MCS-2 -- Chunk with length 92 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4179,6 +4292,7 @@ - Sending new block at BSN 17, CS=MCS-2 -- Chunk with length 64 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4189,6 +4303,7 @@ - Sending new block at BSN 18, CS=MCS-2 -- Chunk with length 36 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4204,6 +4319,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=18 data block (BSN 19, MCS-2): 10 25 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4264,6 +4380,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=25 data block (BSN 0, MCS-3): 14 33 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4277,6 +4394,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4287,6 +4405,7 @@ - Sending new block at BSN 2, CS=MCS-3 -- Chunk with length 475 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4297,6 +4416,7 @@ - Sending new block at BSN 3, CS=MCS-3 -- Chunk with length 438 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4307,6 +4427,7 @@ - Sending new block at BSN 4, CS=MCS-3 -- Chunk with length 401 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4317,6 +4438,7 @@ - Sending new block at BSN 5, CS=MCS-3 -- Chunk with length 364 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4327,6 +4449,7 @@ - Sending new block at BSN 6, CS=MCS-3 -- Chunk with length 327 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4337,6 +4460,7 @@ - Sending new block at BSN 7, CS=MCS-3 -- Chunk with length 290 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4347,6 +4471,7 @@ - Sending new block at BSN 8, CS=MCS-3 -- Chunk with length 253 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4357,6 +4482,7 @@ - Sending new block at BSN 9, CS=MCS-3 -- Chunk with length 216 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4367,6 +4493,7 @@ - Sending new block at BSN 10, CS=MCS-3 -- Chunk with length 179 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4377,6 +4504,7 @@ - Sending new block at BSN 11, CS=MCS-3 -- Chunk with length 142 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4387,6 +4515,7 @@ - Sending new block at BSN 12, CS=MCS-3 -- Chunk with length 105 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4397,6 +4526,7 @@ - Sending new block at BSN 13, CS=MCS-3 -- Chunk with length 68 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4410,6 +4540,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-3): 3f 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4425,6 +4556,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=34 data block (BSN 15, MCS-3): 02 45 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4485,6 +4617,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=32 data block (BSN 0, MCS-4): 14 41 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4498,6 +4631,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4508,6 +4642,7 @@ - Sending new block at BSN 2, CS=MCS-4 -- Chunk with length 468 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4518,6 +4653,7 @@ - Sending new block at BSN 3, CS=MCS-4 -- Chunk with length 424 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4528,6 +4664,7 @@ - Sending new block at BSN 4, CS=MCS-4 -- Chunk with length 380 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4538,6 +4675,7 @@ - Sending new block at BSN 5, CS=MCS-4 -- Chunk with length 336 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4548,6 +4686,7 @@ - Sending new block at BSN 6, CS=MCS-4 -- Chunk with length 292 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4558,6 +4697,7 @@ - Sending new block at BSN 7, CS=MCS-4 -- Chunk with length 248 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4568,6 +4708,7 @@ - Sending new block at BSN 8, CS=MCS-4 -- Chunk with length 204 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4578,6 +4719,7 @@ - Sending new block at BSN 9, CS=MCS-4 -- Chunk with length 160 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4588,6 +4730,7 @@ - Sending new block at BSN 10, CS=MCS-4 -- Chunk with length 116 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4598,6 +4741,7 @@ - Sending new block at BSN 11, CS=MCS-4 -- Chunk with length 72 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4613,6 +4757,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 12, MCS-4): 38 1d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4673,6 +4818,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-5): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4686,6 +4832,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4696,6 +4843,7 @@ - Sending new block at BSN 2, CS=MCS-5 -- Chunk with length 456 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4706,6 +4854,7 @@ - Sending new block at BSN 3, CS=MCS-5 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4716,6 +4865,7 @@ - Sending new block at BSN 4, CS=MCS-5 -- Chunk with length 344 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4726,6 +4876,7 @@ - Sending new block at BSN 5, CS=MCS-5 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4736,6 +4887,7 @@ - Sending new block at BSN 6, CS=MCS-5 -- Chunk with length 232 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4746,6 +4898,7 @@ - Sending new block at BSN 7, CS=MCS-5 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4756,6 +4909,7 @@ - Sending new block at BSN 8, CS=MCS-5 -- Chunk with length 120 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4766,6 +4920,7 @@ - Sending new block at BSN 9, CS=MCS-5 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4781,6 +4936,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-5): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4841,6 +4997,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-6): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4854,6 +5011,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4864,6 +5022,7 @@ - Sending new block at BSN 2, CS=MCS-6 -- Chunk with length 438 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4874,6 +5033,7 @@ - Sending new block at BSN 3, CS=MCS-6 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4884,6 +5044,7 @@ - Sending new block at BSN 4, CS=MCS-6 -- Chunk with length 290 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4894,6 +5055,7 @@ - Sending new block at BSN 5, CS=MCS-6 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4904,6 +5066,7 @@ - Sending new block at BSN 6, CS=MCS-6 -- Chunk with length 142 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4917,6 +5080,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-6): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4932,6 +5096,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-6): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4993,6 +5158,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-7): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5002,12 +5168,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- current_cs_dl(5) demanded_mcs(7) cs_trans(7)arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-7 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5022,6 +5189,7 @@ - Sending new block at BSN 3, CS=MCS-7 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5036,6 +5204,7 @@ - Sending new block at BSN 5, CS=MCS-7 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5050,6 +5219,7 @@ - Sending new block at BSN 7, CS=MCS-7 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5064,6 +5234,7 @@ - Sending new block at BSN 9, CS=MCS-7 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 9) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5081,6 +5252,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-7): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5142,6 +5314,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=56 data block (BSN 0, MCS-8): 14 71 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5152,12 +5325,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(8) demanded_mcs(8) cs_trans(8) +- current_cs_dl(8) demanded_mcs(8) cs_trans(8)arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-8 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5172,6 +5346,7 @@ - Sending new block at BSN 3, CS=MCS-8 -- Chunk with length 376 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5186,6 +5361,7 @@ - Sending new block at BSN 5, CS=MCS-8 -- Chunk with length 240 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5200,6 +5376,7 @@ - Sending new block at BSN 7, CS=MCS-8 -- Chunk with length 104 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5217,6 +5394,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=30 data block (BSN 8, MCS-8): 48 3d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5279,6 +5457,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-9): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5288,12 +5467,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- current_cs_dl(6) demanded_mcs(9) cs_trans(9)arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-9 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5308,6 +5488,7 @@ - Sending new block at BSN 3, CS=MCS-9 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5322,6 +5503,7 @@ - Sending new block at BSN 5, CS=MCS-9 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5339,6 +5521,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-9): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5356,6 +5539,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-9): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5402,11 +5586,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(6) cs_trans(6) +- current_cs_dl(6) demanded_mcs(6) cs_trans(6)arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5450,11 +5636,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 96 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(1) demanded_mcs(1) cs_trans(1) +- current_cs_dl(1) demanded_mcs(1) cs_trans(1)arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 98 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5498,11 +5686,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-2): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 92 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(2) demanded_mcs(2) cs_trans(2) +- current_cs_dl(2) demanded_mcs(2) cs_trans(2)arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 94 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5546,6 +5736,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5557,6 +5748,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-5): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5564,10 +5756,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-5): 0f 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- current_cs_dl(5) demanded_mcs(7) cs_trans(7)arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- current_cs_dl(5) demanded_mcs(7) cs_trans(7)arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-7): 07 00 00 02 c0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 @@ -5612,6 +5805,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5623,6 +5817,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-6): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5630,10 +5825,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-6): 0f 40 00 00 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- current_cs_dl(6) demanded_mcs(9) cs_trans(9)arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- current_cs_dl(6) demanded_mcs(9) cs_trans(9)arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-9): 07 00 00 02 28 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 @@ -5686,6 +5882,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-7): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5694,13 +5891,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-7): 0f 00 00 02 a0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- current_cs_dl(7) demanded_mcs(5) cs_trans(5)arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- current_cs_dl(7) demanded_mcs(5) cs_trans(5)arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-5): 07 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5752,6 +5951,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-9): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5760,13 +5960,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-9): 0f 00 00 02 00 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- current_cs_dl(9) demanded_mcs(6) cs_trans(6)arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- current_cs_dl(9) demanded_mcs(6) cs_trans(6)arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-6): 07 40 00 02 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5780,3 +5982,171 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- current_cs_dl(6) demanded_mcs(3) cs_trans(3)arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- current_cs_dl(3) demanded_mcs(3) cs_trans(3)arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-5 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- current_cs_dl(5) demanded_mcs(2) cs_trans(2)arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 d2 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- current_cs_dl(2) demanded_mcs(2) cs_trans(2)arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 f2 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-4 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (44) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-4): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-4): 07 00 00 80 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- current_cs_dl(4) demanded_mcs(1) cs_trans(1)arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 d6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- current_cs_dl(1) demanded_mcs(1) cs_trans(1)arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 f6 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..23c5e56 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,8 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_egprs_spb_dl === +Testing retx for MCS 6 to reseg_mcs 3 +Testing retx for MCS 5 to reseg_mcs 2 +Testing retx for MCS 4 to reseg_mcs 1 +=== end test_tbf_egprs_spb_dl === -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Mon Aug 8 06:02:40 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 8 Aug 2016 06:02:40 +0000 Subject: [PATCH] osmo-bts[master]: ci/spatch: Remove the "static" analysis handling Message-ID: Review at https://gerrit.osmocom.org/656 ci/spatch: Remove the "static" analysis handling spatch on Debian 8.0 has already crashed twice and is likely to crash more and at the same time the value for this static checking is close to zero (nice idea but never blossomed). So let's remove it, have a more reliable build and let's coverity find those issues. Change-Id: Ic1004edf7f0bee8dda30b95554a0aaf0b116b6b8 --- M contrib/jenkins_oct.sh M contrib/jenkins_sysmobts.sh 2 files changed, 0 insertions(+), 28 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/56/656/1 diff --git a/contrib/jenkins_oct.sh b/contrib/jenkins_oct.sh index 3489297..88b8c08 100755 --- a/contrib/jenkins_oct.sh +++ b/contrib/jenkins_oct.sh @@ -15,9 +15,6 @@ # Build the dependency cd ../ -# Analysis code -osmo-deps.sh osmo-static-analysis - osmo-deps.sh libosmocore cd libosmocore autoreconf --install --force @@ -54,15 +51,3 @@ PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig $MAKE $PARALLEL_MAKE PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig LD_LIBRARY_PATH=$PWD/deps/install/lib $MAKE check DISTCHECK_CONFIGURE_FLAGS="--with-octsdr-2g=$PWD/deps/layer1-api/ --with-openbsc=$PWD/deps/openbsc/openbsc/include" PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig LD_LIBRARY_PATH=$PWD/deps/install/lib $MAKE distcheck - - - -# Use spatch to find common issues -spatch -include_headers -in_place -sp_file deps/osmo-static-analysis/coccinelle/memcpy.cocci . -RES=`git status --porcelain | grep ' M' | wc -l` -git checkout . - -if [ $RES -gt 0 ]; then - echo "Static analysis failed. Please fix the code." - exit 23 -fi diff --git a/contrib/jenkins_sysmobts.sh b/contrib/jenkins_sysmobts.sh index 7d171fc..051c8e0 100755 --- a/contrib/jenkins_sysmobts.sh +++ b/contrib/jenkins_sysmobts.sh @@ -15,9 +15,6 @@ # Build the dependency cd ../ -# Analysis code -osmo-deps.sh osmo-static-analysis - osmo-deps.sh libosmocore cd libosmocore autoreconf --install --force @@ -62,13 +59,3 @@ if [ $FIRMWARE_VERSION != "femtobts_v2.7" ]; then PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig $MAKE -C contrib/sysmobts-calib fi - -# Use spatch to find common issues -spatch -include_headers -in_place -sp_file deps/osmo-static-analysis/coccinelle/memcpy.cocci . -RES=`git status --porcelain | grep ' M' | wc -l` -git checkout . - -if [ $RES -gt 0 ]; then - echo "Static analysis failed. Please fix the code." - exit 23 -fi -- To view, visit https://gerrit.osmocom.org/656 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ic1004edf7f0bee8dda30b95554a0aaf0b116b6b8 Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Holger Freyther From gerrit-no-reply at lists.osmocom.org Mon Aug 8 10:13:02 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Mon, 8 Aug 2016 10:13:02 +0000 Subject: [ABANDON] openbsc[master]: Add web proxy for control interface In-Reply-To: References: Message-ID: Max has abandoned this change. Change subject: Add web proxy for control interface ...................................................................... Abandoned -- To view, visit https://gerrit.osmocom.org/647 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: abandon Gerrit-Change-Id: Id3fc7e6dcf28fe543dc32930e737eae5bc188656 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte From gerrit-no-reply at lists.osmocom.org Mon Aug 8 10:13:19 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Mon, 8 Aug 2016 10:13:19 +0000 Subject: [ABANDON] openbsc[master]: Add python functions to get/set ctrl variables In-Reply-To: References: Message-ID: Max has abandoned this change. Change subject: Add python functions to get/set ctrl variables ...................................................................... Abandoned -- To view, visit https://gerrit.osmocom.org/645 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: abandon Gerrit-Change-Id: I2bc275b801a4b78642653f5b0a91e8cbea25422a Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte From gerrit-no-reply at lists.osmocom.org Mon Aug 8 10:13:49 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Mon, 8 Aug 2016 10:13:49 +0000 Subject: [ABANDON] openbsc[master]: Use random operation id In-Reply-To: References: Message-ID: Max has abandoned this change. Change subject: Use random operation id ...................................................................... Abandoned -- To view, visit https://gerrit.osmocom.org/640 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: abandon Gerrit-Change-Id: I87d9ee0e9a87f58702c60bb141c973d41fa06997 Gerrit-PatchSet: 3 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: daniel From gerrit-no-reply at lists.osmocom.org Mon Aug 8 10:17:44 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Mon, 8 Aug 2016 10:17:44 +0000 Subject: [PATCH] openbsc[master]: Use random operation id Message-ID: Review at https://gerrit.osmocom.org/657 Use random operation id According to documentation for Control Interface Protocol is "A numeric identifier, uniquely identifying this particular operation", hence it's best to be illustrated with random integer - use it as default. Fix override of id with previously used python-specific objects' id. Change-Id: I32236c067360526f4e7ee4bbdba64c5137de696d Related: OS#1646 --- M openbsc/contrib/bsc_control.py 1 file changed, 10 insertions(+), 8 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/57/657/1 diff --git a/openbsc/contrib/bsc_control.py b/openbsc/contrib/bsc_control.py index 26a421d..4fc8b4d 100755 --- a/openbsc/contrib/bsc_control.py +++ b/openbsc/contrib/bsc_control.py @@ -1,6 +1,6 @@ #!/usr/bin/python -import sys,os +import sys,os, random from optparse import OptionParser import socket import struct @@ -36,15 +36,17 @@ data = prefix_ipa_ctrl_header(data) sck.send(data) -def do_set(var, value, id, sck): - setmsg = "SET %s %s %s" %(options.id, var, value) +def do_set(var, value, op_id, sck): + setmsg = "SET %s %s %s" %(op_id, var, value) send(sck, setmsg) -def do_get(var, id, sck): - getmsg = "GET %s %s" %(options.id, var) +def do_get(var, op_id, sck): + getmsg = "GET %s %s" %(op_id, var) send(sck, getmsg) if __name__ == '__main__': + random.seed() + parser = OptionParser("Usage: %prog [options] var [value]") parser.add_option("-d", "--host", dest="host", help="connect to HOST", metavar="HOST") @@ -54,7 +56,7 @@ dest="cmd_get", help="perform GET operation") parser.add_option("-s", "--set", action="store_true", dest="cmd_set", help="perform SET operation") - parser.add_option("-i", "--id", dest="id", default="1", + parser.add_option("-i", "--id", dest="op_id", default=random.randint(1, sys.maxint), help="set id manually", metavar="ID") parser.add_option("-v", "--verbose", action="store_true", dest="verbose", help="be verbose", default=False) @@ -79,12 +81,12 @@ if options.cmd_set: if len(args) < 2: parser.error("Set requires var and value arguments") - do_set(args[0], ' '.join(args[1:]), options.id, sock) + do_set(args[0], ' '.join(args[1:]), options.op_id, sock) if options.cmd_get: if len(args) != 1: parser.error("Get requires the var argument") - do_get(args[0], options.id, sock) + do_get(args[0], options.op_id, sock) data = sock.recv(1024) while (len(data)>0): -- To view, visit https://gerrit.osmocom.org/657 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I32236c067360526f4e7ee4bbdba64c5137de696d Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max From gerrit-no-reply at lists.osmocom.org Mon Aug 8 10:20:01 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Mon, 8 Aug 2016 10:20:01 +0000 Subject: [PATCH] openbsc[master]: Add python functions to get/set ctrl variables Message-ID: Review at https://gerrit.osmocom.org/658 Add python functions to get/set ctrl variables Add get_var and set_var functions which handle requested variable while checking for proper response and id. Split header handling into separate function. Change-Id: I08705963c277bd93a011193dd7451a626d606c21 Related: OS#1646 --- M openbsc/contrib/bsc_control.py 1 file changed, 31 insertions(+), 4 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/58/658/1 diff --git a/openbsc/contrib/bsc_control.py b/openbsc/contrib/bsc_control.py index 4fc8b4d..e7793b9 100755 --- a/openbsc/contrib/bsc_control.py +++ b/openbsc/contrib/bsc_control.py @@ -10,15 +10,20 @@ def prefix_ipa_ctrl_header(data): return struct.pack(">HBB", len(data)+1, 0xee, 0) + data +def ipa_ctrl_header(header): + (plen, ipa_proto, osmo_proto) = struct.unpack(">HBB", header) + if (ipa_proto != 0xee or osmo_proto != 0): + return None + return plen + def remove_ipa_ctrl_header(data): if (len(data) < 4): raise BaseException("Answer too short!") - (plen, ipa_proto, osmo_proto) = struct.unpack(">HBB", data[:4]) + plen = ipa_ctrl_header(data[:4]) + if (None == plen): + raise BaseException("Wrong protocol in answer!") if (plen + 3 > len(data)): print "Warning: Wrong payload length (expected %i, got %i)" % (plen, len(data) - 3) - if (ipa_proto != 0xee or osmo_proto != 0): - raise BaseException("Wrong protocol in answer!") - return data[4:plen+3], data[plen+3:] def connect(host, port): @@ -44,6 +49,28 @@ getmsg = "GET %s %s" %(op_id, var) send(sck, getmsg) +def do_set_get(sck, var, is_get = True, value = None): + r = random.randint(1, sys.maxint) + if (is_get): + s = 'GET_REPLY' + do_get(var, r, sck) + else: + s = 'SET_REPLY' + do_set(var, value, r, sck) + (answer, data) = remove_ipa_ctrl_header(sck.recv(4096)) + x = answer.split() + if (s == x[0] and str(r) == x[1] and var == x[2]): + if (not is_get and value != x[3]): + return None + return x[3] + return None + +def set_var(sck, var, val): + return do_set_get(sck, var, False, val) + +def get_var(sck, var): + return do_set_get(sck, var) + if __name__ == '__main__': random.seed() -- To view, visit https://gerrit.osmocom.org/658 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I08705963c277bd93a011193dd7451a626d606c21 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max From gerrit-no-reply at lists.osmocom.org Mon Aug 8 10:20:02 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Mon, 8 Aug 2016 10:20:02 +0000 Subject: [PATCH] openbsc[master]: Add web proxy for control interface Message-ID: Review at https://gerrit.osmocom.org/659 Add web proxy for control interface Add web application exposing Control Interface over web. Only SET and GET are fully supported - TRAP support is incomplete at the moment. Change-Id: I87d40c80061f8b3d02d656ab8cadabbfb871b461 Related: OS#1646 --- A openbsc/contrib/ctrl2sse.py 1 file changed, 140 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/59/659/1 diff --git a/openbsc/contrib/ctrl2sse.py b/openbsc/contrib/ctrl2sse.py new file mode 100755 index 0000000..9fce3d3 --- /dev/null +++ b/openbsc/contrib/ctrl2sse.py @@ -0,0 +1,140 @@ +#!/usr/bin/python2 + +mod_license = """ +/* + * Copyright (C) 2016 sysmocom s.f.m.c. GmbH + * + * All Rights Reserved + * + * 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +""" + +import sys, argparse, random, logging, tornado.ioloop, tornado.web, tornado.tcpclient, eventsource, bsc_control +from eventsource import listener + +""" +N. B: this is not an example of building proper REST API or building secure web application. +It's only purpose is to illustrate conversion of Osmocom's Control Interface to web-friendly API. +Exposing this to Internet while connected to production network might lead to all sorts of mischief and mayhem +from NSA' TAO breaking into your network to zombie apocalypse. Do NOT do that. +""" + +stream = None + +def read_header(data): + t_length = bsc_control.ipa_ctrl_header(data) + if (t_length): + stream.read_bytes(t_length - 1, callback = read_trap) + else: + print >> sys.stderr, "protocol error: length missing in %s!" % data + +def read_trap(data): + (t, z, v, p) = data.split() + if (t != 'TRAP' or int(z) != 0): + print >> sys.stderr, "protocol error: TRAP != %s or 0! = %d" % (t, int(z)) + (imsi, ip) = p.split(',') + print >> sys.stderr, "X=%s, IMSI=%s, IP=%s" % (v, imsi, ip) + stream.read_bytes(4, callback = read_header) + + at tornado.gen.coroutine +def trap_setup(host, port): + global stream + stream = yield tornado.tcpclient.TCPClient().connect(host, port) + stream.read_bytes(4, callback = read_header) + +def d(s, v): + return { + 'interface' : tornado.escape.json_encode(s.getpeername()), + 'variable' : v, + 'value' : bsc_control.get_var(s, tornado.escape.native_str(v)) + } + +class CtrlHandler(tornado.web.RequestHandler): + ''' + Return json according to following schema - see http://json-schema.org/documentation.html for details: + { + "title": "Ctrl Schema", + "type": "object", + "properties": { + "interface": { + "type": "string" + }, + "variable": { + "type": "string" + }, + "varlue": { + "type": "string" + } + }, + "required": ["interface", "variable", "value"] + } + Example validation from command-line: + json validate --schema-file=schema.json --document-file=data.json + The interface is represented as string because it might look different for IPv4 vs v6. + ''' + def initialize(self): + self.skt = bsc_control.connect(self.settings['host'], self.settings['port']) + + def get(self, v): + self.write(d(self.skt, v)) + + def post(self): + self.write(d(self.skt, self.get_argument("variable"))) + +class SetCtrl(CtrlHandler): + def get(self, var, val): + bsc_control.set_var(self.skt, tornado.escape.native_str(var), tornado.escape.native_str(val)) + super(SetCtrl, self).get(tornado.escape.native_str(var)) + + def post(self): + bsc_control.set_var(self.skt, tornado.escape.native_str(self.get_argument("variable")), tornado.escape.native_str(self.get_argument("value"))) + super(SetCtrl, self).post() + +class Slash(tornado.web.RequestHandler): + def get(self): + self.write('' + '
' + '' + '' + '
' + '
' + '' + '' + '' + '
' + '') + +if __name__ == '__main__': + p = argparse.ArgumentParser(description='Osmocom Control Interface proxy.') +# p.add_argument('-c', '--control-port', type = int, default = 4252, help = 'Target Control Interface port') + p.add_argument('-c', '--control-port', type = int, default = 4249, help = 'Target Control Interface port') + p.add_argument('-a', '--control-host', default = 'localhost', help = 'Target Control Interface adress') + p.add_argument('-p', '--port', type = int, default = 6969, help = "Port to bind proxy's web interface") + args = p.parse_args() + tornado.netutil.Resolver.configure('tornado.netutil.ThreadedResolver') # Use non-blocking resolver + logging.basicConfig() + application = tornado.web.Application([ + (r"/", Slash), + (r"/get", CtrlHandler), + (r"/get/(.*)", CtrlHandler), + (r"/set", SetCtrl), + (r"/set/(.*)/(.*)", SetCtrl), + (r"/sse/(.*)/(.*)", listener.EventSourceHandler, dict(event_class = listener.StringIdEvent, keepalive = 100)), + ], debug = True, host = args.control_host, port = args.control_port) + random.seed() + application.listen(args.port) + trap_setup(application.settings['host'], 4252) + tornado.ioloop.IOLoop.instance().start() -- To view, visit https://gerrit.osmocom.org/659 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I87d40c80061f8b3d02d656ab8cadabbfb871b461 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max From gerrit-no-reply at lists.osmocom.org Mon Aug 8 11:02:18 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 8 Aug 2016 11:02:18 +0000 Subject: libosmocore[master]: Add function to send TRAP over Control Interface In-Reply-To: References: Message-ID: Patch Set 1: Code-Review-1 (1 comment) https://gerrit.osmocom.org/#/c/649/1/src/ctrl/control_if.c File src/ctrl/control_if.c: Line 126: int ctrl_cmd_send_trap(struct ctrl_handle *ctrl, char *name, char *value) why mutable? Who owns name and value? -- To view, visit https://gerrit.osmocom.org/649 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ic0b8d88c4f5c4d42c3f8fb754f8eabf049c9e388 Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Mon Aug 8 11:04:06 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 8 Aug 2016 11:04:06 +0000 Subject: osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Patch Set 8: > (1 comment) I am afraid most comments still stand. * Wrong usage of talloc * T4 support not in a standalone file (making moving it back to libosmocore difficult) -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 8 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: pravin Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 8 11:10:35 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Mon, 8 Aug 2016 11:10:35 +0000 Subject: libosmocore[master]: Add function to send TRAP over Control Interface In-Reply-To: References: Message-ID: Patch Set 1: (1 comment) https://gerrit.osmocom.org/#/c/649/1/src/ctrl/control_if.c File src/ctrl/control_if.c: Line 126: int ctrl_cmd_send_trap(struct ctrl_handle *ctrl, char *name, char *value) > why mutable? Who owns name and value? Because I have not found a way to make it const without adding extra warnings - advices are appreciated. The problem is that it's called by openggsn which does not use talloc. The values are owned by caller for the time being but I don't mind changing it - those are created just for this function so it doesn't really matter from caller's perspective. -- To view, visit https://gerrit.osmocom.org/649 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ic0b8d88c4f5c4d42c3f8fb754f8eabf049c9e388 Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Mon Aug 8 11:12:07 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 8 Aug 2016 11:12:07 +0000 Subject: [PATCH] osmo-bts[master]: Add .mailmap for mapping mail addresses in shortlog Message-ID: Review at https://gerrit.osmocom.org/660 Add .mailmap for mapping mail addresses in shortlog Change-Id: I4789197e18fba6b1a376dc8645fdffa6120f6698 --- A .mailmap 1 file changed, 12 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/60/660/1 diff --git a/.mailmap b/.mailmap new file mode 100644 index 0000000..cda4057 --- /dev/null +++ b/.mailmap @@ -0,0 +1,12 @@ +Harald Welte +Harald Welte +Harald Welte +Holger Hans Peter Freyther +Holger Hans Peter Freyther +Holger Hans Peter Freyther +Andreas Eversberg +Andreas Eversberg +Andreas Eversberg +Pablo Neira Ayuso +Max Suraev +Tom Tsou -- To view, visit https://gerrit.osmocom.org/660 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I4789197e18fba6b1a376dc8645fdffa6120f6698 Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Harald Welte From gerrit-no-reply at lists.osmocom.org Mon Aug 8 11:12:55 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 8 Aug 2016 11:12:55 +0000 Subject: [PATCH] libosmocore[master]: Add .mailmap file for mapping mail addresses in shortlog Message-ID: Review at https://gerrit.osmocom.org/661 Add .mailmap file for mapping mail addresses in shortlog Change-Id: Id6b42bb9ab10f46b76b26057c8228e5da480286d --- A .mailmap 1 file changed, 12 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/61/661/1 diff --git a/.mailmap b/.mailmap new file mode 100644 index 0000000..cda4057 --- /dev/null +++ b/.mailmap @@ -0,0 +1,12 @@ +Harald Welte +Harald Welte +Harald Welte +Holger Hans Peter Freyther +Holger Hans Peter Freyther +Holger Hans Peter Freyther +Andreas Eversberg +Andreas Eversberg +Andreas Eversberg +Pablo Neira Ayuso +Max Suraev +Tom Tsou -- To view, visit https://gerrit.osmocom.org/661 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Id6b42bb9ab10f46b76b26057c8228e5da480286d Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Harald Welte From gerrit-no-reply at lists.osmocom.org Mon Aug 8 11:14:39 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 8 Aug 2016 11:14:39 +0000 Subject: [PATCH] openbsc[master]: add .mailmap file for mapping git author name/mail in shortlog Message-ID: Review at https://gerrit.osmocom.org/662 add .mailmap file for mapping git author name/mail in shortlog Change-Id: I7ed97fb897895935f942e3eb4fd87a8c138417be --- A .mailmap 1 file changed, 7 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/62/662/1 diff --git a/.mailmap b/.mailmap new file mode 100644 index 0000000..9b737d2 --- /dev/null +++ b/.mailmap @@ -0,0 +1,7 @@ +Harald Welte +Harald Welte +Holger Hans Peter Freyther +Holger Hans Peter Freyther +Andreas Eversberg +Andreas Eversberg +Pablo Neira Ayuso -- To view, visit https://gerrit.osmocom.org/662 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I7ed97fb897895935f942e3eb4fd87a8c138417be Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Harald Welte From gerrit-no-reply at lists.osmocom.org Mon Aug 8 11:14:48 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 8 Aug 2016 11:14:48 +0000 Subject: [PATCH] openbsc[master]: add .mailmap file for mapping git author name/mail in shortlog In-Reply-To: References: Message-ID: add .mailmap file for mapping git author name/mail in shortlog Change-Id: I7ed97fb897895935f942e3eb4fd87a8c138417be --- A .mailmap 1 file changed, 12 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/62/662/2 diff --git a/.mailmap b/.mailmap new file mode 100644 index 0000000..cda4057 --- /dev/null +++ b/.mailmap @@ -0,0 +1,12 @@ +Harald Welte +Harald Welte +Harald Welte +Holger Hans Peter Freyther +Holger Hans Peter Freyther +Holger Hans Peter Freyther +Andreas Eversberg +Andreas Eversberg +Andreas Eversberg +Pablo Neira Ayuso +Max Suraev +Tom Tsou -- To view, visit https://gerrit.osmocom.org/662 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I7ed97fb897895935f942e3eb4fd87a8c138417be Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Harald Welte From gerrit-no-reply at lists.osmocom.org Mon Aug 8 11:29:30 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 8 Aug 2016 11:29:30 +0000 Subject: openbsc[master]: add .mailmap file for mapping git author name/mail in shortlog In-Reply-To: References: Message-ID: Patch Set 2: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/662 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I7ed97fb897895935f942e3eb4fd87a8c138417be Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Harald Welte Gerrit-Reviewer: Harald Welte Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 8 11:29:34 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 8 Aug 2016 11:29:34 +0000 Subject: openbsc[master]: add .mailmap file for mapping git author name/mail in shortlog In-Reply-To: References: Message-ID: Patch Set 2: Verified+1 -- To view, visit https://gerrit.osmocom.org/662 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I7ed97fb897895935f942e3eb4fd87a8c138417be Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Harald Welte Gerrit-Reviewer: Harald Welte Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 8 11:29:45 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 8 Aug 2016 11:29:45 +0000 Subject: openbsc[master]: add example config for sysmobts In-Reply-To: References: Message-ID: Patch Set 1: Verified+1 -- To view, visit https://gerrit.osmocom.org/639 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I94ae57c9a3cb497ca39d56270fa15ed65d7f147e Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Harald Welte Gerrit-Reviewer: Harald Welte Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 8 11:30:07 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 8 Aug 2016 11:30:07 +0000 Subject: libosmocore[master]: Add .mailmap file for mapping mail addresses in shortlog In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/661 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Id6b42bb9ab10f46b76b26057c8228e5da480286d Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Harald Welte Gerrit-Reviewer: Harald Welte Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 8 11:30:09 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 8 Aug 2016 11:30:09 +0000 Subject: libosmocore[master]: Add .mailmap file for mapping mail addresses in shortlog In-Reply-To: References: Message-ID: Patch Set 1: Verified+1 -- To view, visit https://gerrit.osmocom.org/661 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Id6b42bb9ab10f46b76b26057c8228e5da480286d Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Harald Welte Gerrit-Reviewer: Harald Welte Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 8 11:30:11 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 8 Aug 2016 11:30:11 +0000 Subject: [MERGED] libosmocore[master]: Add .mailmap file for mapping mail addresses in shortlog In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: Add .mailmap file for mapping mail addresses in shortlog ...................................................................... Add .mailmap file for mapping mail addresses in shortlog Change-Id: Id6b42bb9ab10f46b76b26057c8228e5da480286d --- A .mailmap 1 file changed, 12 insertions(+), 0 deletions(-) Approvals: Harald Welte: Looks good to me, approved; Verified diff --git a/.mailmap b/.mailmap new file mode 100644 index 0000000..cda4057 --- /dev/null +++ b/.mailmap @@ -0,0 +1,12 @@ +Harald Welte +Harald Welte +Harald Welte +Holger Hans Peter Freyther +Holger Hans Peter Freyther +Holger Hans Peter Freyther +Andreas Eversberg +Andreas Eversberg +Andreas Eversberg +Pablo Neira Ayuso +Max Suraev +Tom Tsou -- To view, visit https://gerrit.osmocom.org/661 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: Id6b42bb9ab10f46b76b26057c8228e5da480286d Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Harald Welte Gerrit-Reviewer: Harald Welte From gerrit-no-reply at lists.osmocom.org Mon Aug 8 11:30:19 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 8 Aug 2016 11:30:19 +0000 Subject: osmo-bts[master]: Add .mailmap for mapping mail addresses in shortlog In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/660 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I4789197e18fba6b1a376dc8645fdffa6120f6698 Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Harald Welte Gerrit-Reviewer: Harald Welte Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 8 11:30:22 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 8 Aug 2016 11:30:22 +0000 Subject: osmo-bts[master]: Add .mailmap for mapping mail addresses in shortlog In-Reply-To: References: Message-ID: Patch Set 1: Verified+1 -- To view, visit https://gerrit.osmocom.org/660 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I4789197e18fba6b1a376dc8645fdffa6120f6698 Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Harald Welte Gerrit-Reviewer: Harald Welte Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 8 11:31:03 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 8 Aug 2016 11:31:03 +0000 Subject: osmo-bts[master]: Add .mailmap for mapping mail addresses in shortlog In-Reply-To: References: Message-ID: Patch Set 2: Verified+1 -- To view, visit https://gerrit.osmocom.org/660 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I4789197e18fba6b1a376dc8645fdffa6120f6698 Gerrit-PatchSet: 2 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Harald Welte Gerrit-Reviewer: Harald Welte Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 8 11:31:06 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 8 Aug 2016 11:31:06 +0000 Subject: [MERGED] osmo-bts[master]: Add .mailmap for mapping mail addresses in shortlog In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: Add .mailmap for mapping mail addresses in shortlog ...................................................................... Add .mailmap for mapping mail addresses in shortlog Change-Id: I4789197e18fba6b1a376dc8645fdffa6120f6698 --- A .mailmap 1 file changed, 12 insertions(+), 0 deletions(-) Approvals: Harald Welte: Looks good to me, approved; Verified diff --git a/.mailmap b/.mailmap new file mode 100644 index 0000000..cda4057 --- /dev/null +++ b/.mailmap @@ -0,0 +1,12 @@ +Harald Welte +Harald Welte +Harald Welte +Holger Hans Peter Freyther +Holger Hans Peter Freyther +Holger Hans Peter Freyther +Andreas Eversberg +Andreas Eversberg +Andreas Eversberg +Pablo Neira Ayuso +Max Suraev +Tom Tsou -- To view, visit https://gerrit.osmocom.org/660 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I4789197e18fba6b1a376dc8645fdffa6120f6698 Gerrit-PatchSet: 2 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Harald Welte Gerrit-Reviewer: Harald Welte From gerrit-no-reply at lists.osmocom.org Mon Aug 8 11:31:21 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 8 Aug 2016 11:31:21 +0000 Subject: openbsc[master]: add .mailmap file for mapping git author name/mail in shortlog In-Reply-To: References: Message-ID: Patch Set 4: Verified+1 -- To view, visit https://gerrit.osmocom.org/662 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I7ed97fb897895935f942e3eb4fd87a8c138417be Gerrit-PatchSet: 4 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Harald Welte Gerrit-Reviewer: Harald Welte Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 8 11:31:57 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Mon, 8 Aug 2016 11:31:57 +0000 Subject: [PATCH] openbsc[master]: Add web proxy for control interface In-Reply-To: References: Message-ID: Add web proxy for control interface Add web application exposing Control Interface over web. Only SET and GET are fully supported - TRAP support is incomplete at the moment. Change-Id: I87d40c80061f8b3d02d656ab8cadabbfb871b461 Related: OS#1646 --- A openbsc/contrib/ctrl2sse.py 1 file changed, 140 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/59/659/2 diff --git a/openbsc/contrib/ctrl2sse.py b/openbsc/contrib/ctrl2sse.py new file mode 100755 index 0000000..65770eb --- /dev/null +++ b/openbsc/contrib/ctrl2sse.py @@ -0,0 +1,140 @@ +#!/usr/bin/python2 + +mod_license = """ +/* + * Copyright (C) 2016 sysmocom s.f.m.c. GmbH + * + * All Rights Reserved + * + * 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +""" + +import sys, argparse, random, logging, tornado.ioloop, tornado.web, tornado.tcpclient, eventsource, bsc_control +from eventsource import listener + +""" +N. B: this is not an example of building proper REST API or building secure web application. +It's only purpose is to illustrate conversion of Osmocom's Control Interface to web-friendly API. +Exposing this to Internet while connected to production network might lead to all sorts of mischief and mayhem +from NSA' TAO breaking into your network to zombie apocalypse. Do NOT do that. +""" + +stream = None + +def read_header(data): + t_length = bsc_control.ipa_ctrl_header(data) + if (t_length): + stream.read_bytes(t_length - 1, callback = read_trap) + else: + print >> sys.stderr, "protocol error: length missing in %s!" % data + +def read_trap(data): + (t, z, v, p) = data.split() + if (t != 'TRAP' or int(z) != 0): + print >> sys.stderr, "protocol error: TRAP != %s or 0! = %d" % (t, int(z)) + (imsi, ip) = p.split(',') + print >> sys.stderr, "X=%s, IMSI=%s, IP=%s" % (v, imsi, ip) + stream.read_bytes(4, callback = read_header) + + at tornado.gen.coroutine +def trap_setup(host, port): + global stream + stream = yield tornado.tcpclient.TCPClient().connect(host, port) + stream.read_bytes(4, callback = read_header) + +def d(s, v): + return { + 'interface' : tornado.escape.json_encode(s.getpeername()), + 'variable' : v, + 'value' : bsc_control.get_var(s, tornado.escape.native_str(v)) + } + +class CtrlHandler(tornado.web.RequestHandler): + ''' + Return json according to following schema - see http://json-schema.org/documentation.html for details: + { + "title": "Ctrl Schema", + "type": "object", + "properties": { + "interface": { + "type": "string" + }, + "variable": { + "type": "string" + }, + "varlue": { + "type": "string" + } + }, + "required": ["interface", "variable", "value"] + } + Example validation from command-line: + json validate --schema-file=schema.json --document-file=data.json + The interface is represented as string because it might look different for IPv4 vs v6. + ''' + def initialize(self): + self.skt = bsc_control.connect(self.settings['host'], self.settings['port']) + + def get(self, v): + self.write(d(self.skt, v)) + + def post(self): + self.write(d(self.skt, self.get_argument("variable"))) + +class SetCtrl(CtrlHandler): + def get(self, var, val): + bsc_control.set_var(self.skt, tornado.escape.native_str(var), tornado.escape.native_str(val)) + super(SetCtrl, self).get(tornado.escape.native_str(var)) + + def post(self): + bsc_control.set_var(self.skt, tornado.escape.native_str(self.get_argument("variable")), tornado.escape.native_str(self.get_argument("value"))) + super(SetCtrl, self).post() + +class Slash(tornado.web.RequestHandler): + def get(self): + self.write('' + '
' + '' + '' + '
' + '
' + '' + '' + '' + '
' + '') + +if __name__ == '__main__': + p = argparse.ArgumentParser(description='Osmocom Control Interface proxy.') +# p.add_argument('-c', '--control-port', type = int, default = 4252, help = 'Target Control Interface port') + p.add_argument('-c', '--control-port', type = int, default = 4249, help = 'Target Control Interface port') + p.add_argument('-a', '--control-host', default = 'localhost', help = 'Target Control Interface adress') + p.add_argument('-p', '--port', type = int, default = 6969, help = "Port to bind proxy's web interface") + args = p.parse_args() + tornado.netutil.Resolver.configure('tornado.netutil.ThreadedResolver') # Use non-blocking resolver + logging.basicConfig() + application = tornado.web.Application([ + (r"/", Slash), + (r"/get", CtrlHandler), + (r"/get/(.*)", CtrlHandler), + (r"/set", SetCtrl), + (r"/set/(.*)/(.*)", SetCtrl), + (r"/sse/(.*)/(.*)", listener.EventSourceHandler, dict(event_class = listener.StringIdEvent, keepalive = 100)), + ], debug = True, host = args.control_host, port = args.control_port) + random.seed() + application.listen(args.port) + trap_setup(application.settings['host'], 4252) + tornado.ioloop.IOLoop.instance().start() -- To view, visit https://gerrit.osmocom.org/659 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I87d40c80061f8b3d02d656ab8cadabbfb871b461 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max From gerrit-no-reply at lists.osmocom.org Mon Aug 8 11:43:22 2016 From: gerrit-no-reply at lists.osmocom.org (pravin) Date: Mon, 8 Aug 2016 11:43:22 +0000 Subject: osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Patch Set 8: > > (1 comment) > > I am afraid most comments still stand. > > * Wrong usage of talloc > * T4 support not in a standalone file (making moving it back to > libosmocore difficult) New context tall_tree_ctx is created under tall_pcu_ctx and this new context is used for memory allocation of tree nodes. All functions are defined in a standalone file egprs_rlc_compression.cpp. Currently function decompress_crbb is part of class Decoding. We will remove the declaration from decoding.h and add it in egprs_rlc_compression.h. Please confirm if your comment refers to the same. -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 8 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: pravin Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 8 13:14:31 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 8 Aug 2016 13:14:31 +0000 Subject: osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Patch Set 8: (11 comments) https://gerrit.osmocom.org/#/c/416/8/src/egprs_rlc_compression.cpp File src/egprs_rlc_compression.cpp: Line 14: void *tall_tree_ctx; Every allocation by talloc is a talloc context, no need to create an artificial context here. If you do it needs to be anchored with the "root" context so it shows up in leak detection. Line 22: new_node = talloc(tall_tree_ctx, Node); pass the parent or root as talloc context and use that and use that.. use talloc_zero. Line 227: int search_runlen( static and if not static make this proper doxygen comments Line 244: /* get the bit value at the bitpos and put it in right most of dir */ wrong indent Line 261: } /* search_runlen */ what value does this provide? Line 263: int Decoding::decompress_crbb( doxygen comments.. and document all variables Line 310: } /* Decompress_CRBB */ This comment doesn't provide much info. remove it. https://gerrit.osmocom.org/#/c/416/8/src/pcu_main.cpp File src/pcu_main.cpp: Line 172: tall_tree_ctx = talloc_named_const(tall_pcu_ctx, 0, "decode-tree context"); nack. https://gerrit.osmocom.org/#/c/416/8/tests/tbf/TbfTest.cpp File tests/tbf/TbfTest.cpp: Line 43: #define NUMBER_OF_TEST_CASE 9 Move T4 testcases into a dedicated t4 test directory/application. Line 57: }test[NUMBER_OF_TEST_CASE] = { { (int8_t)67, (uint8_t)1, {0x02, 0x0c, 0xa0, 0x30, 0xcb, 0x1a, 0x0c, 0xe3, 0x6c}, Let the compiler count it for you. If you want to make sure it is 9.. then use a static assert comparing the array size with your magic number Line 1624: tall_tree_ctx = talloc_named_const(tall_pcu_ctx, 0, "decode-tree context"); How many other talloc users do you see that do that? It could be a hint that this is not the correct way? -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 8 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: pravin Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Mon Aug 8 13:32:16 2016 From: gerrit-no-reply at lists.osmocom.org (pravin) Date: Mon, 8 Aug 2016 13:32:16 +0000 Subject: [PATCH] osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Hello Max, Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/416 to look at the new patch set (#9). Add decoding of compressed bitmap in EPDAN Implemented tree based algorithm to decode compressed bitmap in EPDAN as described in section 9.1.10 of 3GPP 44.060. This algorithm intends to improve the performance over existing method. Test case is added to validate decompressed result of the bitmap Present in EPDAN. Test is done for multiple bitmaps of varying length. Invalid inputs are also part of the test vector. Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce --- M src/Makefile.am M src/decoding.cpp M src/decoding.h A src/egprs_rlc_compression.cpp A src/egprs_rlc_compression.h M src/pcu_main.cpp M tests/tbf/TbfTest.cpp 7 files changed, 493 insertions(+), 27 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/16/416/9 diff --git a/src/Makefile.am b/src/Makefile.am index 9bdec2f..9b047e7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -62,7 +62,8 @@ rlc.cpp \ osmobts_sock.cpp \ gprs_codel.c \ - gprs_coding_scheme.cpp + gprs_coding_scheme.cpp \ + egprs_rlc_compression.cpp bin_PROGRAMS = \ osmo-pcu @@ -94,7 +95,8 @@ pcu_utils.h \ cxx_linuxlist.h \ gprs_codel.h \ - gprs_coding_scheme.h + gprs_coding_scheme.h \ + egprs_rlc_compression.h osmo_pcu_SOURCES = pcu_main.cpp diff --git a/src/decoding.cpp b/src/decoding.cpp index 7c00ff7..dd70460 100644 --- a/src/decoding.cpp +++ b/src/decoding.cpp @@ -20,6 +20,7 @@ #include #include #include +#include extern "C" { #include @@ -651,11 +652,10 @@ int crbb_len = 0; int num_blocks = 0; struct bitvec urbb; - int i; + int i, rc; bool have_bitmap; int implicitly_acked_blocks; int ssn = desc->STARTING_SEQUENCE_NUMBER; - int rc; if (desc->FINAL_ACK_INDICATION) return handle_final_ack(bits, bsn_begin, bsn_end, window); @@ -695,27 +695,22 @@ if (crbb_len > 0) { int old_len = bits->cur_bit; - struct bitvec crbb; - crbb.data = (uint8_t *)desc->CRBB; - crbb.data_len = sizeof(desc->CRBB); - crbb.cur_bit = desc->CRBB_LENGTH; - - rc = osmo_t4_decode(&crbb, desc->CRBB_STARTING_COLOR_CODE, - bits); - + LOGP(DRLCMACDL, LOGL_DEBUG, "Compress bitmap exist," + "CRBB LEN =%d and Starting color code =%d", + desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE); + rc = decompress_crbb(desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE, + desc->CRBB, bits); if (rc < 0) { LOGP(DRLCMACUL, LOGL_NOTICE, - "Failed to decode CRBB: " - "length %d, data '%s'\n", - desc->CRBB_LENGTH, - osmo_hexdump(crbb.data, crbb.data_len)); + "Failed to decode CRBB: length %d, data '%s'\n", + desc->CRBB_LENGTH, osmo_hexdump( + desc->CRBB, (desc->CRBB_LENGTH + 7)/8)); /* We don't know the SSN offset for the URBB, - * return what we have so far and assume the - * bitmap has stopped here */ + * return what we have so far and assume the + * bitmap has stopped here */ goto aborted; } - LOGP(DRLCMACDL, LOGL_DEBUG, "CRBB len: %d, decoded len: %d, cc: %d, crbb: '%s'\n", desc->CRBB_LENGTH, bits->cur_bit - old_len, diff --git a/src/decoding.h b/src/decoding.h index d1371d5..33f6199 100644 --- a/src/decoding.h +++ b/src/decoding.h @@ -76,6 +76,6 @@ struct gprs_rlc_dl_window *window); static int decode_gprs_acknack_bits( const Ack_Nack_Description_t *desc, - bitvec *bits, int *bsn_begin, int *bsn_end, - gprs_rlc_dl_window *window); + bitvec * bits, int *bsn_begin, int *bsn_end, + gprs_rlc_dl_window * window); }; diff --git a/src/egprs_rlc_compression.cpp b/src/egprs_rlc_compression.cpp new file mode 100644 index 0000000..b0e68a2 --- /dev/null +++ b/src/egprs_rlc_compression.cpp @@ -0,0 +1,310 @@ +/* egprs_rlc_compression.h +* Routines for EGPRS RLC bitmap compression handling +*/ +#include +#include +#include + +extern "C" { +#include +#include +#include +} + +void *tall_tree_ctx; +egprs_compress *egprs_compress::s_instance = 0; +Node *egprs_compress::ones_list = NULL; +Node *egprs_compress::zeros_list = NULL; + +Node *egprs_compress::create_tree_node() +{ + Node *new_node; + new_node = talloc(tall_tree_ctx, Node); + new_node->left = NULL; + new_node->right = NULL; + new_node->run_length = -1; + return new_node; +} + +void egprs_compress::build_codeword(Node *root, const char *cdwd[]) +{ + Node *iter; /* iterate the node on the tree */ + int len; /* length of the code word */ + int i; /* iterater */ + int idx; /* interate index of the code word table */ + + root->left = NULL; + root->right = NULL; + root->run_length = -1; + + for (idx = 0; idx < MAX_CDWDTBL_LEN; idx++) { + len = strlen((const char *)cdwd[idx]); + iter = root; + for (i = 0; i < len; i++) { + if (cdwd[idx][i] == '0') { + if (iter->left == NULL) + iter->left = create_tree_node(); + iter = iter->left; + } else if (cdwd[idx][i] == '1') { + if (iter->right == NULL) + iter->right = create_tree_node(); + iter = iter->right; + } + } + if (iter != NULL) { + if (idx < 64) + (iter->run_length) = idx; + else + (iter->run_length) = (idx - 63) * 64; + } + } +} + +const char *one_run_len_code_list[MAX_CDWDTBL_LEN] = { + "00110101", + "000111", + "0111", + "1000", + "1011", + "1100", + "1110", + "1111", + "10011", + "10100", + "00111", + "01000", + "001000", + "000011", + "110100", + "110101", + "101010", + "101011", + "0100111", + "0001100", + "0001000", + "0010111", + "0000011", + "0000100", + "0101000", + "0101011", + "0010011", + "0100100", + "0011000", + "00000010", + "00000011", + "00011010", + "00011011", + "00010010", + "00010011", + "00010100", + "00010101", + "00010110", + "00010111", + "00101000", + "00101001", + "00101010", + "00101011", + "00101100", + "00101101", + "00000100", + "00000101", + "00001010", + "00001011", + "01010010", + "01010011", + "01010100", + "01010101", + "00100100", + "00100101", + "01011000", + "01011001", + "01011010", + "01011011", + "01001010", + "01001011", + "00110010", + "00110011", + "00110100", + "11011", + "10010", + "010111", + "0110111", + "00110110", + "00110111", + "01100100", + "01100101", + "01101000", + "01100111", + "011001100", + "011001101", + "011010010", + "011010011", + "011010100" +}; + +const char *zero_run_len_code_list[MAX_CDWDTBL_LEN] = { + "0000110111", + "10", + "11", + "010", + "011", + "0011", + "0010", + "00011", + "000101", + "000100", + "0000100", + "0000101", + "0000111", + "00000100", + "00000111", + "000011000", + "0000010111", + "0000011000", + "0000001000", + "00001100111", + "00001101000", + "00001101100", + "00000110111", + "00000101000", + "00000010111", + "00000011000", + "000011001010", + "000011001011", + "000011001100", + "000011001101", + "000001101000", + "000001101001", + "000001101010", + "000001101011", + "000011010010", + "000011010011", + "000011010100", + "000011010101", + "000011010110", + "000011010111", + "000001101100", + "000001101101", + "000011011010", + "000011011011", + "000001010100", + "000001010101", + "000001010110", + "000001010111", + "000001100100", + "000001100101", + "000001010010", + "000001010011", + "000000100100", + "000000110111", + "000000111000", + "000000100111", + "000000101000", + "000001011000", + "000001011001", + "000000101011", + "000000101100", + "000001011010", + "000001100110", + "000001100111", + "0000001111", + "000011001000", + "000011001001", + "000001011011", + "000000110011", + "000000110100", + "000000110101", + "0000001101100", + "0000001101101", + "0000001001010", + "0000001001011", + "0000001001100", + "0000001001101", + "0000001110010", + "0000001110011" +}; + +int search_runlen( + Node *root, /* root of Ones or Zeros tree */ + const uint8_t *bmbuf, /* Received compressed bitmap buf */ + uint8_t bit_pos, /* the start bit pos to read codeword */ + uint8_t *len_codewd, /* length of code word */ + uint16_t *rlen) +{ + Node *iter; + uint8_t dir; + + iter = root; + *len_codewd = 0; + + while (iter->run_length == -1) { + if ((iter->left == NULL) && (iter->right == NULL)) + return -1; + + /* get the bit value at the bitpos and put it in right most of dir */ + dir = ((bmbuf[BITS_TO_BYTES(bit_pos)-1] + >>(7-(MOD8(bit_pos)))) & 0x01); + (bit_pos)++; + (*len_codewd)++; + + if (((dir&0x01) == 0) && (iter->left != NULL)) + iter = iter->left; + + else if (((dir&0x01) == 1) && (iter->right != NULL)) + iter = iter->right; + else + return -1; + } + (*rlen) = (iter->run_length); + + return 1; +} /* search_runlen */ + +int decompress_crbb( + int8_t compress_bmap_len, /* compressed bitmap length */ + uint8_t clr_code_bit, /* run length of Ones or Zeros */ + const uint8_t *orig_crbb_buf, /* received block crbb bitmap */ + bitvec * dest) +{ + + uint8_t bit_pos = 0; + uint8_t data = 0x0; + node *list = NULL; + uint8_t nbits = 0; /* number of bits of codeword */ + uint16_t run_length = 0; + uint16_t cbmaplen = 0; /* compressed bitmap part after decompression */ + unsigned wp = dest->cur_bit; + int rc = 0; + egprs_compress *compress = egprs_compress::instance(); + + while (compress_bmap_len > 0) { + if (clr_code_bit == 1) { + data = 0xff; + list = compress->ones_list; + } else { + data = 0x00; + list = compress->zeros_list; + } + rc = search_runlen(list, orig_crbb_buf, + bit_pos, &nbits, &run_length); + if (rc == -1) + return -1; + /*If run length > 64, need makeup and terminating code*/ + if (run_length < 64) + clr_code_bit ? clr_code_bit = 0 : clr_code_bit = 1; + cbmaplen = cbmaplen + run_length; + /* put run length of Ones in uncompressed bitmap */ + while (run_length != 0) { + if (run_length > 8) { + bitvec_write_field(dest, wp, data, 8); + run_length = run_length - 8; + } else { + bitvec_write_field(dest, wp, data, run_length); + run_length = 0; + } + } + bit_pos = bit_pos + nbits; + compress_bmap_len = compress_bmap_len - nbits; + } + return 0; +} /* Decompress_CRBB */ diff --git a/src/egprs_rlc_compression.h b/src/egprs_rlc_compression.h new file mode 100644 index 0000000..8e26de1 --- /dev/null +++ b/src/egprs_rlc_compression.h @@ -0,0 +1,67 @@ +/* egprs_rlc_compression.h + * Routines for EGPRS RLC bitmap compression handling + */ +#include +#include + +extern "C" { +#include +} + +#include +#include +#include + +#define MAX_CDWDTBL_LEN 79 /* total number of codewords */ +#define BITS_TO_BYTES(X) ((X ? (X/8):0)+1) +#define MOD8(X) (((X)+8) & (0x07)) + +typedef struct node { + struct node *left; + struct node *right; + int run_length; +} Node; + +extern const char *one_run_len_code_list[MAX_CDWDTBL_LEN]; +extern const char *zero_run_len_code_list[MAX_CDWDTBL_LEN]; +extern void *tall_tree_ctx; + +int decompress_crbb(int8_t compress_bmap_len, uint8_t clr_code_bit, + const uint8_t *orig_buf, bitvec * dest); + +/* Creating singleton class + */ +class egprs_compress +{ + static egprs_compress *s_instance; + egprs_compress() + { + ones_list = talloc(tall_tree_ctx, Node); + zeros_list = talloc(tall_tree_ctx, Node); + } + Node *create_tree_node(); + void build_codeword(Node *root, const char *cdwd[]); + void free_codeword(Node *root); + ~egprs_compress() + { + s_instance = NULL; + } +public: + static Node *ones_list; + static Node *zeros_list; + + void decode_tree_init(void) + { + instance()->build_codeword( + ones_list, one_run_len_code_list); + instance()->build_codeword( + zeros_list, zero_run_len_code_list); + } + static egprs_compress *instance() + { + if (!s_instance) + s_instance = new egprs_compress; + + return s_instance; + } +}; diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2d86cda..ea23ba1 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -28,6 +28,7 @@ #include #include #include +#include extern "C" { #include "pcu_vty.h" #include @@ -168,6 +169,9 @@ if (!tall_pcu_ctx) return -ENOMEM; bv_tall_ctx = tall_pcu_ctx; + tall_tree_ctx = talloc_named_const(tall_pcu_ctx, 0, "decode-tree context"); + if (!tall_tree_ctx) + return -ENOMEM; bts = bts_main_data(); bts->fc_interval = 1; @@ -253,6 +257,8 @@ if (!bts->alloc_algorithm) bts->alloc_algorithm = alloc_algorithm_dynamic; + egprs_compress::instance()->decode_tree_init(); + rc = pcu_l1if_open(); if (rc < 0) @@ -292,6 +298,5 @@ talloc_report_full(tall_pcu_ctx, stderr); talloc_free(tall_pcu_ctx); - return 0; } diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..c13c4d5 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -26,10 +26,11 @@ #include "pcu_utils.h" #include "gprs_bssgp_pcu.h" #include "pcu_l1_if.h" - +#include "egprs_rlc_compression.h" +#include "decoding.h" extern "C" { #include "pcu_vty.h" - +#include #include #include #include @@ -40,8 +41,43 @@ #include +#define NUMBER_OF_TEST_CASE 9 +#define NEW 1 +#define DELTA 1000 +#define MASK(n) (0xFF << (8-n)) +#define MAX_CRBB_LEN 23 +#define MAX_URBB_LEN 40 void *tall_pcu_ctx; +extern void *tall_tree_ctx; int16_t spoof_mnc = 0, spoof_mcc = 0; +struct test_data { + int8_t crbb_len; + uint8_t cc; + uint8_t crbb_data[MAX_CRBB_LEN]; /* compressed data */ + uint8_t ucmp_data[MAX_URBB_LEN]; /* uncompressed data */ + int ucmp_len; + int verify; +}test[NUMBER_OF_TEST_CASE] = { { (int8_t)67, (uint8_t)1, {0x02, 0x0c, 0xa0, 0x30, 0xcb, 0x1a, 0x0c, 0xe3, 0x6c}, + {0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xf8, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, + 0xdb}, (int)194, 1}, + {(int8_t)40, (uint8_t)1, {0x53, 0x06, 0xc5, 0x40, 0x6d}, {0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, + 0x00, 0x00, 0x00, 0x03}, (int)182, 1}, + { (int8_t)8, (uint8_t)1, {0x02}, {0xff, 0xff, 0xff, 0xf8}, (int)29, 1}, + { (int8_t)103, (uint8_t)1, {0x02, 0x0c, 0xe0, 0x41, 0xa0, 0x0c, 0x36, 0x0d, 0x03, + 0x71, 0xb0, 0x6e, 0x24}, {0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xf8, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, + 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff}, + (int)288, 1}, + /* Test vector from libosmocore test */ + { (int8_t)35, (uint8_t)0, {0xde, 0x88, 0x75, 0x65, 0x80}, {0x37, 0x47, 0x81, 0xf0}, (int)28, 1}, + { (int8_t)18, (uint8_t)1, {0xdd, 0x41, 0x00}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00}, (int)90, 1}, + /*Invalid inputs*/ + { (int8_t)18, (uint8_t)1, {0x1E, 0x70, 0xc0}, {0x0}, (int)0, 0}, + { (int8_t)14, (uint8_t)1, {0x00, 0x1E, 0x7c}, {0x0}, (int)0, 0}, + { (int8_t)24, (uint8_t)0, {0x00, 0x00, 0x00}, {0x0}, (int)0, 0} }; static void check_tbf(gprs_rlcmac_tbf *tbf) { @@ -65,6 +101,53 @@ return next_fn; } */ + +/* To verify the result with expected result */ +int check_result(bitvec bits, uint8_t *exp_data, int exp_len) +{ + if (bits.cur_bit != exp_len) + return 0; + size_t n = (exp_len / 8); + int rem = (exp_len % 8); + if (memcmp (exp_data, bits.data, n) == 0) { + if (rem == 0) + return 1; + if ((bits.data[n] & MASK(rem)) == ((*(exp_data + n)) & MASK(rem))) + return 1; + else + return 0; + } else { + return 0; + } +} + +/* To test decoding of compressed bitmap by Tree based method + * and to verify the result with expected result + * for invalid input verfication is suppressed */ +static void test_EPDAN_decode_tree() +{ + bitvec dest; + int init_flag = 1; + int itr; + uint8_t bits_data[RLC_EGPRS_MAX_WS/8]; + + for (itr = 0 ; itr < NUMBER_OF_TEST_CASE ; itr++) { + dest.data = bits_data; + dest.data_len = sizeof(bits_data); + dest.cur_bit = 0; + memset(dest.data, 0, sizeof(bits_data)); + decompress_crbb(test[itr].crbb_len, test[itr].cc, test[itr].crbb_data, &dest); + + if (init_flag) + init_flag = 0; + if (test[itr].verify) { + if (check_result(dest, test[itr].ucmp_data, test[itr].ucmp_len) == 0) { + LOGP (DRLCMACDL, LOGL_DEBUG, "Tree based decoding :Error\n"); + OSMO_ASSERT(0); + } + } + } +} static void test_tbf_base() { @@ -2041,7 +2124,9 @@ tall_pcu_ctx = talloc_named_const(NULL, 1, "moiji-mobile TbfTest context"); if (!tall_pcu_ctx) abort(); - + tall_tree_ctx = talloc_named_const(tall_pcu_ctx, 0, "decode-tree context"); + if (!tall_tree_ctx) + abort(); msgb_set_talloc_ctx(tall_pcu_ctx); osmo_init_logging(&debug_log_info); log_set_use_color(osmo_stderr_target, 0); @@ -2050,7 +2135,8 @@ vty_init(&pcu_vty_info); pcu_vty_init(&debug_log_info); - + /*initialization_of_tree*/ + egprs_compress::instance()->decode_tree_init(); test_tbf_base(); test_tbf_tlli_update(); test_tbf_final_ack(TEST_MODE_STANDARD); @@ -2071,9 +2157,10 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); - + test_EPDAN_decode_tree(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); + talloc_free(tall_pcu_ctx); return EXIT_SUCCESS; } -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 9 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: pravin From gerrit-no-reply at lists.osmocom.org Mon Aug 8 13:40:57 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 8 Aug 2016 13:40:57 +0000 Subject: [PATCH] libosmocore[master]: configure: check for pkg-config presence Message-ID: Review at https://gerrit.osmocom.org/663 configure: check for pkg-config presence On a fresh installation, I was puzzled by a configure.ac 'syntax error' for PKG_CHECK_MODULES(TALLOC). It took me some time to figure out that merely pkg-config was missing. Add a check for pkg-config, which isn't as straightforward as I would wish, so comment generously. Change-Id: I2e7cdc37eb59f9947a45fbc5baddbaf71b655bc0 --- M configure.ac 1 file changed, 15 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/63/663/1 diff --git a/configure.ac b/configure.ac index 33c9b5c..1b62278 100644 --- a/configure.ac +++ b/configure.ac @@ -17,6 +17,21 @@ AC_CONFIG_MACRO_DIR([m4]) +dnl check for pkg-config +dnl * If pkg-config is missing, we get a "syntax error" for PKG_CHECK_MODULES. +dnl Instead, we want to say that pkg-config and pkg.m4 are missing. +dnl * The proper way is PKG_PROG_PKG_CONFIG() but unfortunately that does not +dnl produce an intelligible error message if pkg-config is missing entirely +dnl ("syntax error near unexpected token `0.20'"). +dnl * To produce a hint that pkg-config is missing, check for the pkg-config +dnl binary; but AC_PATH_PROG breaks if the distribution provides only +dnl prefixed (-pkg-config) versions, so just print a warning. +AC_PATH_PROG(PKG_CONFIG_INSTALLED, pkg-config, no) +if test "x$PKG_CONFIG_INSTALLED" = "xno"; then + AC_MSG_WARN([You need to install pkg-config]) +fi +PKG_PROG_PKG_CONFIG([0.20]) + dnl check os: some linker flags not available on osx case $host in *-darwin*) -- To view, visit https://gerrit.osmocom.org/663 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I2e7cdc37eb59f9947a45fbc5baddbaf71b655bc0 Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Mon Aug 8 13:57:53 2016 From: gerrit-no-reply at lists.osmocom.org (pravin) Date: Mon, 8 Aug 2016 13:57:53 +0000 Subject: osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Patch Set 9: > (11 comments) Because of the sync issue in mail I couldn't see this comment before submitting patch set 9. So, I will try to address all the comments in my next patch set. -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 9 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: pravin Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 8 14:02:09 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 8 Aug 2016 14:02:09 +0000 Subject: [PATCH] libosmo-abis[master]: gitignore: platform-libtool Message-ID: Review at https://gerrit.osmocom.org/664 gitignore: platform-libtool Change-Id: I73ad62a015827582d1ac005d9a326b86c699d46b --- M .gitignore 1 file changed, 3 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/libosmo-abis refs/changes/64/664/1 diff --git a/.gitignore b/.gitignore index fa9f1fc..08b34f1 100644 --- a/.gitignore +++ b/.gitignore @@ -21,10 +21,12 @@ ltmain.sh install-sh stamp-h1 -libtool #libosmo-abis-* tests/*_test +# libtool and e.g. arm-poky-linux-gnueabi-libtool +*libtool + .tarball-version .version .dirstamp -- To view, visit https://gerrit.osmocom.org/664 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I73ad62a015827582d1ac005d9a326b86c699d46b Gerrit-PatchSet: 1 Gerrit-Project: libosmo-abis Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Mon Aug 8 14:11:25 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 8 Aug 2016 14:11:25 +0000 Subject: openbsc[master]: ci: Attempt to disable doxygen warnings of dependencies In-Reply-To: References: Message-ID: Patch Set 2: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/616 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I4640cb5b91d54641e8e5b2f096c3bca49bfff60e Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 8 14:19:31 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 8 Aug 2016 14:19:31 +0000 Subject: openbsc[master]: libmsc/bsc: split rate counters into bsc and msc group In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+1 -- To view, visit https://gerrit.osmocom.org/646 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I7361033cd1eb919ec3c2ea2652f40ab8c75b2f99 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 8 14:33:34 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 8 Aug 2016 14:33:34 +0000 Subject: osmo-bts[master]: ci/spatch: Remove the "static" analysis handling In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+1 -- To view, visit https://gerrit.osmocom.org/656 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ic1004edf7f0bee8dda30b95554a0aaf0b116b6b8 Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 8 14:34:44 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 8 Aug 2016 14:34:44 +0000 Subject: osmo-bts[master]: ci/spatch: Remove the "static" analysis handling In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/656 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ic1004edf7f0bee8dda30b95554a0aaf0b116b6b8 Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 8 14:34:52 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 8 Aug 2016 14:34:52 +0000 Subject: [MERGED] osmo-bts[master]: ci/spatch: Remove the "static" analysis handling In-Reply-To: References: Message-ID: Holger Freyther has submitted this change and it was merged. Change subject: ci/spatch: Remove the "static" analysis handling ...................................................................... ci/spatch: Remove the "static" analysis handling spatch on Debian 8.0 has already crashed twice and is likely to crash more and at the same time the value for this static checking is close to zero (nice idea but never blossomed). So let's remove it, have a more reliable build and let's coverity find those issues. Change-Id: Ic1004edf7f0bee8dda30b95554a0aaf0b116b6b8 --- M contrib/jenkins_oct.sh M contrib/jenkins_sysmobts.sh 2 files changed, 0 insertions(+), 28 deletions(-) Approvals: Neels Hofmeyr: Looks good to me, but someone else must approve Jenkins Builder: Verified Holger Freyther: Looks good to me, approved diff --git a/contrib/jenkins_oct.sh b/contrib/jenkins_oct.sh index 3489297..88b8c08 100755 --- a/contrib/jenkins_oct.sh +++ b/contrib/jenkins_oct.sh @@ -15,9 +15,6 @@ # Build the dependency cd ../ -# Analysis code -osmo-deps.sh osmo-static-analysis - osmo-deps.sh libosmocore cd libosmocore autoreconf --install --force @@ -54,15 +51,3 @@ PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig $MAKE $PARALLEL_MAKE PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig LD_LIBRARY_PATH=$PWD/deps/install/lib $MAKE check DISTCHECK_CONFIGURE_FLAGS="--with-octsdr-2g=$PWD/deps/layer1-api/ --with-openbsc=$PWD/deps/openbsc/openbsc/include" PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig LD_LIBRARY_PATH=$PWD/deps/install/lib $MAKE distcheck - - - -# Use spatch to find common issues -spatch -include_headers -in_place -sp_file deps/osmo-static-analysis/coccinelle/memcpy.cocci . -RES=`git status --porcelain | grep ' M' | wc -l` -git checkout . - -if [ $RES -gt 0 ]; then - echo "Static analysis failed. Please fix the code." - exit 23 -fi diff --git a/contrib/jenkins_sysmobts.sh b/contrib/jenkins_sysmobts.sh index 7d171fc..051c8e0 100755 --- a/contrib/jenkins_sysmobts.sh +++ b/contrib/jenkins_sysmobts.sh @@ -15,9 +15,6 @@ # Build the dependency cd ../ -# Analysis code -osmo-deps.sh osmo-static-analysis - osmo-deps.sh libosmocore cd libosmocore autoreconf --install --force @@ -62,13 +59,3 @@ if [ $FIRMWARE_VERSION != "femtobts_v2.7" ]; then PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig $MAKE -C contrib/sysmobts-calib fi - -# Use spatch to find common issues -spatch -include_headers -in_place -sp_file deps/osmo-static-analysis/coccinelle/memcpy.cocci . -RES=`git status --porcelain | grep ' M' | wc -l` -git checkout . - -if [ $RES -gt 0 ]; then - echo "Static analysis failed. Please fix the code." - exit 23 -fi -- To view, visit https://gerrit.osmocom.org/656 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ic1004edf7f0bee8dda30b95554a0aaf0b116b6b8 Gerrit-PatchSet: 2 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 8 14:43:49 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 8 Aug 2016 14:43:49 +0000 Subject: libosmocore[master]: configure: check for pkg-config presence In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 should we have similar patches in all other projects, too? -- To view, visit https://gerrit.osmocom.org/663 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I2e7cdc37eb59f9947a45fbc5baddbaf71b655bc0 Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 8 14:44:13 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 8 Aug 2016 14:44:13 +0000 Subject: libosmo-abis[master]: gitignore: platform-libtool In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/664 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I73ad62a015827582d1ac005d9a326b86c699d46b Gerrit-PatchSet: 1 Gerrit-Project: libosmo-abis Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 8 14:45:02 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 8 Aug 2016 14:45:02 +0000 Subject: openbsc[master]: Add web proxy for control interface In-Reply-To: References: Message-ID: Patch Set 2: Code-Review+1 -- To view, visit https://gerrit.osmocom.org/659 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I87d40c80061f8b3d02d656ab8cadabbfb871b461 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 8 14:45:24 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 8 Aug 2016 14:45:24 +0000 Subject: openbsc[master]: Add python functions to get/set ctrl variables In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+1 -- To view, visit https://gerrit.osmocom.org/658 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I08705963c277bd93a011193dd7451a626d606c21 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 8 14:45:35 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 8 Aug 2016 14:45:35 +0000 Subject: openbsc[master]: Use random operation id In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+1 -- To view, visit https://gerrit.osmocom.org/657 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I32236c067360526f4e7ee4bbdba64c5137de696d Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 8 14:47:22 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 8 Aug 2016 14:47:22 +0000 Subject: openbsc[master]: Adding V42BIS implementation In-Reply-To: References: Message-ID: Patch Set 9: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/643 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Iabedece9f97ca944a1e3f747bb073e532c4e9dca Gerrit-PatchSet: 9 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 8 14:48:19 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 8 Aug 2016 14:48:19 +0000 Subject: openbsc[master]: Adding slhc code from kernel.org In-Reply-To: References: Message-ID: Patch Set 3: Code-Review-1 still seems to be using an old 2.4.x version of the code, rather than starting with latest stable kernel release. -- To view, visit https://gerrit.osmocom.org/634 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ied69c143678dc4a64cecc671f5c4dfebe19d8519 Gerrit-PatchSet: 3 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 8 14:56:35 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 8 Aug 2016 14:56:35 +0000 Subject: openbsc[master]: Adding LLC-XID encoder / decoder In-Reply-To: References: Message-ID: Patch Set 5: Code-Review-1 (14 comments) https://gerrit.osmocom.org/#/c/638/5/openbsc/include/openbsc/gprs_llc_xid.h File openbsc/include/openbsc/gprs_llc_xid.h: Line 40: int gprs_llc_compile_xid(const struct llist_head *xid_fields, uint8_t *dst, the copy_xid and parse_xid functions have the dst as first field, and src as second (which is general argument ordering in osmocom). compile_xid has them reversed. Please make sure this is consistent. https://gerrit.osmocom.org/#/c/638/5/openbsc/src/gprs/gprs_llc_xid.c File openbsc/src/gprs/gprs_llc_xid.c: Line 83: talloc_zero_size(NULL, xid_field->data_len); talloc context comment not yet adressed Line 84: memcpy(xid_field->data, src, xid_field->data_len); talloc_memdup comment not yet adressed Line 179: gprs_llc_free_xid(xid_fields); extra whitespace at end of line Line 216: if (xid_fields) { save one indent level by writing "if (!xid_fields) \n return" Line 218: if ((xid_field->data) && (xid_field->data_len)) if xid_field->data was allocated from the xid_field as talloc context, this explicit free can go. Line 255: void gprs_llc_copy_xid(struct llist_head *xid_fields_copy, again whitespace at EOL. Please keep watching that before pushing. https://gerrit.osmocom.org/#/c/638/5/openbsc/src/gprs/gprs_sndcp_comp_entity.c File openbsc/src/gprs/gprs_sndcp_comp_entity.c: PS5, Line 39: e no space before parentheis in function definition or call Line 42: comp_entity = talloc_zero (NULL, struct gprs_sndcp_comp_entity); extra space, once more Line 53: memcpy (comp_entity->nsapi, and again ... Line 91: /* Determine of which class our compression entity will be extra white space at end of line. please make sure such easy to spot (and easy to automatically spot) issues are not taking up your and my review time. Line 109: else we use curly braces here as there are multiple lines (even if only in a single statement) Line 121: if (comp_entities) { "if (!comp_entities)\n return;" Line 151: if (comp_entities) { if (!comp_entities)\n return; -- To view, visit https://gerrit.osmocom.org/638 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia06e4cb08bf9b48c2a4682606d1b1a91d19a9d37 Gerrit-PatchSet: 5 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Mon Aug 8 17:40:17 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 8 Aug 2016 17:40:17 +0000 Subject: [MERGED] openbsc[master]: add example config for sysmobts In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: add example config for sysmobts ...................................................................... add example config for sysmobts Many years ago, there was no difference between the libbsc support for nanobts and sysmobts. However, this is not the case for a long time anymore, and there are some specifics in OsmoNITB when it comes to sysmobts. Let's have an example config file Change-Id: I94ae57c9a3cb497ca39d56270fa15ed65d7f147e --- A openbsc/doc/examples/osmo-nitb/sysmobts/openbsc.cfg 1 file changed, 77 insertions(+), 0 deletions(-) Approvals: Harald Welte: Looks good to me, approved; Verified Jenkins Builder: Verified diff --git a/openbsc/doc/examples/osmo-nitb/sysmobts/openbsc.cfg b/openbsc/doc/examples/osmo-nitb/sysmobts/openbsc.cfg new file mode 100644 index 0000000..7c078f6 --- /dev/null +++ b/openbsc/doc/examples/osmo-nitb/sysmobts/openbsc.cfg @@ -0,0 +1,77 @@ +! +! OpenBSC configuration saved from vty +! ! +password foo +! +line vty + no login +! +e1_input + e1_line 0 driver ipa +network + network country code 1 + mobile network code 1 + short name OpenBSC + long name OpenBSC + auth policy closed + location updating reject cause 13 + encryption a5 0 + neci 1 + rrlp mode none + mm info 1 + handover 0 + handover window rxlev averaging 10 + handover window rxqual averaging 1 + handover window rxlev neighbor averaging 10 + handover power budget interval 6 + handover power budget hysteresis 3 + handover maximum distance 9999 + timer t3101 10 + timer t3103 0 + timer t3105 0 + timer t3107 0 + timer t3109 4 + timer t3111 0 + timer t3113 60 + timer t3115 0 + timer t3117 0 + timer t3119 0 + timer t3141 0 + bts 0 + type sysmobts + band DCS1800 + cell_identity 0 + location_area_code 1 + training_sequence_code 7 + base_station_id_code 63 + ms max power 15 + cell reselection hysteresis 4 + rxlev access min 0 + channel allocator ascending + rach tx integer 9 + rach max transmission 7 + ip.access unit_id 1801 0 + oml ip.access stream_id 255 line 0 + gprs mode none + trx 0 + rf_locked 0 + arfcn 514 + nominal power 23 + max_power_red 20 + rsl e1 tei 0 + timeslot 0 + phys_chan_config CCCH+SDCCH4 + timeslot 1 + phys_chan_config SDCCH8 + timeslot 2 + phys_chan_config TCH/F + timeslot 3 + phys_chan_config TCH/F + timeslot 4 + phys_chan_config TCH/F + timeslot 5 + phys_chan_config TCH/F + timeslot 6 + phys_chan_config TCH/F + timeslot 7 + phys_chan_config TCH/F -- To view, visit https://gerrit.osmocom.org/639 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I94ae57c9a3cb497ca39d56270fa15ed65d7f147e Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Harald Welte Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 8 17:40:28 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 8 Aug 2016 17:40:28 +0000 Subject: [MERGED] openbsc[master]: add .mailmap file for mapping git author name/mail in shortlog In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: add .mailmap file for mapping git author name/mail in shortlog ...................................................................... add .mailmap file for mapping git author name/mail in shortlog Change-Id: I7ed97fb897895935f942e3eb4fd87a8c138417be --- A .mailmap 1 file changed, 12 insertions(+), 0 deletions(-) Approvals: Harald Welte: Looks good to me, approved; Verified diff --git a/.mailmap b/.mailmap new file mode 100644 index 0000000..cda4057 --- /dev/null +++ b/.mailmap @@ -0,0 +1,12 @@ +Harald Welte +Harald Welte +Harald Welte +Holger Hans Peter Freyther +Holger Hans Peter Freyther +Holger Hans Peter Freyther +Andreas Eversberg +Andreas Eversberg +Andreas Eversberg +Pablo Neira Ayuso +Max Suraev +Tom Tsou -- To view, visit https://gerrit.osmocom.org/662 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I7ed97fb897895935f942e3eb4fd87a8c138417be Gerrit-PatchSet: 6 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Harald Welte Gerrit-Reviewer: Harald Welte From gerrit-no-reply at lists.osmocom.org Mon Aug 8 17:41:28 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 8 Aug 2016 17:41:28 +0000 Subject: [MERGED] osmo-bts[master]: Fill measurements data for L1SAP In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: Fill measurements data for L1SAP ...................................................................... Fill measurements data for L1SAP Fill in values for BER, BTO, Link quality in L1SAP and send them to PCU. Note: this increases the version of BTS <-> PCU protocol. It also requires corresponding changes in libosmocore. All BTS models provide measurements data unless direct DSP access for PCU is enabled. For BTS-specific notes see below. Octphy: conversion from sSNRDb to Link Quality uses formulae which works in practice instead of what's documented for sSNRDb value. Subject to change in future revisions. TRX: C / I link quality estimator is not computed. Change-Id: Ic9693a044756fb1c7bd2ff3cfa0db042c3c4e01c Related: OS#1616 --- M include/osmo-bts/pcu_if.h M include/osmo-bts/pcuif_proto.h M include/osmo-bts/scheduler_backend.h M src/common/l1sap.c M src/common/pcu_sock.c M src/common/scheduler.c M src/osmo-bts-litecell15/l1_if.c M src/osmo-bts-octphy/l1_if.c M src/osmo-bts-sysmo/l1_if.c M src/osmo-bts-trx/scheduler_trx.c 10 files changed, 71 insertions(+), 18 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/include/osmo-bts/pcu_if.h b/include/osmo-bts/pcu_if.h index 3ce4d0b..efad0c5 100644 --- a/include/osmo-bts/pcu_if.h +++ b/include/osmo-bts/pcu_if.h @@ -10,7 +10,7 @@ uint16_t arfcn, uint8_t block_nr); int pcu_tx_data_ind(struct gsm_bts_trx_ts *ts, uint8_t is_ptcch, uint32_t fn, uint16_t arfcn, uint8_t block_nr, uint8_t *data, uint8_t len, - int8_t rssi); + int8_t rssi, uint16_t ber10k, int16_t bto, int16_t lqual); int pcu_tx_rach_ind(struct gsm_bts *bts, int16_t qta, uint8_t ra, uint32_t fn); int pcu_tx_time_ind(uint32_t fn); int pcu_tx_pag_req(const uint8_t *identity_lv, uint8_t chan_needed); diff --git a/include/osmo-bts/pcuif_proto.h b/include/osmo-bts/pcuif_proto.h index 9d740ac..07d35f8 100644 --- a/include/osmo-bts/pcuif_proto.h +++ b/include/osmo-bts/pcuif_proto.h @@ -1,7 +1,7 @@ #ifndef _PCUIF_PROTO_H #define _PCUIF_PROTO_H -#define PCU_IF_VERSION 0x05 +#define PCU_IF_VERSION 0x06 /* msg_type */ #define PCU_IF_MSG_DATA_REQ 0x00 /* send data to given channel */ @@ -50,6 +50,9 @@ uint8_t ts_nr; uint8_t block_nr; int8_t rssi; + uint16_t ber10k; /*!< \brief BER in units of 0.01% */ + int16_t ta_offs_qbits; /* !< \brief Burst TA Offset in quarter bits */ + int16_t lqual_cb; /* !< \brief Link quality in centiBel */ } __attribute__ ((packed)); struct gsm_pcu_if_rts_req { diff --git a/include/osmo-bts/scheduler_backend.h b/include/osmo-bts/scheduler_backend.h index 68f0c60..e63b961 100644 --- a/include/osmo-bts/scheduler_backend.h +++ b/include/osmo-bts/scheduler_backend.h @@ -43,7 +43,11 @@ enum trx_chan_type chan); int _sched_compose_ph_data_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t *l2, uint8_t l2_len, float rssi, enum osmo_ph_pres_info_type presence_info); + enum trx_chan_type chan, uint8_t *l2, + uint8_t l2_len, float rssi, + int16_t ta_offs_qbits, int16_t link_qual_cb, + uint16_t ber10k, + enum osmo_ph_pres_info_type presence_info); int _sched_compose_tch_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t *tch, uint8_t tch_len); diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 4f6cf05..304f718 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -820,7 +820,9 @@ if (L1SAP_IS_PTCCH(fn)) { pcu_tx_data_ind(&trx->ts[tn], 1, fn, 0 /* ARFCN */, L1SAP_FN2PTCCHBLOCK(fn), - data, len, rssi); + data, len, rssi, data_ind->ber10k, + data_ind->ta_offs_qbits, + data_ind->lqual_cb); return 0; } @@ -829,7 +831,8 @@ return 0; /* PDTCH / PACCH frame handling */ pcu_tx_data_ind(&trx->ts[tn], 0, fn, 0 /* ARFCN */, - L1SAP_FN2MACBLOCK(fn), data, len, rssi); + L1SAP_FN2MACBLOCK(fn), data, len, rssi, data_ind->ber10k, + data_ind->ta_offs_qbits, data_ind->lqual_cb); return 0; } diff --git a/src/common/pcu_sock.c b/src/common/pcu_sock.c index 22b6fab..fed464f 100644 --- a/src/common/pcu_sock.c +++ b/src/common/pcu_sock.c @@ -337,7 +337,7 @@ int pcu_tx_data_ind(struct gsm_bts_trx_ts *ts, uint8_t is_ptcch, uint32_t fn, uint16_t arfcn, uint8_t block_nr, uint8_t *data, uint8_t len, - int8_t rssi) + int8_t rssi, uint16_t ber10k, int16_t bto, int16_t lqual) { struct msgb *msg; struct gsm_pcu_if *pcu_prim; @@ -362,6 +362,9 @@ data_ind->ts_nr = ts->nr; data_ind->block_nr = block_nr; data_ind->rssi = rssi; + data_ind->ber10k = ber10k; + data_ind->ta_offs_qbits = bto; + data_ind->lqual_cb = lqual; memcpy(data_ind->data, data, len); data_ind->len = len; diff --git a/src/common/scheduler.c b/src/common/scheduler.c index eeaf2c1..ec66cfc 100644 --- a/src/common/scheduler.c +++ b/src/common/scheduler.c @@ -295,7 +295,11 @@ } int _sched_compose_ph_data_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t *l2, uint8_t l2_len, float rssi, enum osmo_ph_pres_info_type presence_info) + enum trx_chan_type chan, uint8_t *l2, + uint8_t l2_len, float rssi, + int16_t ta_offs_qbits, int16_t link_qual_cb, + uint16_t ber10k, + enum osmo_ph_pres_info_type presence_info) { struct msgb *msg; struct osmo_phsap_prim *l1sap; @@ -311,6 +315,9 @@ l1sap->u.data.link_id = trx_chan_desc[chan].link_id; l1sap->u.data.fn = fn; l1sap->u.data.rssi = (int8_t) (rssi); + l1sap->u.data.ber10k = ber10k; + l1sap->u.data.ta_offs_qbits = ta_offs_qbits; + l1sap->u.data.lqual_cb = link_qual_cb; l1sap->u.data.pdch_presence_info = presence_info; msg->l2h = msgb_put(msg, l2_len); if (l2_len) diff --git a/src/osmo-bts-litecell15/l1_if.c b/src/osmo-bts-litecell15/l1_if.c index a979bd7..dcd25ee 100644 --- a/src/osmo-bts-litecell15/l1_if.c +++ b/src/osmo-bts-litecell15/l1_if.c @@ -916,7 +916,11 @@ l1sap->u.data.chan_nr = chan_nr; l1sap->u.data.fn = fn; l1sap->u.data.rssi = rssi; - + if (!pcu_direct) { + l1sap->u.data.ber10k = data_ind->measParam.fBer * 10000; + l1sap->u.data.ta_offs_qbits = data_ind->measParam.i16BurstTiming; + l1sap->u.data.lqual_cb = data_ind->measParam.fLinkQuality * 10; + } return l1sap_up(trx, l1sap); } diff --git a/src/osmo-bts-octphy/l1_if.c b/src/osmo-bts-octphy/l1_if.c index 760c988..d621bcf 100644 --- a/src/osmo-bts-octphy/l1_if.c +++ b/src/osmo-bts-octphy/l1_if.c @@ -961,7 +961,8 @@ struct osmo_phsap_prim *l1sap; uint32_t fn; uint8_t *data; - uint16_t len; + uint16_t len, b_total, b_error; + int16_t snr; int8_t rssi; int rc; @@ -1029,6 +1030,16 @@ l1sap->u.data.chan_nr = chan_nr; l1sap->u.data.fn = fn; l1sap->u.data.rssi = rssi; + b_total = data_ind->MeasurementInfo.usBERTotalBitCnt; + b_error =data_ind->MeasurementInfo.usBERCnt; + l1sap->u.data.ber10k = b_total ? 10000 * b_error / b_total : 0; + l1sap->u.data.ta_offs_qbits = data_ind->MeasurementInfo.sBurstTiming4x; + snr = data_ind->MeasurementInfo.sSNRDb; + /* FIXME: better converion formulae for SnR -> C / I? + l1sap->u.data.lqual_cb = (snr ? snr : (snr - 65536)) * 10 / 256; + LOGP(DL1C, LOGL_ERROR, "SnR: raw %d, computed %d\n", snr, l1sap->u.data.lqual_cb); + */ + l1sap->u.data.lqual_cb = (snr ? snr : (snr - 65536)) * 100; l1sap->u.data.pdch_presence_info = PRES_INFO_BOTH; /* FIXME: consider EDGE support */ l1sap_up(trx, l1sap); diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index 45de199..f70ccf5 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -904,7 +904,11 @@ l1sap->u.data.chan_nr = chan_nr; l1sap->u.data.fn = fn; l1sap->u.data.rssi = (int8_t) (data_ind->measParam.fRssi); - + if (!pcu_direct) { + l1sap->u.data.ber10k = data_ind->measParam.fBer * 10000; + l1sap->u.data.ta_offs_qbits = data_ind->measParam.i16BurstTiming; + l1sap->u.data.lqual_cb = data_ind->measParam.fLinkQuality * 10; + } /* copy data from L1 primitive to L1SAP primitive */ sap_msg->l2h = msgb_put(sap_msg, data_ind->msgUnitParam.u8Size); memcpy(sap_msg->l2h, data_ind->msgUnitParam.u8Buffer, diff --git a/src/osmo-bts-trx/scheduler_trx.c b/src/osmo-bts-trx/scheduler_trx.c index 3a6ede3..e02232b 100644 --- a/src/osmo-bts-trx/scheduler_trx.c +++ b/src/osmo-bts-trx/scheduler_trx.c @@ -200,8 +200,10 @@ /* Send uplnk measurement information to L2 */ l1if_process_meas_res(l1t->trx, tn, fn, trx_chan_desc[chan].chan_nr | tn, 456, 456, -110, 0); - - _sched_compose_ph_data_ind(l1t, tn, 0, chan, NULL, 0, -110, PRES_INFO_INVALID); + /* FIXME: use actual values for BER etc */ + _sched_compose_ph_data_ind(l1t, tn, 0, chan, NULL, 0, + -110, 0, 0, 10000, + PRES_INFO_INVALID); } } @@ -886,8 +888,12 @@ /* Send uplnk measurement information to L2 */ l1if_process_meas_res(l1t->trx, tn, fn, trx_chan_desc[chan].chan_nr | tn, n_errors, n_bits_total, *rssi_sum / *rssi_num, *toa_sum / *toa_num); - - return _sched_compose_ph_data_ind(l1t, tn, *first_fn, chan, l2, l2_len, *rssi_sum / *rssi_num, PRES_INFO_UNKNOWN); + uint16_t ber10k = + (n_bits_total == 0) ? 10000 : 10000 * n_errors / n_bits_total; + return _sched_compose_ph_data_ind(l1t, tn, *first_fn, chan, l2, l2_len, + *rssi_sum / *rssi_num, + 4 * (*toa_sum) / *toa_num, 0, ber10k, + PRES_INFO_UNKNOWN); } int rx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, @@ -985,9 +991,11 @@ l1ts->mf_period, trx_chan_desc[chan].name); return 0; } - + uint16_t ber10k = + (n_bits_total == 0) ? 10000 : 10000 * n_errors / n_bits_total; return _sched_compose_ph_data_ind(l1t, tn, (fn + GSM_HYPERFRAME - 3) % GSM_HYPERFRAME, chan, - l2, rc, *rssi_sum / *rssi_num, PRES_INFO_BOTH); + l2, rc, *rssi_sum / *rssi_num, 4 * (*toa_sum) / *toa_num, 0, + ber10k, PRES_INFO_BOTH); } int rx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, @@ -1105,8 +1113,11 @@ /* FACCH */ if (rc == GSM_MACBLOCK_LEN) { + uint16_t ber10k = (n_bits_total == 0) ? 10000 : + 10000 * n_errors / n_bits_total; _sched_compose_ph_data_ind(l1t, tn, (fn + GSM_HYPERFRAME - 7) % GSM_HYPERFRAME, chan, - tch_data + amr, GSM_MACBLOCK_LEN, rssi, PRES_INFO_UNKNOWN); + tch_data + amr, GSM_MACBLOCK_LEN, rssi, 4 * toa, 0, + ber10k, PRES_INFO_UNKNOWN); bfi: if (rsl_cmode == RSL_CMOD_SPD_SPEECH) { /* indicate bad frame */ @@ -1275,9 +1286,12 @@ /* FACCH */ if (rc == GSM_MACBLOCK_LEN) { chan_state->ul_ongoing_facch = 1; + uint16_t ber10k = + (n_bits_total == 0) ? 10000 : 10000 * n_errors / n_bits_total; _sched_compose_ph_data_ind(l1t, tn, (fn + GSM_HYPERFRAME - 10 - ((fn % 26) >= 19)) % GSM_HYPERFRAME, chan, - tch_data + amr, GSM_MACBLOCK_LEN, rssi, PRES_INFO_UNKNOWN); + tch_data + amr, GSM_MACBLOCK_LEN, rssi, 4 * toa, 0, + ber10k, PRES_INFO_UNKNOWN); bfi: if (rsl_cmode == RSL_CMOD_SPD_SPEECH) { /* indicate bad frame */ -- To view, visit https://gerrit.osmocom.org/623 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ic9693a044756fb1c7bd2ff3cfa0db042c3c4e01c Gerrit-PatchSet: 6 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max From gerrit-no-reply at lists.osmocom.org Mon Aug 8 17:42:17 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 8 Aug 2016 17:42:17 +0000 Subject: [MERGED] libosmocore[master]: Add control interface port for GGSN In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: Add control interface port for GGSN ...................................................................... Add control interface port for GGSN Change-Id: Ie7232189fe3265a8631fd3652b2c8c152cdee918 Related: OS#1646 --- M include/osmocom/ctrl/ports.h 1 file changed, 1 insertion(+), 0 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/include/osmocom/ctrl/ports.h b/include/osmocom/ctrl/ports.h index 71c8e2d..c89bbe3 100644 --- a/include/osmocom/ctrl/ports.h +++ b/include/osmocom/ctrl/ports.h @@ -6,4 +6,5 @@ #define OSMO_CTRL_PORT_NITB_BSC 4249 #define OSMO_CTRL_PORT_BSC_NAT 4250 #define OSMO_CTRL_PORT_SGSN 4251 +#define OSMO_CTRL_PORT_GGSN 4252 #define OSMO_CTRL_PORT_CSCN 4255 -- To view, visit https://gerrit.osmocom.org/648 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ie7232189fe3265a8631fd3652b2c8c152cdee918 Gerrit-PatchSet: 2 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max From gerrit-no-reply at lists.osmocom.org Mon Aug 8 17:45:14 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 8 Aug 2016 17:45:14 +0000 Subject: osmo-bts[master]: osmo-bts-trx: Fix PCS1900 operation In-Reply-To: References: Message-ID: Patch Set 2: Verified+1 -- To view, visit https://gerrit.osmocom.org/650 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I637b76bc1fc749eed8e364412d76606589991c02 Gerrit-PatchSet: 2 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Harald Welte Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 8 17:46:13 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 8 Aug 2016 17:46:13 +0000 Subject: [MERGED] osmo-bts[master]: osmo-bts-trx: Fix PCS1900 operation In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: osmo-bts-trx: Fix PCS1900 operation ...................................................................... osmo-bts-trx: Fix PCS1900 operation As the ARFCN numbers in DCS (1800) and PCS (1900) are not unique, we need to specify the band in the upper bits of the ARFCN value before calling gsm_arfcn2freq10(). Change-Id: I637b76bc1fc749eed8e364412d76606589991c02 --- M src/osmo-bts-trx/trx_if.c 1 file changed, 12 insertions(+), 2 deletions(-) Approvals: Harald Welte: Looks good to me, approved; Verified diff --git a/src/osmo-bts-trx/trx_if.c b/src/osmo-bts-trx/trx_if.c index bef6c09..42d383c 100644 --- a/src/osmo-bts-trx/trx_if.c +++ b/src/osmo-bts-trx/trx_if.c @@ -288,11 +288,16 @@ int trx_if_cmd_rxtune(struct trx_l1h *l1h, uint16_t arfcn) { + struct phy_instance *pinst = l1h->phy_inst; uint16_t freq10; + + if (pinst->trx->bts->band == GSM_BAND_1900) + arfcn |= ARFCN_PCS; freq10 = gsm_arfcn2freq10(arfcn, 1); /* RX = uplink */ if (freq10 == 0xffff) { - LOGP(DTRX, LOGL_ERROR, "Arfcn %d not defined.\n", arfcn); + LOGP(DTRX, LOGL_ERROR, "Arfcn %d not defined.\n", + arfcn & ~ARFCN_FLAG_MASK); return -ENOTSUP; } @@ -301,11 +306,16 @@ int trx_if_cmd_txtune(struct trx_l1h *l1h, uint16_t arfcn) { + struct phy_instance *pinst = l1h->phy_inst; uint16_t freq10; + + if (pinst->trx->bts->band == GSM_BAND_1900) + arfcn |= ARFCN_PCS; freq10 = gsm_arfcn2freq10(arfcn, 0); /* TX = downlink */ if (freq10 == 0xffff) { - LOGP(DTRX, LOGL_ERROR, "Arfcn %d not defined.\n", arfcn); + LOGP(DTRX, LOGL_ERROR, "Arfcn %d not defined.\n", + arfcn & ~ARFCN_FLAG_MASK); return -ENOTSUP; } -- To view, visit https://gerrit.osmocom.org/650 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I637b76bc1fc749eed8e364412d76606589991c02 Gerrit-PatchSet: 3 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Harald Welte Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 8 17:53:46 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 8 Aug 2016 17:53:46 +0000 Subject: libosmocore[master]: configure: check for pkg-config presence In-Reply-To: References: Message-ID: Patch Set 1: > should we have similar patches in all other projects, too? Arguably, if we've built and installed libosmocore successfully, pkg-config would then be installed and in practice we don't really need to check every time. But for completeness' sake, we "should" still add it everywhere. I was going to wait for comments here before posting more patches. -- To view, visit https://gerrit.osmocom.org/663 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I2e7cdc37eb59f9947a45fbc5baddbaf71b655bc0 Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 8 18:00:13 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 8 Aug 2016 18:00:13 +0000 Subject: [PATCH] osmo-pcu[master]: Revert "tbf: Add state WAIT_ASSIGN" In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/218 to look at the new patch set (#3). Revert "tbf: Add state WAIT_ASSIGN" This reverts commit f1a7b8fc6651f92a8b7f3f27b7ca05d07f4e44e0. Conflicts: tests/tbf/TbfTest.err The commit broke GPRS service at least for osmo-bts-sysmo on a SysmoBTS 1002 with current master of osmo-bts (ef30f50d5d6d5f863fc147d05ccdceb89284934e). The error observed is the following log output (was viewing both osmo-bts-sysmo and osmo-pcu logs interleaved): <0002> tbf.cpp:874 TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=WAIT ASSIGN) T3169 timeout during transsmission <0002> tbf.cpp:893 - Assignment was on CCCH <0002> tbf.cpp:899 - No uplink data received yet <0007> l1sap.c:904 RACH for packet access <0001> pcu_l1_if.cpp:311 RACH request received: sapi=1 qta=0, ra=121, fn=13653 [repeat] When removing this single commit from current osmo-pcu master, GPRS service works well on SysmoBTS, with current osmo-bts master. The TbfTest.err expected output needed adjustment after the revert. Disclaimer: I am not aware of adverse effects this commit may have. I have no idea what the WAIT_ASSIGN state is used for -- further review is required. Change-Id: I1532f8e93194368cdc1e3846f82afa6d68cd5fbd --- M src/bts.cpp M src/tbf.cpp M src/tbf.h M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err 5 files changed, 124 insertions(+), 179 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/18/218/3 diff --git a/src/bts.cpp b/src/bts.cpp index c53c92c..3b1ad43 100644 --- a/src/bts.cpp +++ b/src/bts.cpp @@ -552,11 +552,8 @@ m_bts.trx[trx_no].arfcn, ts_no, tsc, usf, 0, sb_fn, m_bts.alpha, m_bts.gamma, -1); - if (plen >= 0) { + if (plen >= 0) pcu_l1if_tx_agch(immediate_assignment, plen); - if (tbf) - tbf->set_state(GPRS_RLCMAC_WAIT_ASSIGN); - } bitvec_free(immediate_assignment); @@ -614,10 +611,8 @@ (tbf->pdch[ts]->last_rts_fn + 21216) % 2715648, tbf->ta(), tbf->trx->arfcn, ts, tbf->tsc(), 7, poll, tbf->poll_fn, m_bts.alpha, m_bts.gamma, -1); - if (plen >= 0) { + if (plen >= 0) pcu_l1if_tx_pch(immediate_assignment, plen, imsi); - tbf->set_state(GPRS_RLCMAC_WAIT_ASSIGN); - } bitvec_free(immediate_assignment); } diff --git a/src/tbf.cpp b/src/tbf.cpp index 1fc1aef..59e3688 100644 --- a/src/tbf.cpp +++ b/src/tbf.cpp @@ -394,7 +394,6 @@ const char *gprs_rlcmac_tbf::tbf_state_name[] = { "NULL", "ASSIGN", - "WAIT ASSIGN", "FLOW", "FINISHED", "WAIT RELEASE", @@ -825,12 +824,6 @@ if ((state_flags & (1 << GPRS_RLCMAC_FLAG_PACCH))) { if (state_is(GPRS_RLCMAC_ASSIGN)) { LOGP(DRLCMAC, LOGL_NOTICE, "%s releasing due to " - "PACCH assignment timeout (not yet sent).\n", - tbf_name(this)); - tbf_free(this); - return; - } else if (state_is(GPRS_RLCMAC_WAIT_ASSIGN)) { - LOGP(DRLCMAC, LOGL_NOTICE, "%s releasing due to " "PACCH assignment timeout.\n", tbf_name(this)); tbf_free(this); return; @@ -841,7 +834,7 @@ if ((state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH))) { gprs_rlcmac_dl_tbf *dl_tbf = as_dl_tbf(this); dl_tbf->m_wait_confirm = 0; - if (dl_tbf->state_is(GPRS_RLCMAC_WAIT_ASSIGN)) { + if (dl_tbf->state_is(GPRS_RLCMAC_ASSIGN)) { tbf_assign_control_ts(dl_tbf); if (!dl_tbf->upgrade_to_multislot) { @@ -1002,8 +995,6 @@ if (poll_ass_dl) { set_polling(new_poll_fn, ts); - if (new_dl_tbf->state_is(GPRS_RLCMAC_ASSIGN)) - new_dl_tbf->set_state(GPRS_RLCMAC_WAIT_ASSIGN); dl_ass_state = GPRS_RLCMAC_DL_ASS_WAIT_ACK; LOGP(DRLCMACDL, LOGL_INFO, "%s Scheduled DL Assignment polling on FN=%d, TS=%d\n", @@ -1076,8 +1067,6 @@ set_polling(new_poll_fn, ts); ul_ass_state = GPRS_RLCMAC_UL_ASS_WAIT_ACK; - if (new_tbf->state_is(GPRS_RLCMAC_ASSIGN)) - new_tbf->set_state(GPRS_RLCMAC_WAIT_ASSIGN); LOGP(DRLCMACDL, LOGL_INFO, "%s Scheduled UL Assignment polling on FN=%d, TS=%d\n", name(), poll_fn, poll_ts); diff --git a/src/tbf.h b/src/tbf.h index 1bd7878..38258a0 100644 --- a/src/tbf.h +++ b/src/tbf.h @@ -43,8 +43,7 @@ enum gprs_rlcmac_tbf_state { GPRS_RLCMAC_NULL = 0, /* new created TBF */ - GPRS_RLCMAC_ASSIGN, /* wait for DL transmission */ - GPRS_RLCMAC_WAIT_ASSIGN,/* wait for confirmation */ + GPRS_RLCMAC_ASSIGN, /* wait for downlink assignment */ GPRS_RLCMAC_FLOW, /* RLC/MAC flow, resource needed */ GPRS_RLCMAC_FINISHED, /* flow finished, wait for release */ GPRS_RLCMAC_WAIT_RELEASE,/* wait for release or restart of DL TBF */ @@ -231,7 +230,7 @@ int set_tlli_from_ul(uint32_t new_tlli); void merge_and_clear_ms(GprsMs *old_ms); - static const char *tbf_state_name[7]; + static const char *tbf_state_name[6]; class GprsMs *m_ms; @@ -316,7 +315,10 @@ { /* The TBF is established or has been assigned by a IMM.ASS for * download */ - return state > GPRS_RLCMAC_ASSIGN; + return state > GPRS_RLCMAC_ASSIGN || + (direction == GPRS_RLCMAC_DL_TBF && + state == GPRS_RLCMAC_ASSIGN && + (state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH))); } inline uint8_t gprs_rlcmac_tbf::tfi() const diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..f1d3f85 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -1524,7 +1524,7 @@ ms2 = the_bts.ms_by_tlli(tlli1); OSMO_ASSERT(ms2 == ms1); OSMO_ASSERT(ms2->dl_tbf()); - OSMO_ASSERT(ms2->dl_tbf()->state_is(GPRS_RLCMAC_WAIT_ASSIGN)); + OSMO_ASSERT(ms2->dl_tbf()->state_is(GPRS_RLCMAC_ASSIGN)); dl_tbf2 = ms2->dl_tbf(); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..72b81d6 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -570,8 +570,7 @@ TX: START TBF(TFI=0 TLLI=0xc0000000 DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 30 30 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 00 08 00 23 2b 2b 2b 2b -TBF(TFI=0 TLLI=0xc0000000 DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=0 TLLI=0xc0000000 DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=0 TLLI=0xc0000000 DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -597,8 +596,7 @@ TX: START TBF(TFI=1 TLLI=0xc0000001 DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 30 31 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 00 18 40 23 2b 2b 2b 2b -TBF(TFI=1 TLLI=0xc0000001 DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=1 TLLI=0xc0000001 DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=1 TLLI=0xc0000001 DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -624,8 +622,7 @@ TX: START TBF(TFI=2 TLLI=0xc0000002 DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 30 32 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 00 28 80 23 2b 2b 2b 2b -TBF(TFI=2 TLLI=0xc0000002 DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=2 TLLI=0xc0000002 DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=2 TLLI=0xc0000002 DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -651,8 +648,7 @@ TX: START TBF(TFI=3 TLLI=0xc0000003 DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 30 33 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 00 38 c0 23 2b 2b 2b 2b -TBF(TFI=3 TLLI=0xc0000003 DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=3 TLLI=0xc0000003 DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=3 TLLI=0xc0000003 DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -678,8 +674,7 @@ TX: START TBF(TFI=4 TLLI=0xc0000004 DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 30 34 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 00 49 00 23 2b 2b 2b 2b -TBF(TFI=4 TLLI=0xc0000004 DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=4 TLLI=0xc0000004 DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=4 TLLI=0xc0000004 DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -705,8 +700,7 @@ TX: START TBF(TFI=5 TLLI=0xc0000005 DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 30 35 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 00 59 40 23 2b 2b 2b 2b -TBF(TFI=5 TLLI=0xc0000005 DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=5 TLLI=0xc0000005 DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=5 TLLI=0xc0000005 DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -732,8 +726,7 @@ TX: START TBF(TFI=6 TLLI=0xc0000006 DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 30 36 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 00 69 80 23 2b 2b 2b 2b -TBF(TFI=6 TLLI=0xc0000006 DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=6 TLLI=0xc0000006 DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=6 TLLI=0xc0000006 DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -759,8 +752,7 @@ TX: START TBF(TFI=7 TLLI=0xc0000007 DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 30 37 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 00 79 c0 23 2b 2b 2b 2b -TBF(TFI=7 TLLI=0xc0000007 DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=7 TLLI=0xc0000007 DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=7 TLLI=0xc0000007 DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -786,8 +778,7 @@ TX: START TBF(TFI=8 TLLI=0xc0000008 DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 30 38 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 00 8a 00 23 2b 2b 2b 2b -TBF(TFI=8 TLLI=0xc0000008 DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=8 TLLI=0xc0000008 DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=8 TLLI=0xc0000008 DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -813,8 +804,7 @@ TX: START TBF(TFI=9 TLLI=0xc0000009 DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 30 39 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 00 9a 40 23 2b 2b 2b 2b -TBF(TFI=9 TLLI=0xc0000009 DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=9 TLLI=0xc0000009 DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=9 TLLI=0xc0000009 DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -840,8 +830,7 @@ TX: START TBF(TFI=10 TLLI=0xc000000a DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 31 30 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 00 aa 80 23 2b 2b 2b 2b -TBF(TFI=10 TLLI=0xc000000a DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=10 TLLI=0xc000000a DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=10 TLLI=0xc000000a DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -867,8 +856,7 @@ TX: START TBF(TFI=11 TLLI=0xc000000b DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 31 31 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 00 ba c0 23 2b 2b 2b 2b -TBF(TFI=11 TLLI=0xc000000b DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=11 TLLI=0xc000000b DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=11 TLLI=0xc000000b DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -894,8 +882,7 @@ TX: START TBF(TFI=12 TLLI=0xc000000c DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 31 32 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 00 cb 00 23 2b 2b 2b 2b -TBF(TFI=12 TLLI=0xc000000c DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=12 TLLI=0xc000000c DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=12 TLLI=0xc000000c DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -921,8 +908,7 @@ TX: START TBF(TFI=13 TLLI=0xc000000d DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 31 33 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 00 db 40 23 2b 2b 2b 2b -TBF(TFI=13 TLLI=0xc000000d DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=13 TLLI=0xc000000d DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=13 TLLI=0xc000000d DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -948,8 +934,7 @@ TX: START TBF(TFI=14 TLLI=0xc000000e DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 31 34 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 00 eb 80 23 2b 2b 2b 2b -TBF(TFI=14 TLLI=0xc000000e DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=14 TLLI=0xc000000e DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=14 TLLI=0xc000000e DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -975,8 +960,7 @@ TX: START TBF(TFI=15 TLLI=0xc000000f DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 31 35 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 00 fb c0 23 2b 2b 2b 2b -TBF(TFI=15 TLLI=0xc000000f DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=15 TLLI=0xc000000f DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=15 TLLI=0xc000000f DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -1002,8 +986,7 @@ TX: START TBF(TFI=16 TLLI=0xc0000010 DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 31 36 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 01 0c 00 23 2b 2b 2b 2b -TBF(TFI=16 TLLI=0xc0000010 DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=16 TLLI=0xc0000010 DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=16 TLLI=0xc0000010 DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -1029,8 +1012,7 @@ TX: START TBF(TFI=17 TLLI=0xc0000011 DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 31 37 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 01 1c 40 23 2b 2b 2b 2b -TBF(TFI=17 TLLI=0xc0000011 DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=17 TLLI=0xc0000011 DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=17 TLLI=0xc0000011 DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -1056,8 +1038,7 @@ TX: START TBF(TFI=18 TLLI=0xc0000012 DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 31 38 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 01 2c 80 23 2b 2b 2b 2b -TBF(TFI=18 TLLI=0xc0000012 DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=18 TLLI=0xc0000012 DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=18 TLLI=0xc0000012 DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -1083,8 +1064,7 @@ TX: START TBF(TFI=19 TLLI=0xc0000013 DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 31 39 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 01 3c c0 23 2b 2b 2b 2b -TBF(TFI=19 TLLI=0xc0000013 DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=19 TLLI=0xc0000013 DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=19 TLLI=0xc0000013 DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -1110,8 +1090,7 @@ TX: START TBF(TFI=20 TLLI=0xc0000014 DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 32 30 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 01 4d 00 23 2b 2b 2b 2b -TBF(TFI=20 TLLI=0xc0000014 DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=20 TLLI=0xc0000014 DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=20 TLLI=0xc0000014 DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -1137,8 +1116,7 @@ TX: START TBF(TFI=21 TLLI=0xc0000015 DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 32 31 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 01 5d 40 23 2b 2b 2b 2b -TBF(TFI=21 TLLI=0xc0000015 DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=21 TLLI=0xc0000015 DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=21 TLLI=0xc0000015 DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -1164,8 +1142,7 @@ TX: START TBF(TFI=22 TLLI=0xc0000016 DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 32 32 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 01 6d 80 23 2b 2b 2b 2b -TBF(TFI=22 TLLI=0xc0000016 DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=22 TLLI=0xc0000016 DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=22 TLLI=0xc0000016 DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -1191,8 +1168,7 @@ TX: START TBF(TFI=23 TLLI=0xc0000017 DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 32 33 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 01 7d c0 23 2b 2b 2b 2b -TBF(TFI=23 TLLI=0xc0000017 DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=23 TLLI=0xc0000017 DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=23 TLLI=0xc0000017 DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -1218,8 +1194,7 @@ TX: START TBF(TFI=24 TLLI=0xc0000018 DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 32 34 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 01 8e 00 23 2b 2b 2b 2b -TBF(TFI=24 TLLI=0xc0000018 DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=24 TLLI=0xc0000018 DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=24 TLLI=0xc0000018 DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -1245,8 +1220,7 @@ TX: START TBF(TFI=25 TLLI=0xc0000019 DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 32 35 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 01 9e 40 23 2b 2b 2b 2b -TBF(TFI=25 TLLI=0xc0000019 DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=25 TLLI=0xc0000019 DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=25 TLLI=0xc0000019 DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -1272,8 +1246,7 @@ TX: START TBF(TFI=26 TLLI=0xc000001a DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 32 36 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 01 ae 80 23 2b 2b 2b 2b -TBF(TFI=26 TLLI=0xc000001a DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=26 TLLI=0xc000001a DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=26 TLLI=0xc000001a DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -1299,8 +1272,7 @@ TX: START TBF(TFI=27 TLLI=0xc000001b DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 32 37 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 01 be c0 23 2b 2b 2b 2b -TBF(TFI=27 TLLI=0xc000001b DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=27 TLLI=0xc000001b DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=27 TLLI=0xc000001b DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -1326,8 +1298,7 @@ TX: START TBF(TFI=28 TLLI=0xc000001c DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 32 38 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 01 cf 00 23 2b 2b 2b 2b -TBF(TFI=28 TLLI=0xc000001c DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=28 TLLI=0xc000001c DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=28 TLLI=0xc000001c DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -1353,8 +1324,7 @@ TX: START TBF(TFI=29 TLLI=0xc000001d DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 32 39 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 01 df 40 23 2b 2b 2b 2b -TBF(TFI=29 TLLI=0xc000001d DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=29 TLLI=0xc000001d DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=29 TLLI=0xc000001d DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -1380,8 +1350,7 @@ TX: START TBF(TFI=30 TLLI=0xc000001e DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 33 30 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 01 ef 80 23 2b 2b 2b 2b -TBF(TFI=30 TLLI=0xc000001e DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=30 TLLI=0xc000001e DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=30 TLLI=0xc000001e DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -1407,8 +1376,7 @@ TX: START TBF(TFI=31 TLLI=0xc000001f DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=30 33 31 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 00 00 01 ff c0 23 2b 2b 2b 2b -TBF(TFI=31 TLLI=0xc000001f DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=31 TLLI=0xc000001f DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=31 TLLI=0xc000001f DIR=DL STATE=ASSIGN) append ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=45/0 Creating MS object, TLLI = 0x00000000 @@ -1442,10 +1410,9 @@ TX: START TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=34 35 36 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 01 23 45 68 00 23 2b 2b 2b 2b -TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) append -TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) append -TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to RELEASING +TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=ASSIGN) append +TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=ASSIGN) append +TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=ASSIGN) changes state from ASSIGN to RELEASING TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=RELEASING) free PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=RELEASING), 0 TBFs, USFs = 00, TFIs = 00000000. Detaching TBF from MS object, TLLI = 0xc0123456, TBF = TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=RELEASING) @@ -1471,35 +1438,34 @@ TX: START TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=4 TA=0 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=34 35 36 2d 06 3f 30 0c 00 00 7d 80 00 00 00 dc 01 23 45 68 00 23 2b 2b 2b 2b -TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) append -TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) downlink (V(A)==0 .. V(S)==0) +TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=ASSIGN) append +TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=ASSIGN) downlink (V(A)==0 .. V(S)==0) - Sending new block at BSN 0, CS=CS-1 -- Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) +- Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=ASSIGN) (len=19) -- Chunk with length 19 is less than remaining space (20): add length header to to delimit LLC frame -- No space left, so we are done. -Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 -- Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) +Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=ASSIGN)len=19 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=ASSIGN) (len=19) data block (BSN 0, CS-1): 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 MSG = 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 -TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) downlink (V(A)==0 .. V(S)==1) +TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=ASSIGN) downlink (V(A)==0 .. V(S)==1) - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 19 is less than remaining space (20): add length header to to delimit LLC frame -- No space left, so we are done. -Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 -- Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) +Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=ASSIGN)len=19 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=ASSIGN) (len=19) data block (BSN 1, CS-1): 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 MSG = 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 -TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) downlink (V(A)==0 .. V(S)==2) +TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=ASSIGN) downlink (V(A)==0 .. V(S)==2) - Sending new block at BSN 2, CS=CS-1 -- Chunk with length 19 is less than remaining space (20): add length header to to delimit LLC frame -- Final block, so we done. -Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 -TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FINISHED +Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=ASSIGN)len=19 +TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=ASSIGN) changes state from ASSIGN to FINISHED data block (BSN 2, CS-1): 4d 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -1533,26 +1499,29 @@ TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=FLOW) TX: START Immediate Assignment Uplink (AGCH) - TRX=0 (0) TS=7 TA=7 TSC=0 TFI=0 USF=0 Sending data request: trx=0 ts=0 sapi=2 arfcn=0 fn=0 block=0 data=2d 06 3f 10 0f 00 00 03 8b 29 07 00 c8 00 10 0b 2b 2b 2b 2b 2b 2b 2b -TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=FLOW) changes state from FLOW to WAIT ASSIGN Got RLC block, coding scheme: CS-1, length: 23 (23)) UL data: 00 01 01 f1 22 33 44 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 UL DATA TFI=0 received (V(Q)=0 .. V(R)=0) -TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=WAIT ASSIGN) restarting timer 3169 while old timer 3169 pending -TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=WAIT ASSIGN): Got CS-1 RLC data block: CV=0, BSN=0, SPB=0, PI=0, E=1, TI=1, bitoffs=24 +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=0, BSN=0, SPB=0, PI=0, E=1, TI=1, bitoffs=24 - BSN 0 storing in window (0..63) -TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=WAIT ASSIGN): data_length=20, data=f1 22 33 44 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=FLOW): data_length=20, data=f1 22 33 44 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Decoded premier TLLI=0x00000000 of UL DATA TFI=0. Modifying MS object, UL TLLI: 0x00000000 -> 0xf1223344, not yet confirmed - Raising V(R) to 1 - Taking block 0 out, raising V(Q) to 1 - Assembling frames: (len=20) -- Frame 1 starts at offset 4, length=16, is_complete=1 -TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) complete UL frame len=16 -LLC [PCU -> SGSN] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) len=16 +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) complete UL frame len=16 +LLC [PCU -> SGSN] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) len=16 No bctx +- No gaps in received block, last block: BSN=0 CV=0 +- Finished with UL TBF +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) changes state from FLOW to FINISHED - Scheduling Ack/Nack, because TLLI is included. -Got 'TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN)', TA=7 +- Scheduling Ack/Nack, because last block has CV==0. +Got 'TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FINISHED)', TA=7 Got MS: TLLI = 0xf1223344, TA = 7 ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=0/0 @@ -1577,8 +1546,7 @@ TX: START TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN) Immediate Assignment Downlink (PCH) - TRX=0 (0) TS=7 TA=7 pollFN=-1 Sending data request: trx=0 ts=0 sapi=3 arfcn=0 fn=0 block=0 data=33 34 34 2d 06 3f 30 0f 00 00 7d 80 00 07 00 df 12 23 34 48 00 23 2b 2b 2b 2b -TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=WAIT ASSIGN) append +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN) append Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654218 block=8 data=47 94 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b MS requests UL TBF on RACH, so we provide one: MS requests single block allocation @@ -1618,16 +1586,15 @@ +++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++ ------------------------- TX : Packet Uplink Assignment ------------------------- TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN): Scheduling polling at FN 2654283 TS 7 -TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) Scheduled UL Assignment polling on FN=2654283, TS=7 -Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) (TRX=0, TS=7) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) Scheduled UL Assignment polling on FN=2654283, TS=7 +Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) (TRX=0, TS=7) Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654270 block=8 data=4f 28 5e 24 46 68 8f 1d 00 00 88 00 08 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b Got RLC block, coding scheme: CS-1, length: 23 (23)) +++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ ------------------------- RX : Uplink Control Block ------------------------- -RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) Packet Control Ack -TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) -TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FLOW +RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) Packet Control Ack +TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) changes state from ASSIGN to FLOW Got RLC block, coding scheme: CS-1, length: 23 (23)) UL data: 3c 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 @@ -1704,16 +1671,15 @@ +++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++ ------------------------- TX : Packet Uplink Assignment ------------------------- TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN): Scheduling polling at FN 2654283 TS 7 -TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) Scheduled UL Assignment polling on FN=2654283, TS=7 -Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) (TRX=0, TS=7) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) Scheduled UL Assignment polling on FN=2654283, TS=7 +Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) (TRX=0, TS=7) Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654270 block=8 data=4f 28 5e 24 46 68 8f 1d 00 00 88 00 08 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b Got RLC block, coding scheme: CS-1, length: 23 (23)) +++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ ------------------------- RX : Uplink Control Block ------------------------- -RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) Packet Control Ack -TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) -TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FLOW +RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) Packet Control Ack +TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) changes state from ASSIGN to FLOW Got RLC block, coding scheme: CS-1, length: 23 (23)) UL data: 3c 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 @@ -1756,7 +1722,6 @@ +++++++++++++++++++++++++ TX : Packet Downlink Assignment +++++++++++++++++++++++++ ------------------------- TX : Packet Downlink Assignment ------------------------- TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Scheduling polling at FN 2654288 TS 7 -TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) Scheduled DL Assignment polling on FN=2654288, TS=7 Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) (TRX=0, TS=7) Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654275 block=9 data=48 08 00 00 0c 72 00 02 08 00 80 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b @@ -1765,7 +1730,7 @@ ------------------------- RX : Uplink Control Block ------------------------- RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) Packet Control Ack TBF: [UPLINK] DOWNLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) -TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FLOW +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN) changes state from ASSIGN to FLOW TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) stopping timer 0. Received RTS on disabled PDCH: TRX=0 TS=0 Received RTS on disabled PDCH: TRX=0 TS=1 @@ -1843,16 +1808,15 @@ +++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++ ------------------------- TX : Packet Uplink Assignment ------------------------- TBF(TFI=1 TLLI=0xf5667788 DIR=UL STATE=ASSIGN): Scheduling polling at FN 2654348 TS 7 -TBF(TFI=1 TLLI=0xf5667788 DIR=UL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=1 TLLI=0xf5667788 DIR=UL STATE=WAIT ASSIGN) Scheduled UL Assignment polling on FN=2654348, TS=7 -Scheduling control message at RTS for TBF(TFI=1 TLLI=0xf5667788 DIR=UL STATE=WAIT ASSIGN) (TRX=0, TS=7) +TBF(TFI=1 TLLI=0xf5667788 DIR=UL STATE=ASSIGN) Scheduled UL Assignment polling on FN=2654348, TS=7 +Scheduling control message at RTS for TBF(TFI=1 TLLI=0xf5667788 DIR=UL STATE=ASSIGN) (TRX=0, TS=7) Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654335 block=11 data=48 28 5e ac ce f1 0f 1d 00 00 88 40 09 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b Got RLC block, coding scheme: CS-1, length: 23 (23)) +++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ ------------------------- RX : Uplink Control Block ------------------------- -RX: [PCU <- BTS] TBF(TFI=1 TLLI=0xf5667788 DIR=UL STATE=WAIT ASSIGN) Packet Control Ack -TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=1 TLLI=0xf5667788 DIR=UL STATE=WAIT ASSIGN) -TBF(TFI=1 TLLI=0xf5667788 DIR=UL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FLOW +RX: [PCU <- BTS] TBF(TFI=1 TLLI=0xf5667788 DIR=UL STATE=ASSIGN) Packet Control Ack +TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=1 TLLI=0xf5667788 DIR=UL STATE=ASSIGN) +TBF(TFI=1 TLLI=0xf5667788 DIR=UL STATE=ASSIGN) changes state from ASSIGN to FLOW Got RLC block, coding scheme: CS-1, length: 23 (23)) UL data: 3c 02 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Got CS-1 RLC block: R=0, SI=0, TFI=1, CPS=0, RSB=0, rc=184 @@ -1915,16 +1879,15 @@ +++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++ ------------------------- TX : Packet Uplink Assignment ------------------------- TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN): Scheduling polling at FN 2654283 TS 7 -TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) Scheduled UL Assignment polling on FN=2654283, TS=7 -Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) (TRX=0, TS=7) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) Scheduled UL Assignment polling on FN=2654283, TS=7 +Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) (TRX=0, TS=7) Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654270 block=8 data=4f 28 5e 24 46 68 83 1d 00 00 88 00 08 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b Got RLC block, coding scheme: CS-1, length: 23 (23)) +++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ ------------------------- RX : Uplink Control Block ------------------------- -RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) Packet Control Ack -TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) -TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FLOW +RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) Packet Control Ack +TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) changes state from ASSIGN to FLOW Got RLC block, coding scheme: CS-1, length: 23 (23)) UL data: 3c 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 @@ -2012,16 +1975,15 @@ +++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++ ------------------------- TX : Packet Uplink Assignment ------------------------- TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN): Scheduling polling at FN 2654340 TS 7 -TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) Scheduled UL Assignment polling on FN=2654340, TS=7 -Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) (TRX=0, TS=7) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) Scheduled UL Assignment polling on FN=2654340, TS=7 +Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) (TRX=0, TS=7) Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654327 block=9 data=4f 28 5e 24 46 68 83 1d 00 00 88 00 08 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b Got RLC block, coding scheme: CS-1, length: 23 (23)) +++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ ------------------------- RX : Uplink Control Block ------------------------- -RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) Packet Control Ack -TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) -TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FLOW +RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) Packet Control Ack +TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) changes state from ASSIGN to FLOW ********** TBF starts here ********** Allocating DL TBF: MS_CLASS=1/0 Slot Allocation (Algorithm A) for class 1 @@ -2094,16 +2056,15 @@ +++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++ ------------------------- TX : Packet Uplink Assignment ------------------------- TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN): Scheduling polling at FN 2654283 TS 7 -TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) Scheduled UL Assignment polling on FN=2654283, TS=7 -Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) (TRX=0, TS=7) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) Scheduled UL Assignment polling on FN=2654283, TS=7 +Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) (TRX=0, TS=7) Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654270 block=8 data=4f 28 5e 24 46 68 83 1d 00 00 88 00 08 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b Got RLC block, coding scheme: CS-1, length: 23 (23)) +++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ ------------------------- RX : Uplink Control Block ------------------------- -RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) Packet Control Ack -TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) -TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FLOW +RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) Packet Control Ack +TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) changes state from ASSIGN to FLOW Got RLC block, coding scheme: CS-1, length: 23 (23)) UL data: 3c 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 @@ -2176,15 +2137,14 @@ TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=FLOW) TX: START Immediate Assignment Uplink (AGCH) - TRX=0 (0) TS=7 TA=7 TSC=0 TFI=0 USF=0 Sending data request: trx=0 ts=0 sapi=2 arfcn=0 fn=0 block=0 data=2d 06 3f 10 0f 00 00 03 8b ed 07 00 c8 00 10 0b 2b 2b 2b 2b 2b 2b 2b -TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=FLOW) changes state from FLOW to WAIT ASSIGN Got RLC block, coding scheme: CS-1, length: 23 (23)) UL data: 00 01 01 f1 22 33 44 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 UL DATA TFI=0 received (V(Q)=0 .. V(R)=0) -TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=WAIT ASSIGN) restarting timer 3169 while old timer 3169 pending -TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=WAIT ASSIGN): Got CS-1 RLC data block: CV=0, BSN=0, SPB=0, PI=0, E=1, TI=1, bitoffs=24 +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=0, BSN=0, SPB=0, PI=0, E=1, TI=1, bitoffs=24 - BSN 0 storing in window (0..63) -TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=WAIT ASSIGN): data_length=20, data=f1 22 33 44 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=FLOW): data_length=20, data=f1 22 33 44 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Decoded premier TLLI=0x00000000 of UL DATA TFI=0. Got RACH from TLLI=0x00000000 while TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN) still exists. Killing pending DL TBF TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN) changes state from ASSIGN to RELEASING @@ -2202,10 +2162,14 @@ - Taking block 0 out, raising V(Q) to 1 - Assembling frames: (len=20) -- Frame 1 starts at offset 4, length=16, is_complete=1 -TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) complete UL frame len=16 -LLC [PCU -> SGSN] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) len=16 +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) complete UL frame len=16 +LLC [PCU -> SGSN] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) len=16 No bctx +- No gaps in received block, last block: BSN=0 CV=0 +- Finished with UL TBF +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) changes state from FLOW to FINISHED - Scheduling Ack/Nack, because TLLI is included. +- Scheduling Ack/Nack, because last block has CV==0. New MS: TLLI = 0xf1223344, TA = 7, IMSI = 0011223344, LLC = 2 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654218 block=8 data=47 94 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b MS requests UL TBF on RACH, so we provide one: @@ -2246,16 +2210,15 @@ +++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++ ------------------------- TX : Packet Uplink Assignment ------------------------- TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN): Scheduling polling at FN 2654283 TS 7 -TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) Scheduled UL Assignment polling on FN=2654283, TS=7 -Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) (TRX=0, TS=7) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) Scheduled UL Assignment polling on FN=2654283, TS=7 +Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) (TRX=0, TS=7) Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654270 block=8 data=4f 28 5e 24 46 68 83 1d 00 00 88 00 08 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b Got RLC block, coding scheme: CS-1, length: 23 (23)) +++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ ------------------------- RX : Uplink Control Block ------------------------- -RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) Packet Control Ack -TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) -TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FLOW +RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) Packet Control Ack +TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) changes state from ASSIGN to FLOW Got RLC block, coding scheme: CS-1, length: 23 (23)) UL data: 3c 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 @@ -2337,7 +2300,6 @@ +++++++++++++++++++++++++ TX : Packet Downlink Assignment +++++++++++++++++++++++++ ------------------------- TX : Packet Downlink Assignment ------------------------- TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Scheduling polling at FN 2654288 TS 7 -TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) Scheduled DL Assignment polling on FN=2654288, TS=7 Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) (TRX=0, TS=7) Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654275 block=9 data=48 08 00 00 0c 72 00 02 08 00 80 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b @@ -2346,7 +2308,7 @@ ------------------------- RX : Uplink Control Block ------------------------- RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) Packet Control Ack TBF: [UPLINK] DOWNLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) -TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FLOW +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN) changes state from ASSIGN to FLOW TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) stopping timer 0. Received RTS on disabled PDCH: TRX=0 TS=0 Received RTS on disabled PDCH: TRX=0 TS=1 @@ -2997,7 +2959,6 @@ +++++++++++++++++++++++++ TX : Packet Downlink Assignment +++++++++++++++++++++++++ ------------------------- TX : Packet Downlink Assignment ------------------------- TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=WAIT RELEASE): Scheduling polling at FN 2654413 TS 7 -TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=WAIT RELEASE) Scheduled DL Assignment polling on FN=2654413, TS=7 Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=WAIT RELEASE) (TRX=0, TS=7) Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654400 block=2 data=48 08 20 08 0c 72 00 02 18 00 80 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b @@ -3012,7 +2973,7 @@ PDCH(TS 7, TRX 0): Detaching TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=RELEASING), 1 TBFs, USFs = 01, TFIs = 00000002. Detaching TBF from MS object, TLLI = 0xf1223344, TBF = TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=RELEASING) ********** TBF ends here ********** -TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FLOW +TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=ASSIGN) changes state from ASSIGN to FLOW TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) stopping timer 0. Received RTS on disabled PDCH: TRX=0 TS=0 Received RTS on disabled PDCH: TRX=0 TS=1 @@ -3348,16 +3309,15 @@ +++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++ ------------------------- TX : Packet Uplink Assignment ------------------------- TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS): Scheduling polling at FN 2654283 TS 7 -TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Scheduled UL Assignment polling on FN=2654283, TS=7 -Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) (TRX=0, TS=7) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS) Scheduled UL Assignment polling on FN=2654283, TS=7 +Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS) (TRX=0, TS=7) Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654270 block=8 data=4f 28 5e 24 46 68 90 f8 0a 39 00 00 88 00 08 2b 2b 2b 2b 2b 2b 2b 2b Got RLC block, coding scheme: CS-1, length: 23 (23)) +++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ ------------------------- RX : Uplink Control Block ------------------------- -RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Packet Control Ack -TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) -TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) changes state from WAIT ASSIGN to FLOW +RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS) Packet Control Ack +TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS) changes state from ASSIGN to FLOW Got RLC block, coding scheme: CS-1, length: 23 (23)) UL data: 3c 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 @@ -3441,16 +3401,15 @@ +++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++ ------------------------- TX : Packet Uplink Assignment ------------------------- TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS): Scheduling polling at FN 2654283 TS 7 -TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS) changes state from ASSIGN to WAIT ASSIGN -TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Scheduled UL Assignment polling on FN=2654283, TS=7 -Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) (TRX=0, TS=7) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS) Scheduled UL Assignment polling on FN=2654283, TS=7 +Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS) (TRX=0, TS=7) Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654270 block=8 data=4f 28 5e 24 46 68 90 f8 0a 39 00 00 88 00 08 2b 2b 2b 2b 2b 2b 2b 2b Got RLC block, coding scheme: CS-1, length: 23 (23)) +++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ ------------------------- RX : Uplink Control Block ------------------------- -RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Packet Control Ack -TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) -TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) changes state from WAIT ASSIGN to FLOW +RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS) Packet Control Ack +TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS) changes state from ASSIGN to FLOW Got RLC block, coding scheme: CS-1, length: 23 (23)) UL data: 3c 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 -- To view, visit https://gerrit.osmocom.org/218 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I1532f8e93194368cdc1e3846f82afa6d68cd5fbd Gerrit-PatchSet: 3 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Tue Aug 9 05:56:47 2016 From: gerrit-no-reply at lists.osmocom.org (pravin) Date: Tue, 9 Aug 2016 05:56:47 +0000 Subject: osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Patch Set 9: (1 comment) https://gerrit.osmocom.org/#/c/416/8/src/pcu_main.cpp File src/pcu_main.cpp: Line 172: tall_tree_ctx = talloc_named_const(tall_pcu_ctx, 0, "decode-tree context"); > nack. We have taken the reference of MS object creation for hierarchical talloc usage. In gprs_ms.cpp, talloc_named_const is used to create tall_ms_ctx under tall_pcu_ctx and hence, tall_pcu_ctx will be the parent of tall_ms_ctx. Similarly,tall_tree_ctx is created under tall_pcu_ctx. All the tree nodes are created under tall_tree_ctx. This is verified using talloc report.Please let me know if you have further comments. -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 9 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: pravin Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 9 06:29:52 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 9 Aug 2016 06:29:52 +0000 Subject: [PATCH] osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/655 to look at the new patch set (#4). Modify EGPRS DL TBF flow to support SPB Modify the EGPRS DL TBF flow to support Split block during Retx. This patch will also Upgrade the test suite with test cases to validate the EGPRS Downlink SPB for Retransmission Scenarios like MCS6->MCS3, MCS4->MCS1, MCS5->MCS2, MCS9->MCS3 MCS7->MCS2, MCS8->MCS3 have been simulated and Integration tested in NuRAN 1.0 hardware thoroughly. Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 --- M src/gprs_coding_scheme.h M src/pcu_main.cpp M src/pcu_vty.c M src/rlc.cpp M src/rlc.h M src/tbf.h M src/tbf_dl.cpp M tests/edge/EdgeTest.cpp M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 11 files changed, 950 insertions(+), 77 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/55/655/4 diff --git a/src/gprs_coding_scheme.h b/src/gprs_coding_scheme.h index 60a8e79..3b15372 100644 --- a/src/gprs_coding_scheme.h +++ b/src/gprs_coding_scheme.h @@ -113,7 +113,8 @@ static const char *modeName(Mode mode); static Scheme get_retx_mcs(const GprsCodingScheme mcs, - const GprsCodingScheme retx_mcs); + const GprsCodingScheme retx_mcs, + const unsigned arq_type); static enum Scheme egprs_mcs_retx_tbl[MAX_NUM_ARQ] [MAX_NUM_MCS][MAX_NUM_MCS]; @@ -232,8 +233,9 @@ } inline GprsCodingScheme::Scheme GprsCodingScheme::get_retx_mcs( const GprsCodingScheme mcs, - const GprsCodingScheme demanded_mcs) + const GprsCodingScheme demanded_mcs, + const unsigned arq_type) { - return egprs_mcs_retx_tbl[EGPRS_ARQ2][mcs.to_num() - 1] + return egprs_mcs_retx_tbl[arq_type][mcs.to_num() - 1] [demanded_mcs.to_num() - 1]; } diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2d86cda..e34d534 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -210,6 +210,12 @@ bts->dl_tbf_idle_msec = 2000; bts->llc_idle_ack_csec = 10; + /* + * By default resegmentation is supported in DL + * can also be configured through VTY + */ + bts->dl_arq_type = EGPRS_ARQ1; + msgb_set_talloc_ctx(tall_pcu_ctx); osmo_init_logging(&gprs_log_info); diff --git a/src/pcu_vty.c b/src/pcu_vty.c index 58fea99..81fdb88 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -129,6 +129,9 @@ vty_out(vty, " window-size %d %d%s", bts->ws_base, bts->ws_pdch, VTY_NEWLINE); + if (bts->dl_arq_type) + vty_out(vty, " arq %d %s", bts->dl_arq_type, VTY_NEWLINE); + if (bts->force_llc_lifetime == 0xffff) vty_out(vty, " queue lifetime infinite%s", VTY_NEWLINE); else if (bts->force_llc_lifetime) @@ -477,6 +480,22 @@ bts->max_mcs_dl = 0; bts->max_mcs_ul = 0; + return CMD_SUCCESS; +} + +#define EGPRS_DL_ARQ_STR "DL ARQ TYPE (EGPRS)\n" + +DEFUN(cfg_pcu_dl_arq_type, + cfg_pcu_dl_arq_cmd, + "dl arq <0-1> [<0-1>]", + EGPRS_DL_ARQ_STR + "Initial ARQ value to be used is (default 0:Reseg)\n" + "0:Reseg, 1:no Reseg") +{ + struct gprs_rlcmac_bts *bts = bts_main_data(); + uint8_t dl_arq_type = atoi(argv[0]); + + bts->dl_arq_type = dl_arq_type; return CMD_SUCCESS; } @@ -954,6 +973,7 @@ install_element(PCU_NODE, &cfg_pcu_no_cs_downgrade_thrsh_cmd); install_element(PCU_NODE, &cfg_pcu_cs_lqual_ranges_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_cmd); + install_element(PCU_NODE, &cfg_pcu_dl_arq_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_max_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_max_cmd); diff --git a/src/rlc.cpp b/src/rlc.cpp index 6770043..8da96f7 100644 --- a/src/rlc.cpp +++ b/src/rlc.cpp @@ -285,7 +285,8 @@ } static void gprs_rlc_data_header_init(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding, unsigned int header_bits) + GprsCodingScheme cs, bool with_padding, unsigned int header_bits, + const unsigned int spb) { unsigned int i; unsigned int padding_bits = with_padding ? cs.optionalPaddingBits() : 0; @@ -300,7 +301,7 @@ for (i = 0; i < rlc->num_data_blocks; i++) { gprs_rlc_data_block_info_init(&rlc->block_info[i], cs, - with_padding); + with_padding, spb); rlc->data_offs_bits[i] = header_bits + padding_bits + @@ -310,21 +311,25 @@ } void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsDL()); + cs.numDataHeaderBitsDL(), spb); } void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding) { + /* + * last parameter is sent as 0 since common function used + * for both DL and UL + */ return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsUL()); + cs.numDataHeaderBitsUL(), 0); } void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { unsigned int data_len = cs.maxDataBlockBytes(); if (with_padding) @@ -336,7 +341,7 @@ rdbi->e = 1; rdbi->cv = 15; rdbi->pi = 0; - rdbi->spb = 0; + rdbi->spb = spb; } unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, @@ -411,8 +416,17 @@ enum egprs_puncturing_values gprs_get_punct_scheme( enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current) + const GprsCodingScheme &cs_current, + const unsigned int spb) { + + /* + * If it is second segment of the block + * dont change the puncturing scheme + */ + if (spb == 3) + return punct; + /* TS 44.060 9.3.2.1.1 */ if ((GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS9) && (GprsCodingScheme::Scheme(cs_current) == GprsCodingScheme::MCS6)) { diff --git a/src/rlc.h b/src/rlc.h index 539b30b..66faf6f 100644 --- a/src/rlc.h +++ b/src/rlc.h @@ -206,18 +206,19 @@ }; void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding); void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, enum egprs_puncturing_values punct, enum egprs_puncturing_values punct2, int with_padding); void gprs_rlc_mcs_cps_decode(unsigned int cps, GprsCodingScheme cs, int *punct, int *punct2, int *with_padding); enum egprs_puncturing_values gprs_get_punct_scheme(enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current_trans); + const GprsCodingScheme &cs_current_trans, + const unsigned int spb); void gprs_update_punct_scheme(enum egprs_puncturing_values *punct, const GprsCodingScheme &cs); /* diff --git a/src/tbf.h b/src/tbf.h index 1bd7878..969836b 100644 --- a/src/tbf.h +++ b/src/tbf.h @@ -421,6 +421,11 @@ int analyse_errors(char *show_rbb, uint8_t ssn, ana_result *res); void schedule_next_frame(); + enum egprs_rlc_dl_reseg_bsn_state egprs_dl_get_data_buffer + (int bsn, uint8_t **block_data); + unsigned int get_egprs_dl_spb_status(int bsn); + unsigned int get_egprs_dl_spb_value(int bsn); + struct osmo_timer_list m_llc_timer; }; diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp index 07a747a..0395ed0 100644 --- a/src/tbf_dl.cpp +++ b/src/tbf_dl.cpp @@ -375,21 +375,27 @@ return -1; if (is_egprs_enabled()) { + /* Table 8.1.1.2 and Table 8.1.1.1 of 44.060 */ m_rlc.block(bsn)->cs_current_trans = - GprsCodingScheme::get_retx_mcs( - m_rlc.block(bsn)->cs_last, ms()->current_cs_dl()); + GprsCodingScheme::get_retx_mcs( + m_rlc.block(bsn)->cs_init, + ms()->current_cs_dl(), + bts->bts_data()->dl_arq_type); LOGP(DRLCMACDL, LOGL_DEBUG, - "- current_cs_dl(%d) demanded_mcs(%d) cs_trans(%d)\n", + "- initial_cs_dl(%d) last_mcs(%d) demanded_mcs(%d)" + "cs_trans(%d) arq_type(%d) bsn(%d)\n", + m_rlc.block(bsn)->cs_init.to_num(), m_rlc.block(bsn)->cs_last.to_num(), ms()->current_cs_dl().to_num(), - m_rlc.block(bsn)->cs_current_trans.to_num()); + m_rlc.block(bsn)->cs_current_trans.to_num(), + bts->bts_data()->dl_arq_type, bsn); /* TODO: Need to remove this check when MCS-8 -> MCS-6 * transistion is handled. * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 */ - if (m_rlc.block(bsn)->cs_last == GprsCodingScheme::MCS8) + if (m_rlc.block(bsn)->cs_init == GprsCodingScheme::MCS8) m_rlc.block(bsn)->cs_current_trans = GprsCodingScheme::MCS8; } else @@ -523,6 +529,11 @@ data = rlc_data->prepare(block_data_len); rlc_data->cs_last = cs; rlc_data->cs_current_trans = cs; + + /* Initialise the variable related to DL SPB */ + rlc_data->spb_status.block_status_dl = EGPRS_RESEG_DL_DEFAULT; + rlc_data->cs_init = cs; + rlc_data->len = block_data_len; rdbi = &(rlc_data->block_info); @@ -616,6 +627,7 @@ unsigned num_bsns; enum egprs_puncturing_values punct[ARRAY_SIZE(rlc.block_info)]; bool need_padding = false; + unsigned int spb = 0; /* * TODO: This is an experimental work-around to put 2 BSN into @@ -626,6 +638,7 @@ * the current limit. */ cs = m_rlc.block(index)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(index)->cs_init; bsns[0] = index; num_bsns = 1; @@ -634,7 +647,19 @@ num_bsns += 1; } - if (num_bsns == 1) { + /* + * if the intial mcs is 8 and retransmission mcs is either 6 or 3 + * we have to include the padding of 6 octets in first segment + */ + if ((GprsCodingScheme::Scheme(cs_init) == GprsCodingScheme::MCS8) && + (GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS6 || + GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS3)) { + if ((get_egprs_dl_spb_status(index) == + EGPRS_RESEG_DL_DEFAULT) || + (get_egprs_dl_spb_status(index) == + EGPRS_RESEG_SECOND_SEG_SENT)) + need_padding = true; + } else if (num_bsns == 1) { /* TODO: remove the conditional when MCS-6 padding isn't * failing to be decoded by MEs anymore */ /* TODO: support of MCS-8 -> MCS-6 transition should be @@ -646,7 +671,14 @@ cs.decToSingleBlock(&need_padding); } - gprs_rlc_data_info_init_dl(&rlc, cs, need_padding); + spb = get_egprs_dl_spb_value(index); + + LOGP(DRLCMACDL, LOGL_DEBUG, "- need_padding %d spb_status %d spb %d" + "(BSN1 %d BSN2 %d)\n", + need_padding, + get_egprs_dl_spb_status(index), spb, index, index2); + + gprs_rlc_data_info_init_dl(&rlc, cs, need_padding, spb); rlc.usf = 7; /* will be set at scheduler */ rlc.pr = 0; /* FIXME: power reduction */ @@ -665,10 +697,9 @@ data_block_idx++) { int bsn; - GprsCodingScheme cs_enc; uint8_t *block_data; gprs_rlc_data_block_info *rdbi, *block_info; - enum egprs_puncturing_values punct_scheme; + enum egprs_rlc_dl_reseg_bsn_state reseg_status; /* Check if there are more blocks than BSNs */ if (data_block_idx < num_bsns) @@ -676,38 +707,43 @@ else bsn = bsns[0]; - cs_enc = m_rlc.block(bsn)->cs_current_trans; - /* get data and header from current block */ - block_data = m_rlc.block(bsn)->block; - /* Get current puncturing scheme from block */ - punct_scheme = gprs_get_punct_scheme( + + m_rlc.block(bsn)->next_ps = gprs_get_punct_scheme( m_rlc.block(bsn)->next_ps, - m_rlc.block(bsn)->cs_last, cs); + m_rlc.block(bsn)->cs_last, cs, spb); if (cs.isEgprs()) { - OSMO_ASSERT(punct_scheme >= EGPRS_PS_1); - OSMO_ASSERT(punct_scheme <= EGPRS_PS_3); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps >= EGPRS_PS_1); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps <= EGPRS_PS_3); } - punct[data_block_idx] = punct_scheme; + punct[data_block_idx] = m_rlc.block(bsn)->next_ps; rdbi = &rlc.block_info[data_block_idx]; block_info = &m_rlc.block(bsn)->block_info; - if(rdbi->data_len != m_rlc.block(bsn)->len) { - LOGP(DRLCMACDL, LOGL_ERROR, - "ERROR: Expected len = %d for %s instead of " - "%d in data unit %d (BSN %d, %s)\n", - rdbi->data_len, cs.name(), m_rlc.block(bsn)->len, - data_block_idx, bsn, cs_enc.name()); - OSMO_ASSERT(rdbi->data_len == m_rlc.block(bsn)->len); - } - - /* TODO: Need to handle 2 same bsns - * in header type 1 + /* + * get data and header from current block + * function returns the reseg status */ - gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, - cs); + reseg_status = egprs_dl_get_data_buffer(bsn, &block_data); + m_rlc.block(bsn)->spb_status.block_status_dl = reseg_status; + + /* + * If it is first segment of the split block set the state of + * bsn to nacked. If it is the first segment dont update the + * next ps value of bsn. since next segment also needs same cps + */ + if (spb == 2) + m_window.m_v_b.mark_nacked(bsn); + else { + /* + * TODO: Need to handle 2 same bsns + * in header type 1 + */ + gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, + cs); + } m_rlc.block(bsn)->cs_last = cs; rdbi->e = block_info->e; @@ -1169,3 +1205,119 @@ keep_time_frames = msecs_to_frames(bts_data()->dl_tbf_idle_msec); return frames_since_last_drain(fn) <= keep_time_frames; } + +/* + * This function returns the pointer to data which needs + * to be copied. Also updates the status of the block related to + * Split block handling in the RLC/MAC block. + */ +enum egprs_rlc_dl_reseg_bsn_state + gprs_rlcmac_dl_tbf::egprs_dl_get_data_buffer(int bsn, + uint8_t **block_data) +{ + gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state *block_status_dl = + &rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + *block_data = &rlc_data->block[0]; + + /* + * Table 10.3a.0.1 of 44.060 + * MCS6,9: second segment starts at 74/2 = 37 + * MCS5,7: second segment starts at 56/2 = 28 + * MCS8: second segment starts at 31 + * MCS4: second segment starts at 44/2 = 22 + */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + if (*block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + switch (GprsCodingScheme::Scheme(cs_init)) { + case GprsCodingScheme::MCS6 : + case GprsCodingScheme::MCS9 : + *block_data = &rlc_data->block[37]; + break; + case GprsCodingScheme::MCS7 : + case GprsCodingScheme::MCS5 : + *block_data = &rlc_data->block[28]; + break; + case GprsCodingScheme::MCS8 : + *block_data = &rlc_data->block[31]; + break; + case GprsCodingScheme::MCS4 : + *block_data = &rlc_data->block[22]; + break; + default: + LOGP(DRLCMACDL, LOGL_ERROR, "Software error: " + "--%s hit invalid condition. headerType(%d) " + " blockstatus(%d) cs(%s) PLEASE FIX!\n", name(), + cs_current_trans.headerTypeData(), + *block_status_dl, cs_init.name()); + break; + + } + return EGPRS_RESEG_SECOND_SEG_SENT; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } + } + return EGPRS_RESEG_DL_DEFAULT; +} + +/* + * This function returns the status of split block + * for RLC/MAC block. + */ +unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_status(const int bsn) +{ + const gprs_rlc_data *rlc_data = m_rlc.block(bsn); + + return rlc_data->spb_status.block_status_dl; +} + +/* + * This function returns the spb value to be sent OTA + * for RLC/MAC block. + */ +unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_value(const int bsn) +{ + struct gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state block_status_dl = + rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + + /* Table 10.4.8b.1 of 44.060 */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + /* + * if we are sending the second segment the spb should be 3 + * other wise it should be 2 + */ + if (block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + return 3; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return 2; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return 2; + } + } + /* Non SPB cases 0 is reurned */ + return 0; +} diff --git a/tests/edge/EdgeTest.cpp b/tests/edge/EdgeTest.cpp index 807102c..9081d4d 100644 --- a/tests/edge/EdgeTest.cpp +++ b/tests/edge/EdgeTest.cpp @@ -517,7 +517,7 @@ /* TS 44.060, B.1 */ cs = GprsCodingScheme::CS4; - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -570,7 +570,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -592,7 +592,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -630,7 +630,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -669,7 +669,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -694,7 +694,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -719,7 +719,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -740,7 +740,7 @@ OSMO_ASSERT(data[0] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -777,7 +777,7 @@ cs = GprsCodingScheme::MCS4; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -835,7 +835,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -872,7 +872,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -923,7 +923,7 @@ OSMO_ASSERT(data[3] == 0); /* Block 3 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -967,7 +967,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -993,7 +993,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1020,7 +1020,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1074,7 +1074,7 @@ block_idx++) { struct gprs_rlc_data_info rlc; - gprs_rlc_data_info_init_dl(&rlc, cs, false); + gprs_rlc_data_info_init_dl(&rlc, cs, false, 0); memset(bits, pattern, sizeof(bits)); Decoding::rlc_copy_to_aligned_buffer( @@ -1118,12 +1118,14 @@ struct gprs_rlc_data_info rlc; printf("=== start %s ===\n", __func__); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::CS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::CS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 24); OSMO_ASSERT(rlc.block_info[0].data_len == 20); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::MCS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::MCS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 33); OSMO_ASSERT(rlc.block_info[0].data_len == 22); diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..18cc5cb 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -1814,6 +1814,201 @@ } +static void egprs_spb_to_normal_validation(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + uint16_t bsn1, bsn2, bsn3; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + struct gprs_rlc_dl_header_egprs_2 *egprs2; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + if ((mcs == 6) && (demanded_mcs == 3)) { + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + bsn1 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) + || (egprs2->bsn1_lo); + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(bsn1 == 0); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + bsn2 = (egprs3->bsn1_hi << 9) || (egprs3->bsn1_mid << 1) || + (egprs3->bsn1_lo); + OSMO_ASSERT(bsn2 == bsn1); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Handle (MCS3, MCS3) -> MCS6 case */ + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + mcs)); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs2->cps == 0); + bsn3 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) || + (egprs2->bsn1_lo); + OSMO_ASSERT(bsn3 == bsn2); + + tbf_cleanup(dl_tbf); + } +} +static void establish_and_use_egprs_dl_tbf_for_spb(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + /* TODO: Need to support of MCS8 -> MCS6 ->MCS3 transistion + * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 + * dated 2016-02-07 23:45:40 (UTC) + */ + if (((mcs == 5) && (demanded_mcs == 2)) || + ((mcs == 6) && (demanded_mcs == 3)) || + ((mcs == 4) && (demanded_mcs == 1))) { + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + tbf_cleanup(dl_tbf); + } +} + static void establish_and_use_egprs_dl_tbf_for_retx(BTS *the_bts, int mcs, int demanded_mcs) { @@ -1972,6 +2167,9 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; + /* First parameter is current MCS, second one is demanded_mcs */ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 6); @@ -1981,6 +2179,38 @@ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 9); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 7, 5); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 9, 6); + + printf("=== end %s ===\n", __func__); +} + +static void test_tbf_egprs_spb_dl(void) +{ + BTS the_bts; + gprs_rlcmac_bts *bts; + uint8_t ts_no = 4; + int i, j; + + printf("=== start %s ===\n", __func__); + + bts = the_bts.bts_data(); + bts->cs_downgrade_threshold = 0; + setup_bts(&the_bts, ts_no); + bts->dl_tbf_idle_msec = 200; + bts->egprs_enabled = 1; + + /* ARQ I resegmentation support */ + bts->dl_arq_type = EGPRS_ARQ1; + + /* + * First parameter is current MCS, second one is demanded_mcs + * currently only MCS5->MCS2, MCS6->3, MCS4->MCS1 is tested in UT + * rest scenarios has been integration tested + */ + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 6, 3); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 5, 2); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 4, 1); + /* check MCS6->(MCS3+MCS3)->MCS6 case */ + egprs_spb_to_normal_validation(&the_bts, 6, 3); printf("=== end %s ===\n", __func__); } @@ -1999,6 +2229,8 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; for (i = 1; i <= 9; i++) establish_and_use_egprs_dl_tbf(&the_bts, i); @@ -2071,6 +2303,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_egprs_spb_dl(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..7b3f339 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -72,6 +72,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -81,6 +82,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -157,6 +159,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -166,6 +169,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -242,6 +246,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -251,6 +256,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -259,6 +265,7 @@ - Sending new block at BSN 2, CS=CS-1 -- Chunk with length 160 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=13 block=3 data=07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b @@ -267,6 +274,7 @@ - Sending new block at BSN 3, CS=CS-1 -- Chunk with length 140 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=17 block=4 data=07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @@ -275,6 +283,7 @@ - Sending new block at BSN 4, CS=CS-1 -- Chunk with length 120 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=21 block=5 data=07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 @@ -283,6 +292,7 @@ - Sending new block at BSN 5, CS=CS-1 -- Chunk with length 100 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=26 block=6 data=07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 @@ -291,6 +301,7 @@ - Sending new block at BSN 6, CS=CS-1 -- Chunk with length 80 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=30 block=7 data=07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b @@ -299,6 +310,7 @@ - Sending new block at BSN 7, CS=CS-1 -- Chunk with length 60 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=34 block=8 data=07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f @@ -307,6 +319,7 @@ - Sending new block at BSN 8, CS=CS-1 -- Chunk with length 40 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=39 block=9 data=07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 @@ -315,6 +328,7 @@ - Sending new block at BSN 9, CS=CS-1 -- Chunk with length 20 would exactly fit into space (20): add length header with LI=0, to make frame extend to next block, and we are done data block (BSN 9, CS-1): 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=43 block=10 data=07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 @@ -326,6 +340,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=47 block=11 data=07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 @@ -334,6 +349,7 @@ - Sending new block at BSN 11, CS=CS-1 -- Chunk with length 182 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=52 block=0 data=07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 @@ -342,6 +358,7 @@ - Sending new block at BSN 12, CS=CS-1 -- Chunk with length 162 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=56 block=1 data=07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 @@ -350,6 +367,7 @@ - Sending new block at BSN 13, CS=CS-1 -- Chunk with length 142 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 13, CS-1): 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=60 block=2 data=07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d @@ -358,6 +376,7 @@ - Sending new block at BSN 14, CS=CS-1 -- Chunk with length 122 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=65 block=3 data=07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 @@ -366,6 +385,7 @@ - Sending new block at BSN 15, CS=CS-1 -- Chunk with length 102 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=69 block=4 data=07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 @@ -374,6 +394,7 @@ - Sending new block at BSN 16, CS=CS-1 -- Chunk with length 82 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=73 block=5 data=07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 @@ -382,6 +403,7 @@ - Sending new block at BSN 17, CS=CS-1 -- Chunk with length 62 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=78 block=6 data=07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d @@ -390,6 +412,7 @@ - Sending new block at BSN 18, CS=CS-1 -- Chunk with length 42 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=82 block=7 data=07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 @@ -398,6 +421,7 @@ - Sending new block at BSN 19, CS=CS-1 -- Chunk with length 22 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=86 block=8 data=07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 @@ -411,6 +435,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=16 data block (BSN 20, CS-1): 0a 41 c6 c7 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -449,6 +474,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 data block (BSN 21, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -468,6 +494,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 22, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FINISHED) @@ -1481,6 +1508,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 0, CS-1): 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 MSG = 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 @@ -1491,6 +1519,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 1, CS-1): 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 MSG = 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 @@ -1501,6 +1530,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FINISHED data block (BSN 2, CS-1): 4d 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling cannot be scheduled in this TS 7 (first control TS 4) @@ -1784,6 +1814,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=10 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 0, CS-4): 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654292 TS 7 @@ -1797,6 +1828,7 @@ TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) downlink (V(A)==0 .. V(S)==1) - Restarting at BSN 0, because all blocks have been transmitted. - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-4): 07 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 @@ -2365,6 +2397,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654279 block=10 data=00 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 @@ -2384,6 +2417,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -2406,6 +2440,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654288 block=0 data=00 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 @@ -2425,6 +2460,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654292 block=1 data=00 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2447,6 +2483,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654296 block=2 data=00 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c @@ -2466,6 +2503,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654301 block=3 data=00 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b @@ -2488,6 +2526,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 6, CS-1): 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654305 block=4 data=00 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 @@ -2507,6 +2546,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654309 block=5 data=00 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 @@ -2526,6 +2566,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654314 block=6 data=00 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 @@ -2548,6 +2589,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654318 block=7 data=00 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 @@ -2567,6 +2609,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654322 block=8 data=00 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2589,6 +2632,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654327 block=9 data=00 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c @@ -2608,6 +2652,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654331 block=10 data=00 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b @@ -2630,6 +2675,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 13, CS-1): 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654335 block=11 data=00 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 @@ -2649,6 +2695,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654340 block=0 data=00 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 @@ -2668,6 +2715,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654344 block=1 data=00 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 @@ -2690,6 +2738,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654348 block=2 data=00 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 @@ -2709,6 +2758,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654353 block=3 data=00 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2731,6 +2781,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654357 block=4 data=00 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c @@ -2750,6 +2801,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654361 block=5 data=00 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b @@ -2772,6 +2824,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 20, CS-1): 16 35 45 54 20 32 38 4c 4c 43 20 50 41 43 4b 45 54 20 32 39 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because 20 blocks sent. TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW): Scheduling polling at FN 2654379 TS 7 @@ -2795,6 +2848,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 21, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) msg block (BSN 21, CS-1): 07 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654370 block=7 data=00 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 @@ -2814,6 +2868,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 22, CS-1): 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) msg block (BSN 22, CS-1): 07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654374 block=8 data=07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 @@ -2836,6 +2891,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 23, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) msg block (BSN 23, CS-1): 07 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654379 block=9 data=00 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 @@ -2855,6 +2911,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 24, CS-1): 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) msg block (BSN 24, CS-1): 07 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654383 block=10 data=00 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2877,6 +2934,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 25, CS-1): 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 25 BSN2 -1) - Copying data unit 0 (BSN 25) msg block (BSN 25, CS-1): 07 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654387 block=11 data=00 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c @@ -2896,6 +2954,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 26, CS-1): 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 26 BSN2 -1) - Copying data unit 0 (BSN 26) msg block (BSN 26, CS-1): 07 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654392 block=0 data=00 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b @@ -2918,6 +2977,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 27, CS-1): 16 35 45 54 20 33 38 4c 4c 43 20 50 41 43 4b 45 54 20 33 39 +- need_padding 0 spb_status 0 spb 0(BSN1 27 BSN2 -1) - Copying data unit 0 (BSN 27) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) @@ -3028,6 +3088,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654405 block=3 data=00 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 @@ -3047,6 +3108,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654409 block=4 data=00 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 @@ -3066,6 +3128,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (16) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654413 block=5 data=00 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 @@ -3085,6 +3148,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (14) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654418 block=6 data=00 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 @@ -3104,6 +3168,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654422 block=7 data=00 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -3123,6 +3188,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654426 block=8 data=00 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 @@ -3142,6 +3208,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654431 block=9 data=00 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b @@ -3161,6 +3228,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654435 block=10 data=00 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 @@ -3180,6 +3248,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654439 block=11 data=00 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 @@ -3199,6 +3268,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654444 block=0 data=00 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c @@ -3218,6 +3288,7 @@ Complete DL frame for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=21 TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 10, CS-1): 4d 43 20 50 41 43 4b 45 54 20 30 39 20 28 54 42 46 20 32 29 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654461 TS 7 @@ -3698,6 +3769,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 0, MCS-1): 14 15 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3711,6 +3783,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3721,6 +3794,7 @@ - Sending new block at BSN 2, CS=MCS-1 -- Chunk with length 490 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3731,6 +3805,7 @@ - Sending new block at BSN 3, CS=MCS-1 -- Chunk with length 468 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3741,6 +3816,7 @@ - Sending new block at BSN 4, CS=MCS-1 -- Chunk with length 446 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3751,6 +3827,7 @@ - Sending new block at BSN 5, CS=MCS-1 -- Chunk with length 424 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3761,6 +3838,7 @@ - Sending new block at BSN 6, CS=MCS-1 -- Chunk with length 402 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3771,6 +3849,7 @@ - Sending new block at BSN 7, CS=MCS-1 -- Chunk with length 380 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3781,6 +3860,7 @@ - Sending new block at BSN 8, CS=MCS-1 -- Chunk with length 358 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3791,6 +3871,7 @@ - Sending new block at BSN 9, CS=MCS-1 -- Chunk with length 336 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3801,6 +3882,7 @@ - Sending new block at BSN 10, CS=MCS-1 -- Chunk with length 314 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3811,6 +3893,7 @@ - Sending new block at BSN 11, CS=MCS-1 -- Chunk with length 292 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3821,6 +3904,7 @@ - Sending new block at BSN 12, CS=MCS-1 -- Chunk with length 270 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3831,6 +3915,7 @@ - Sending new block at BSN 13, CS=MCS-1 -- Chunk with length 248 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3841,6 +3926,7 @@ - Sending new block at BSN 14, CS=MCS-1 -- Chunk with length 226 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3851,6 +3937,7 @@ - Sending new block at BSN 15, CS=MCS-1 -- Chunk with length 204 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3861,6 +3948,7 @@ - Sending new block at BSN 16, CS=MCS-1 -- Chunk with length 182 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3871,6 +3959,7 @@ - Sending new block at BSN 17, CS=MCS-1 -- Chunk with length 160 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3881,6 +3970,7 @@ - Sending new block at BSN 18, CS=MCS-1 -- Chunk with length 138 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3891,6 +3981,7 @@ - Sending new block at BSN 19, CS=MCS-1 -- Chunk with length 116 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 19, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3901,6 +3992,7 @@ - Sending new block at BSN 20, CS=MCS-1 -- Chunk with length 94 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 20, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3911,6 +4003,7 @@ - Sending new block at BSN 21, CS=MCS-1 -- Chunk with length 72 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 21, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3921,6 +4014,7 @@ - Sending new block at BSN 22, CS=MCS-1 -- Chunk with length 50 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 22, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3931,6 +4025,7 @@ - Sending new block at BSN 23, CS=MCS-1 -- Chunk with length 28 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 23, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3946,6 +4041,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 24, MCS-1): 0c 1d 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4006,6 +4102,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=16 data block (BSN 0, MCS-2): 14 21 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4019,6 +4116,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4029,6 +4127,7 @@ - Sending new block at BSN 2, CS=MCS-2 -- Chunk with length 484 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4039,6 +4138,7 @@ - Sending new block at BSN 3, CS=MCS-2 -- Chunk with length 456 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4049,6 +4149,7 @@ - Sending new block at BSN 4, CS=MCS-2 -- Chunk with length 428 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4059,6 +4160,7 @@ - Sending new block at BSN 5, CS=MCS-2 -- Chunk with length 400 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4069,6 +4171,7 @@ - Sending new block at BSN 6, CS=MCS-2 -- Chunk with length 372 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4079,6 +4182,7 @@ - Sending new block at BSN 7, CS=MCS-2 -- Chunk with length 344 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4089,6 +4193,7 @@ - Sending new block at BSN 8, CS=MCS-2 -- Chunk with length 316 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4099,6 +4204,7 @@ - Sending new block at BSN 9, CS=MCS-2 -- Chunk with length 288 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4109,6 +4215,7 @@ - Sending new block at BSN 10, CS=MCS-2 -- Chunk with length 260 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4119,6 +4226,7 @@ - Sending new block at BSN 11, CS=MCS-2 -- Chunk with length 232 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4129,6 +4237,7 @@ - Sending new block at BSN 12, CS=MCS-2 -- Chunk with length 204 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4139,6 +4248,7 @@ - Sending new block at BSN 13, CS=MCS-2 -- Chunk with length 176 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4149,6 +4259,7 @@ - Sending new block at BSN 14, CS=MCS-2 -- Chunk with length 148 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4159,6 +4270,7 @@ - Sending new block at BSN 15, CS=MCS-2 -- Chunk with length 120 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4169,6 +4281,7 @@ - Sending new block at BSN 16, CS=MCS-2 -- Chunk with length 92 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4179,6 +4292,7 @@ - Sending new block at BSN 17, CS=MCS-2 -- Chunk with length 64 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4189,6 +4303,7 @@ - Sending new block at BSN 18, CS=MCS-2 -- Chunk with length 36 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4204,6 +4319,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=18 data block (BSN 19, MCS-2): 10 25 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4264,6 +4380,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=25 data block (BSN 0, MCS-3): 14 33 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4277,6 +4394,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4287,6 +4405,7 @@ - Sending new block at BSN 2, CS=MCS-3 -- Chunk with length 475 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4297,6 +4416,7 @@ - Sending new block at BSN 3, CS=MCS-3 -- Chunk with length 438 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4307,6 +4427,7 @@ - Sending new block at BSN 4, CS=MCS-3 -- Chunk with length 401 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4317,6 +4438,7 @@ - Sending new block at BSN 5, CS=MCS-3 -- Chunk with length 364 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4327,6 +4449,7 @@ - Sending new block at BSN 6, CS=MCS-3 -- Chunk with length 327 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4337,6 +4460,7 @@ - Sending new block at BSN 7, CS=MCS-3 -- Chunk with length 290 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4347,6 +4471,7 @@ - Sending new block at BSN 8, CS=MCS-3 -- Chunk with length 253 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4357,6 +4482,7 @@ - Sending new block at BSN 9, CS=MCS-3 -- Chunk with length 216 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4367,6 +4493,7 @@ - Sending new block at BSN 10, CS=MCS-3 -- Chunk with length 179 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4377,6 +4504,7 @@ - Sending new block at BSN 11, CS=MCS-3 -- Chunk with length 142 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4387,6 +4515,7 @@ - Sending new block at BSN 12, CS=MCS-3 -- Chunk with length 105 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4397,6 +4526,7 @@ - Sending new block at BSN 13, CS=MCS-3 -- Chunk with length 68 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4410,6 +4540,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-3): 3f 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4425,6 +4556,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=34 data block (BSN 15, MCS-3): 02 45 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4485,6 +4617,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=32 data block (BSN 0, MCS-4): 14 41 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4498,6 +4631,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4508,6 +4642,7 @@ - Sending new block at BSN 2, CS=MCS-4 -- Chunk with length 468 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4518,6 +4653,7 @@ - Sending new block at BSN 3, CS=MCS-4 -- Chunk with length 424 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4528,6 +4664,7 @@ - Sending new block at BSN 4, CS=MCS-4 -- Chunk with length 380 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4538,6 +4675,7 @@ - Sending new block at BSN 5, CS=MCS-4 -- Chunk with length 336 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4548,6 +4686,7 @@ - Sending new block at BSN 6, CS=MCS-4 -- Chunk with length 292 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4558,6 +4697,7 @@ - Sending new block at BSN 7, CS=MCS-4 -- Chunk with length 248 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4568,6 +4708,7 @@ - Sending new block at BSN 8, CS=MCS-4 -- Chunk with length 204 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4578,6 +4719,7 @@ - Sending new block at BSN 9, CS=MCS-4 -- Chunk with length 160 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4588,6 +4730,7 @@ - Sending new block at BSN 10, CS=MCS-4 -- Chunk with length 116 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4598,6 +4741,7 @@ - Sending new block at BSN 11, CS=MCS-4 -- Chunk with length 72 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4613,6 +4757,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 12, MCS-4): 38 1d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4673,6 +4818,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-5): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4686,6 +4832,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4696,6 +4843,7 @@ - Sending new block at BSN 2, CS=MCS-5 -- Chunk with length 456 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4706,6 +4854,7 @@ - Sending new block at BSN 3, CS=MCS-5 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4716,6 +4865,7 @@ - Sending new block at BSN 4, CS=MCS-5 -- Chunk with length 344 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4726,6 +4876,7 @@ - Sending new block at BSN 5, CS=MCS-5 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4736,6 +4887,7 @@ - Sending new block at BSN 6, CS=MCS-5 -- Chunk with length 232 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4746,6 +4898,7 @@ - Sending new block at BSN 7, CS=MCS-5 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4756,6 +4909,7 @@ - Sending new block at BSN 8, CS=MCS-5 -- Chunk with length 120 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4766,6 +4920,7 @@ - Sending new block at BSN 9, CS=MCS-5 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4781,6 +4936,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-5): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4841,6 +4997,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-6): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4854,6 +5011,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4864,6 +5022,7 @@ - Sending new block at BSN 2, CS=MCS-6 -- Chunk with length 438 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4874,6 +5033,7 @@ - Sending new block at BSN 3, CS=MCS-6 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4884,6 +5044,7 @@ - Sending new block at BSN 4, CS=MCS-6 -- Chunk with length 290 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4894,6 +5055,7 @@ - Sending new block at BSN 5, CS=MCS-6 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4904,6 +5066,7 @@ - Sending new block at BSN 6, CS=MCS-6 -- Chunk with length 142 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4917,6 +5080,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-6): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4932,6 +5096,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-6): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4993,6 +5158,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-7): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5002,12 +5168,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(7) last_mcs(5) demanded_mcs(7)cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-7 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5022,6 +5189,7 @@ - Sending new block at BSN 3, CS=MCS-7 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5036,6 +5204,7 @@ - Sending new block at BSN 5, CS=MCS-7 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5050,6 +5219,7 @@ - Sending new block at BSN 7, CS=MCS-7 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5064,6 +5234,7 @@ - Sending new block at BSN 9, CS=MCS-7 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 9) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5081,6 +5252,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-7): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5142,6 +5314,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=56 data block (BSN 0, MCS-8): 14 71 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5152,12 +5325,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(8) demanded_mcs(8) cs_trans(8) +- initial_cs_dl(8) last_mcs(8) demanded_mcs(8)cs_trans(8) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-8 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5172,6 +5346,7 @@ - Sending new block at BSN 3, CS=MCS-8 -- Chunk with length 376 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5186,6 +5361,7 @@ - Sending new block at BSN 5, CS=MCS-8 -- Chunk with length 240 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5200,6 +5376,7 @@ - Sending new block at BSN 7, CS=MCS-8 -- Chunk with length 104 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5217,6 +5394,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=30 data block (BSN 8, MCS-8): 48 3d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5279,6 +5457,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-9): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5288,12 +5467,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(9) last_mcs(6) demanded_mcs(9)cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-9 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5308,6 +5488,7 @@ - Sending new block at BSN 3, CS=MCS-9 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5322,6 +5503,7 @@ - Sending new block at BSN 5, CS=MCS-9 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5339,6 +5521,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-9): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5356,6 +5539,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-9): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5402,11 +5586,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(6)cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5450,11 +5636,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 96 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(1) demanded_mcs(1) cs_trans(1) +- initial_cs_dl(1) last_mcs(1) demanded_mcs(1)cs_trans(1) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 98 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5498,11 +5686,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-2): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 92 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(2) demanded_mcs(2) cs_trans(2) +- initial_cs_dl(2) last_mcs(2) demanded_mcs(2)cs_trans(2) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 94 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5546,6 +5736,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5557,6 +5748,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-5): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5564,10 +5756,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-5): 0f 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7)cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7)cs_trans(7) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-7): 07 00 00 02 c0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 @@ -5612,6 +5805,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5623,6 +5817,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-6): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5630,10 +5825,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-6): 0f 40 00 00 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9)cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9)cs_trans(9) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-9): 07 00 00 02 28 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 @@ -5686,6 +5882,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-7): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5694,13 +5891,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-7): 0f 00 00 02 a0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5)cs_trans(5) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5)cs_trans(5) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-5): 07 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5752,6 +5951,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-9): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5760,13 +5960,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-9): 0f 00 00 02 00 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6)cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6)cs_trans(6) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-6): 07 40 00 02 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5780,3 +5982,233 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-5 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(2)cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 d2 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(2) demanded_mcs(2)cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 f2 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-4 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (44) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-4): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-4): 07 00 00 80 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(4) demanded_mcs(1)cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 d6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(1) demanded_mcs(1)cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 f6 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(6)cs_trans(6) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 2 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..c38417d 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,9 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_egprs_spb_dl === +Testing retx for MCS 6 to reseg_mcs 3 +Testing retx for MCS 5 to reseg_mcs 2 +Testing retx for MCS 4 to reseg_mcs 1 +Testing retx for MCS 6 to reseg_mcs 3 +=== end test_tbf_egprs_spb_dl === -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 4 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Tue Aug 9 07:11:08 2016 From: gerrit-no-reply at lists.osmocom.org (pravin) Date: Tue, 9 Aug 2016 07:11:08 +0000 Subject: osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Patch Set 9: (2 comments) https://gerrit.osmocom.org/#/c/416/8/src/egprs_rlc_compression.cpp File src/egprs_rlc_compression.cpp: Line 14: void *tall_tree_ctx; > Every allocation by talloc is a talloc context, no need to create an artifi This context is under root context tall_pcu_ctx (Similar to tall_ms_ctx defined in gprs_ms.cpp) Line 22: new_node = talloc(tall_tree_ctx, Node); > pass the parent or root as talloc context and use that and use that.. use t tall_tree_ctx is the parent for all new nodes. I will use talloc_zero instead of talloc. -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 9 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: pravin Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 9 09:16:51 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 9 Aug 2016 09:16:51 +0000 Subject: [PATCH] openbsc[master]: gsm_pchan2chan_nr: disable a chan_nr assert, to not break oc... Message-ID: Review at https://gerrit.osmocom.org/665 gsm_pchan2chan_nr: disable a chan_nr assert, to not break octphy In https://gerrit.osmocom.org/589 , msuraev reports an assertion on octphy. So disable this recently added assertion until we clarify the invocation in question. Change-Id: I05253343d5bcc7b319444376098dc8561dd83944 --- M openbsc/src/libcommon/gsm_data_shared.c 1 file changed, 6 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/65/665/1 diff --git a/openbsc/src/libcommon/gsm_data_shared.c b/openbsc/src/libcommon/gsm_data_shared.c index 8d99ea4..7c6b3e4 100644 --- a/openbsc/src/libcommon/gsm_data_shared.c +++ b/openbsc/src/libcommon/gsm_data_shared.c @@ -592,7 +592,13 @@ break; default: case GSM_PCHAN_CCCH: + /* + * FIXME: On octphy, we hit this assertion (see Max's comment + * at https://gerrit.osmocom.org/589 ); disabled until this is + * clarified: OSMO_ASSERT(lchan_nr == 0); + */ +#warning "fix caller that passes lchan_nr != 0" cbits = 0x10; break; } -- To view, visit https://gerrit.osmocom.org/665 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I05253343d5bcc7b319444376098dc8561dd83944 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Tue Aug 9 09:16:51 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 9 Aug 2016 09:16:51 +0000 Subject: [PATCH] openbsc[master]: gsm_pchan2chan_nr(): fix uninitialized cbits Message-ID: Review at https://gerrit.osmocom.org/666 gsm_pchan2chan_nr(): fix uninitialized cbits Commit ec1b5a0e9e2b6549e0ede48e803095e569997355 introduced an unset cbits value for the 'special hack for BCCH', where I break out of the switch without setting cbits. Fix that. Also remove the comment part that says 'return 0', because I don't return 0. Change-Id: If69f6b1f6208138d5b91bac51ffd78dab95245e5 --- M openbsc/src/libcommon/gsm_data_shared.c 1 file changed, 5 insertions(+), 6 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/66/666/1 diff --git a/openbsc/src/libcommon/gsm_data_shared.c b/openbsc/src/libcommon/gsm_data_shared.c index 7c6b3e4..0a38528 100644 --- a/openbsc/src/libcommon/gsm_data_shared.c +++ b/openbsc/src/libcommon/gsm_data_shared.c @@ -573,14 +573,13 @@ case GSM_PCHAN_CCCH_SDCCH4_CBCH: /* * As a special hack for BCCH, lchan_nr == 4 may be passed - * here. This should never be sent in an RSL message, so just - * return 0. See osmo-bts-xxx/oml.c:opstart_compl(). + * here. This should never be sent in an RSL message. + * See osmo-bts-xxx/oml.c:opstart_compl(). */ - if (lchan_nr == 4) { + if (lchan_nr == 4) chan_nr = 0; - break; - } - OSMO_ASSERT(lchan_nr < 4); + else + OSMO_ASSERT(lchan_nr < 4); cbits = 0x04; cbits += lchan_nr; break; -- To view, visit https://gerrit.osmocom.org/666 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: If69f6b1f6208138d5b91bac51ffd78dab95245e5 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Tue Aug 9 09:18:01 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Tue, 9 Aug 2016 09:18:01 +0000 Subject: openbsc[master]: gsm_pchan2chan_nr: disable a chan_nr assert, to not break oc... In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+1 -- To view, visit https://gerrit.osmocom.org/665 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I05253343d5bcc7b319444376098dc8561dd83944 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Max Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 9 09:53:23 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Tue, 9 Aug 2016 09:53:23 +0000 Subject: [PATCH] openbsc[master]: V42BIS integration In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/644 to look at the new patch set (#13). V42BIS integration The previously committed SPANDSP v42bis implementation has been edited to function outside the SPANDSP library. Debug printf statements were changed into DEBUGP statements. Als removed the assembely code in top_bit(). Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d --- M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/debug.h M openbsc/include/openbsc/v42bis.h R openbsc/include/openbsc/v42bis_private.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/v42bis.c 6 files changed, 22 insertions(+), 23 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/44/644/13 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index e159db5..e404b17 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,8 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h gprs_sndcp_xid.h \ - gprs_sndcp_comp_entity.h gprs_sndcp_hdrcomp.h + gprs_sndcp_comp_entity.h gprs_sndcp_hdrcomp.h v42bis.h \ + v42bis_private.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 90ddca5..ca3d4ad 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -37,6 +37,7 @@ DGTPHUB, DRANAP, DSUA, + DV42BIS, Debug_LastEntry, }; diff --git a/openbsc/include/openbsc/v42bis.h b/openbsc/include/openbsc/v42bis.h index f13e5c5..e7592e8 100644 --- a/openbsc/include/openbsc/v42bis.h +++ b/openbsc/include/openbsc/v42bis.h @@ -36,6 +36,8 @@ #if !defined(_SPANDSP_V42BIS_H_) #define _SPANDSP_V42BIS_H_ +#define SPAN_DECLARE(x) x + #define V42BIS_MAX_BITS 12 #define V42BIS_MAX_CODEWORDS 4096 /* 2^V42BIS_MAX_BITS */ #define V42BIS_TABLE_SIZE 5021 /* This should be a prime >(2^V42BIS_MAX_BITS) */ diff --git a/openbsc/include/openbsc/private_v42bis.h b/openbsc/include/openbsc/v42bis_private.h similarity index 100% rename from openbsc/include/openbsc/private_v42bis.h rename to openbsc/include/openbsc/v42bis_private.h diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 3d6c82a..2c03a45 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -22,7 +22,7 @@ osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \ slhc.c gprs_sndcp_xid.c gprs_sndcp_comp_entity.c \ - gprs_sndcp_hdrcomp.c \ + gprs_sndcp_hdrcomp.c v42bis.c \ sgsn_main.c sgsn_vty.c sgsn_libgtp.c \ gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c \ gprs_llc_xid.c crc24.c \ diff --git a/openbsc/src/gprs/v42bis.c b/openbsc/src/gprs/v42bis.c index 6d38916..fd88b53 100644 --- a/openbsc/src/gprs/v42bis.c +++ b/openbsc/src/gprs/v42bis.c @@ -31,9 +31,8 @@ /*! \file */ -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif +#define FALSE 0 +#define TRUE 1 #include #include @@ -44,13 +43,9 @@ #include #include -#include "spandsp/telephony.h" -#include "spandsp/logging.h" -#include "spandsp/bit_operations.h" -#include "spandsp/v42bis.h" +#include +#include -#include "spandsp/private/logging.h" -#include "spandsp/private/v42bis.h" /* Fixed parameters from the spec. */ #define V42BIS_N3 8 /* Character size (bits) */ @@ -310,7 +305,7 @@ { if (ss->transparent) { - printf("Going compressed\n"); + DEBUGP(DV42BIS,"Going compressed\n"); /* 7.8.1 Transition to compressed mode */ /* Switch out of transparent now, between codes. We need to send the octet which did not match, just before switching. */ @@ -332,7 +327,7 @@ { if (!ss->transparent) { - printf("Going transparent\n"); + DEBUGP(DV42BIS,"Going transparent\n"); /* 7.8.2 Transition to transparent mode */ /* Switch into transparent now, between codes, and the unmatched octet should go out in transparent mode, just below */ @@ -401,7 +396,7 @@ { if (s->compress.dict[i].parent_code != 0xFFFF) { - printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); + DEBUGP(DV42BIS,"Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); } } return 0; @@ -454,13 +449,13 @@ ss->escaped = FALSE; if (code == V42BIS_ECM) { - printf("Hit V42BIS_ECM\n"); + DEBUGP(DV42BIS,"Hit V42BIS_ECM\n"); ss->transparent = FALSE; code_len = ss->v42bis_parm_c2; } else if (code == V42BIS_EID) { - printf("Hit V42BIS_EID\n"); + DEBUGP(DV42BIS,"Hit V42BIS_EID\n"); ss->output_buf[ss->output_octet_count++] = ss->escape_code - 1; if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) { @@ -470,11 +465,11 @@ } else if (code == V42BIS_RESET) { - printf("Hit V42BIS_RESET\n"); + DEBUGP(DV42BIS,"Hit V42BIS_RESET\n"); } else { - printf("Hit V42BIS_???? - %" PRIu32 "\n", code); + DEBUGP(DV42BIS,"Hit V42BIS_???? - %" PRIu32 "\n", code); } } else if (code == ss->escape_code) @@ -500,17 +495,17 @@ switch (new_code) { case V42BIS_ETM: - printf("Hit V42BIS_ETM\n"); + DEBUGP(DV42BIS,"Hit V42BIS_ETM\n"); ss->transparent = TRUE; code_len = 8; break; case V42BIS_FLUSH: - printf("Hit V42BIS_FLUSH\n"); + DEBUGP(DV42BIS,"Hit V42BIS_FLUSH\n"); v42bis_decompress_flush(s); break; case V42BIS_STEPUP: /* We need to increase the codeword size */ - printf("Hit V42BIS_STEPUP\n"); + DEBUGP(DV42BIS,"Hit V42BIS_STEPUP\n"); if (ss->v42bis_parm_c3 >= s->v42bis_parm_n2) { /* Invalid condition */ @@ -547,7 +542,7 @@ /* Trace back through the octets which form the string, and output them. */ while (code >= V42BIS_N5) { -if (code > 4095) {printf("Code is 0x%" PRIu32 "\n", code); exit(2);} +if (code > 4095) {DEBUGP(DV42BIS,"Code is 0x%" PRIu32 "\n", code); exit(2);} *string-- = ss->dict[code].node_octet; code = ss->dict[code].parent_code; } @@ -631,7 +626,7 @@ { if (s->decompress.dict[i].parent_code != 0xFFFF) { - printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); + DEBUGP(DV42BIS,"Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); } } return 0; -- To view, visit https://gerrit.osmocom.org/644 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d Gerrit-PatchSet: 13 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Tue Aug 9 09:53:23 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Tue, 9 Aug 2016 09:53:23 +0000 Subject: [PATCH] openbsc[master]: XID related modifications in LLC In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/652 to look at the new patch set (#9). XID related modifications in LLC With this commit the already existing XID mechanism has been modified to suit the needs for the upcomming SNDCP-XID patches. The SNDCP-XID related calls are currently disabled since the necessary patches for gprs_sndcp.c are not yet pushed. This commit should not break anything since it does not alter the current behaviour (incoming XID is still just echoed, on GMM-Reset a basic XID message is still echoed) Change-Id: I65b9d625e72d3d61c99abdc7041773701d694d52 --- M openbsc/include/openbsc/gprs_llc.h M openbsc/src/gprs/gprs_llc.c M openbsc/tests/sgsn/Makefile.am 3 files changed, 347 insertions(+), 62 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/52/652/9 diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h index 39d17f4..8b93784 100644 --- a/openbsc/include/openbsc/gprs_llc.h +++ b/openbsc/include/openbsc/gprs_llc.h @@ -4,6 +4,7 @@ #include #include #include +#include /* Section 4.7 LLC Layer Structure */ enum gprs_llc_sapi { @@ -148,10 +149,8 @@ /* Lists holding the compression entities */ struct comp_ent { - /* - * In this two list_heads we will store the data and protocol - * compression entities, together with their compression states - */ + /* In this two list_heads we will store the data and protocol + * compression entities, together with their compression states */ struct llist_head proto; struct llist_head data; }; @@ -235,6 +234,10 @@ int gprs_llgmm_reset_oldmsg(struct msgb* oldmsg, uint8_t sapi, struct gprs_llc_llme *llme); +/* Set of LL-XID negotiation (See also: TS 101 351, Section 7.2.2.4) */ +int gprs_ll_xid_req(struct gprs_llc_lle *lle, + struct gprs_llc_xid_field *l3_xid_field); + /* 04.64 Chapter 7.2.1.1 LLGMM-ASSIGN */ int gprs_llgmm_assign(struct gprs_llc_llme *llme, uint32_t old_tlli, uint32_t new_tlli); diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c index 7724ebb..9e85f63 100644 --- a/openbsc/src/gprs/gprs_llc.c +++ b/openbsc/src/gprs/gprs_llc.c @@ -38,8 +38,312 @@ #include #include #include +#include +#include +#include + + +/* FIXME: Remove this switch as soon as the XID integration in + * gprs_sndcp.c h is done */ +#define WITH_SNDCP_XID 1 static struct gprs_llc_llme *llme_alloc(uint32_t tlli); +static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg, + int command); +static int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi, + int command, enum gprs_llc_u_cmd u_cmd, int pf_bit); + +/* BEGIN XID RELATED */ + +/* Generate XID message */ +static int gprs_llc_generate_xid(uint8_t *bytes, int bytes_len, + struct gprs_llc_xid_field *l3_xid_field, + struct gprs_llc_llme *llme) +{ + /* Note: Called by gprs_ll_xid_req() */ + + LLIST_HEAD(xid_fields); + + struct gprs_llc_xid_field xid_version; + struct gprs_llc_xid_field xid_n201u; + struct gprs_llc_xid_field xid_n201i; + + xid_version.type = GPRS_LLC_XID_T_VERSION; + xid_version.data = (uint8_t *) "\x00"; + xid_version.data_len = 1; + + xid_n201u.type = GPRS_LLC_XID_T_N201_U; + xid_n201u.data = (uint8_t *) "\x05\xf0"; + xid_n201u.data_len = 2; + + xid_n201i.type = GPRS_LLC_XID_T_N201_I; + xid_n201i.data = (uint8_t *) "\x05\xf0"; + xid_n201i.data_len = 2; + + /* Add layer 3 XID field (if present) */ + if (l3_xid_field) { + /* Enforce layer 3 XID type (just to be sure) */ + l3_xid_field->type = GPRS_LLC_XID_T_L3_PAR; + + /* Add Layer 3 XID field to the list */ + llist_add(&l3_xid_field->list, &xid_fields); + } + + /* Add locally managed XID Fields */ + llist_add(&xid_n201i.list, &xid_fields); + llist_add(&xid_n201u.list, &xid_fields); + llist_add(&xid_version.list, &xid_fields); + + gprs_llc_copy_xid(&llme->xid, &xid_fields); + + return gprs_llc_compile_xid(&xid_fields, bytes, bytes_len); +} + +/* Generate XID message that will cause the GMM to reset */ +static int gprs_llc_generate_xid_for_gmm_reset(uint8_t *bytes, + int bytes_len, uint32_t iov_ui, + struct gprs_llc_llme *llme) +{ + /* Called by gprs_llgmm_reset() and + * gprs_llgmm_reset_oldmsg() */ + + LLIST_HEAD(xid_fields); + + struct gprs_llc_xid_field xid_reset; + struct gprs_llc_xid_field xid_iovui; + + /* First XID component must be RESET */ + xid_reset.type = GPRS_LLC_XID_T_RESET; + xid_reset.data = NULL; + xid_reset.data_len = 0; + + /* Add new IOV-UI */ + xid_iovui.type = GPRS_LLC_XID_T_IOV_UI; + xid_iovui.data = (uint8_t *) & iov_ui; + xid_iovui.data_len = 4; + + /* Add locally managed XID Fields */ + llist_add(&xid_iovui.list, &xid_fields); + llist_add(&xid_reset.list, &xid_fields); + + gprs_llc_copy_xid(&llme->xid, &xid_fields); + + return gprs_llc_compile_xid(&xid_fields, bytes, bytes_len); +} + +/* Process an incoming XID confirmation */ +static int gprs_llc_process_xid_conf(uint8_t *bytes, int bytes_len, + struct gprs_llc_lle *lle) +{ + /* Note: This function handles the response of a network originated + * XID-Request. There XID messages reflected by the phone are analyzed + * and processed here. The caller is called by rx_llc_xid(). */ + + int rc; + LLIST_HEAD(xid_fields); + struct gprs_llc_xid_field *xid_field; + struct gprs_llc_xid_field *xid_field_request; + struct gprs_llc_xid_field *xid_field_request_l3 = NULL; + + /* Pick layer3 XID from the XID request we have sent last */ + llist_for_each_entry(xid_field_request, &lle->llme->xid, list) { + if (xid_field_request->type == GPRS_LLC_XID_T_L3_PAR) + xid_field_request_l3 = xid_field_request; + } + + /* Parse and analyze XID-Response */ + rc = gprs_llc_parse_xid(&xid_fields, bytes, bytes_len); + if (rc == 0) { + gprs_llc_dump_xid_fields(&xid_fields, LOGL_DEBUG); + + llist_for_each_entry(xid_field, &xid_fields, list) { + + /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { +#if WITH_SNDCP_XID == 1 + sndcp_sn_xid_conf(xid_field, + xid_field_request_l3, + lle); +#endif + } + + /* Process LLC-XID fields: */ + else { + + /* FIXME: Do something more useful with the + * echoed XID-Information. Currently we + * just ignore the response completely and + * by doing so we blindly accept any changes + * the MS might have done to the our XID + * inquiry. There is a remainig risk of + * malfunction! */ + LOGP(DLLC, LOGL_NOTICE, + "Ignoring XID-Field: XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + xid_field->data); + + } + } + } + + /* Flush pending XID fields */ + gprs_llc_free_xid(&lle->llme->xid); + + return 0; +} + + +/* Process an incoming XID indication and generate an appropiate response */ +static int gprs_llc_process_xid_ind(uint8_t *bytes_request, + int bytes_request_len, + uint8_t *bytes_response, + int bytes_response_maxlen, + struct gprs_llc_lle *lle) +{ + /* Note: This function computes the response that is sent back to the + * phone when a phone originated XID is received. The function is + * called by rx_llc_xid() */ + + int rc; + LLIST_HEAD(xid_fields); + LLIST_HEAD(xid_fields_response); + + struct gprs_llc_xid_field *xid_field; + struct gprs_llc_xid_field *xid_field_response; + + /* Flush eventually pending XID fields */ + gprs_llc_free_xid(&lle->llme->xid); + + /* Parse and analyze XID-Request */ + rc = gprs_llc_parse_xid(&xid_fields, bytes_request, + bytes_request_len); + if (rc == 0) { + gprs_llc_dump_xid_fields(&xid_fields, LOGL_DEBUG); + + llist_for_each_entry(xid_field, &xid_fields, list) { + /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { +#if WITH_SNDCP_XID == 1 + xid_field_response = + talloc_zero(NULL, + struct gprs_llc_xid_field); + rc = sndcp_sn_xid_ind(xid_field, + xid_field_response, + lle); + if (rc == 0) + llist_add(&xid_field_response-> + list, + &xid_fields_response); + else + talloc_free(xid_field_response); +#endif + } + + /* Process LLC-XID fields: */ + else { + /* FIXME: Check the incoming XID parameters for + * for validity. Currently we just blindly + * accept all XID fields by just echoing them. + * There is a remaining risk of malfunction + * when a phone submits values which defer from + * the default! */ + LOGP(DLLC, LOGL_NOTICE, + "Echoing XID-Field: XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + osmo_hexdump_nospc(xid_field->data, + xid_field-> + data_len)); + xid_field_response = + gprs_llc_duplicate_xid_field + (xid_field); + llist_add(&xid_field_response->list, + &xid_fields_response); + } + } + + rc = gprs_llc_compile_xid(&xid_fields_response, + bytes_response, + bytes_response_maxlen); + gprs_llc_free_xid(&xid_fields_response); + } + gprs_llc_free_xid(&xid_fields); + + return rc; +} + +/* Dispatch XID indications and responses comming from the Phone */ +static void rx_llc_xid(struct gprs_llc_lle *lle, + struct gprs_llc_hdr_parsed *gph) +{ + uint8_t response[1024]; + int response_len; + + /* FIXME: 8.5.3.3: check if XID is invalid */ + if (gph->is_cmd) { + LOGP(DLLC, LOGL_NOTICE, + "Received XID indication from phone.\n"); + + struct msgb *resp; + uint8_t *xid; + resp = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + + response_len = + gprs_llc_process_xid_ind(gph->data, gph->data_len, + response, sizeof(response), + lle); + xid = msgb_put(resp, response_len); + memcpy(xid, response, response_len); + + gprs_llc_tx_xid(lle, resp, 0); + } else { + LOGP(DLLC, LOGL_NOTICE, + "Received XID confirmation from phone.\n"); + gprs_llc_process_xid_conf(gph->data, gph->data_len, lle); + /* FIXME: if we had sent a XID reset, send + * LLGMM-RESET.conf to GMM */ + } +} + + +/* Set of LL-XID negotiation (See also: TS 101 351, Section 7.2.2.4) */ +int gprs_ll_xid_req(struct gprs_llc_lle *lle, + struct gprs_llc_xid_field *l3_xid_field) +{ + /* Note: This functions is calle from gprs_sndcp.c */ + + uint8_t xid_bytes[1024];; + int xid_bytes_len; + uint8_t *xid; + struct msgb *msg; + + /* Generate XID */ + xid_bytes_len = + gprs_llc_generate_xid(xid_bytes, sizeof(xid_bytes), + l3_xid_field, lle->llme); + + + /* Only perform XID sending if the XID message contains something */ + if (xid_bytes_len > 0) { + /* Transmit XID bytes */ + msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); + LOGP(DLLC, LOGL_NOTICE, + "Sending XID request to phone...\n"); + gprs_llc_tx_xid(lle, msg, 1); + } else { + LOGP(DLLC, LOGL_ERROR, + "XID-Message generation failed, XID not sent!\n"); + return -EINVAL; + } + + return 0; +} + +/* END XID RELATED */ + + + /* Entry function from upper level (LLC), asking us to transmit a BSSGP PDU * to a remote MS (identified by TLLI) at a BTS identified by its BVCI and NSEI */ @@ -51,7 +355,7 @@ memset(&dup, 0, sizeof(dup)); /* before we have received some identity from the MS, we might * not yet have a MMC context (e.g. XID negotiation of primarly - * LLC connection fro GMM sapi). */ + * LLC connection from GMM sapi). */ if (mmctx) { dup.imsi = mmctx->imsi; dup.drx_parms = mmctx->drx_parms; @@ -246,11 +550,18 @@ llist_add(&llme->list, &gprs_llc_llmes); + INIT_LLIST_HEAD(&llme->comp.proto); + INIT_LLIST_HEAD(&llme->comp.data); + INIT_LLIST_HEAD(&llme->xid); + return llme; } static void llme_free(struct gprs_llc_llme *llme) { + gprs_sndcp_comp_entities_free(&llme->comp.proto); + gprs_sndcp_comp_entities_free(&llme->comp.data); + gprs_llc_free_xid(&llme->xid); llist_del(&llme->list); talloc_free(llme); } @@ -464,54 +775,6 @@ /* Send BSSGP-DL-UNITDATA.req */ return _bssgp_tx_dl_ud(msg, mmctx); -} - -/* According to 6.4.1.6 / Figure 11 */ -static int msgb_put_xid_par(struct msgb *msg, uint8_t type, uint8_t length, uint8_t *data) -{ - uint8_t header_len = 1; - uint8_t *cur; - - /* type is a 5-bit field... */ - if (type > 0x1f) - return -EINVAL; - - if (length > 3) - header_len = 2; - - cur = msgb_put(msg, length + header_len); - - /* build the header without or with XL bit */ - if (length <= 3) { - *cur++ = (type << 2) | (length & 3); - } else { - *cur++ = 0x80 | (type << 2) | (length >> 6); - *cur++ = (length << 2); - } - - /* copy over the payload of the parameter*/ - memcpy(cur, data, length); - - return length + header_len; -} - -static void rx_llc_xid(struct gprs_llc_lle *lle, - struct gprs_llc_hdr_parsed *gph) -{ - /* FIXME: 8.5.3.3: check if XID is invalid */ - if (gph->is_cmd) { - /* FIXME: implement XID negotiation using SNDCP */ - struct msgb *resp; - uint8_t *xid; - resp = msgb_alloc_headroom(4096, 1024, "LLC_XID"); - xid = msgb_put(resp, gph->data_len); - memcpy(xid, gph->data, gph->data_len); - gprs_llc_tx_xid(lle, resp, 0); - } else { - /* FIXME: if we had sent a XID reset, send - * LLGMM-RESET.conf to GMM */ - /* FIXME: implement XID negotiation using SNDCP */ - } } static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph, @@ -784,17 +1047,24 @@ { struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); struct gprs_llc_lle *lle = &llme->lle[1]; + uint8_t xid_bytes[1024]; + int xid_bytes_len; + uint8_t *xid; + LOGP(DLLC, LOGL_NOTICE, "LLGM Reset\n"); if (RAND_bytes((uint8_t *) &llme->iov_ui, 4) != 1) { LOGP(DLLC, LOGL_NOTICE, "RAND_bytes failed for LLC XID reset, " "falling back to rand()\n"); llme->iov_ui = rand(); } - /* First XID component must be RESET */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL); - /* randomly select new IOV-UI */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &llme->iov_ui); + /* Generate XID message */ + xid_bytes_len = gprs_llc_generate_xid_for_gmm_reset(xid_bytes, + sizeof(xid_bytes),llme->iov_ui,llme); + if(xid_bytes_len < 0) + return -EINVAL; + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); /* Reset some of the LLC parameters. See GSM 04.64, 8.5.3.1 */ lle->vu_recv = 0; @@ -810,17 +1080,24 @@ struct gprs_llc_llme *llme) { struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + uint8_t xid_bytes[1024]; + int xid_bytes_len; + uint8_t *xid; + LOGP(DLLC, LOGL_NOTICE, "LLGM Reset\n"); if (RAND_bytes((uint8_t *) &llme->iov_ui, 4) != 1) { LOGP(DLLC, LOGL_NOTICE, "RAND_bytes failed for LLC XID reset, " "falling back to rand()\n"); llme->iov_ui = rand(); } - /* First XID component must be RESET */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL); - /* randomly select new IOV-UI */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &llme->iov_ui); + /* Generate XID message */ + xid_bytes_len = gprs_llc_generate_xid_for_gmm_reset(xid_bytes, + sizeof(xid_bytes),llme->iov_ui,llme); + if(xid_bytes_len < 0) + return -EINVAL; + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); /* FIXME: Start T200, wait for XID response */ diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index b6036c7..3b34452 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -30,6 +30,11 @@ $(top_builddir)/src/gprs/gprs_gb_parse.o \ $(top_builddir)/src/gprs/oap.o \ $(top_builddir)/src/gprs/oap_messages.o \ + $(top_builddir)/src/gprs/gprs_llc_xid.o \ + $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ + $(top_builddir)/src/gprs/gprs_sndcp_comp_entity.o \ + $(top_builddir)/src/gprs/gprs_sndcp_hdrcomp.o \ + $(top_builddir)/src/gprs/slhc.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ @@ -37,5 +42,5 @@ $(LIBOSMOGB_LIBS) \ $(LIBCARES_LIBS) \ $(LIBCRYPTO_LIBS) \ - -lgtp -lrt + -lgtp -lrt -lm -- To view, visit https://gerrit.osmocom.org/652 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I65b9d625e72d3d61c99abdc7041773701d694d52 Gerrit-PatchSet: 9 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Tue Aug 9 10:05:44 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Tue, 9 Aug 2016 10:05:44 +0000 Subject: openbsc[master]: gsm_pchan2chan_nr: disable a chan_nr assert, to not break oc... In-Reply-To: References: Message-ID: Patch Set 1: Note: this also fixes litecell which is currently broken. -- To view, visit https://gerrit.osmocom.org/665 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I05253343d5bcc7b319444376098dc8561dd83944 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Max Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 9 10:23:42 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Tue, 9 Aug 2016 10:23:42 +0000 Subject: openbsc[master]: gsm_pchan2chan_nr: disable a chan_nr assert, to not break oc... In-Reply-To: References: Message-ID: Patch Set 1: (1 comment) https://gerrit.osmocom.org/#/c/665/1/openbsc/src/libcommon/gsm_data_shared.c File openbsc/src/libcommon/gsm_data_shared.c: Line 599: OSMO_ASSERT(lchan_nr == 0); either remove it completely or check for 0 || 4. As far as I remember, 0 and 4 are the only values used? Alternatively, put an "#ifdef ROLE_BSC" around it, in case the lchan_nr!=0 is only in the BTS? -- To view, visit https://gerrit.osmocom.org/665 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I05253343d5bcc7b319444376098dc8561dd83944 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Max Gerrit-Reviewer: neels_test_account Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 9 10:24:30 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 9 Aug 2016 10:24:30 +0000 Subject: osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Patch Set 9: Code-Review-1 I notice that your new patch set 9 ignores various comments issued for patch set 8. Do you intend to fix those in a subsequent patch set? -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 9 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: pravin Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 9 10:28:17 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Tue, 9 Aug 2016 10:28:17 +0000 Subject: openbsc[master]: gsm_pchan2chan_nr: disable a chan_nr assert, to not break oc... In-Reply-To: References: Message-ID: Patch Set 1: The failure is triggered on bts side (both octasic and litecell). -- To view, visit https://gerrit.osmocom.org/665 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I05253343d5bcc7b319444376098dc8561dd83944 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Max Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 9 10:40:45 2016 From: gerrit-no-reply at lists.osmocom.org (pravin) Date: Tue, 9 Aug 2016 10:40:45 +0000 Subject: osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Patch Set 9: (1 comment) https://gerrit.osmocom.org/#/c/416/8/tests/tbf/TbfTest.cpp File tests/tbf/TbfTest.cpp: Line 1624: > How many other talloc users do you see that do that? It could be a hint tha I will move the creation of talloc tree context to decode_tree_init function in egprs_rlc_compression.h with a parameter of pcu context from pcu_main.cpp and test file. -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 9 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: pravin Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 9 10:46:56 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 9 Aug 2016 10:46:56 +0000 Subject: openbsc[master]: gsm_pchan2chan_nr: disable a chan_nr assert, to not break oc... In-Reply-To: References: Message-ID: Patch Set 1: (1 comment) https://gerrit.osmocom.org/#/c/665/1/openbsc/src/libcommon/gsm_data_shared.c File openbsc/src/libcommon/gsm_data_shared.c: Line 599: OSMO_ASSERT(lchan_nr == 0); > either remove it completely or check for 0 || 4. As far as I remember, 0 a To fix the regression introduced by this assertion, I'd just drop it for now until we have time to properly check on it. The point is that this needs to be clarified. But ok, I guess I can ROLE_BSC it... -- To view, visit https://gerrit.osmocom.org/665 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I05253343d5bcc7b319444376098dc8561dd83944 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 9 10:51:04 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 9 Aug 2016 10:51:04 +0000 Subject: [PATCH] openbsc[master]: gsm_pchan2chan_nr: disable a chan_nr assert in BTS, to not b... In-Reply-To: References: Message-ID: Hello Max, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/665 to look at the new patch set (#2). gsm_pchan2chan_nr: disable a chan_nr assert in BTS, to not break octphy In https://gerrit.osmocom.org/589 , msuraev reports an assertion on octphy. So disable this recently added assertion until we clarify the invocation in question. Change-Id: I05253343d5bcc7b319444376098dc8561dd83944 --- M openbsc/src/libcommon/gsm_data_shared.c 1 file changed, 9 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/65/665/2 diff --git a/openbsc/src/libcommon/gsm_data_shared.c b/openbsc/src/libcommon/gsm_data_shared.c index 8d99ea4..ad8ee39 100644 --- a/openbsc/src/libcommon/gsm_data_shared.c +++ b/openbsc/src/libcommon/gsm_data_shared.c @@ -592,7 +592,16 @@ break; default: case GSM_PCHAN_CCCH: +#ifdef ROLE_BSC OSMO_ASSERT(lchan_nr == 0); +#else + /* + * FIXME: On octphy, we hit above assertion (see Max's comment + * at https://gerrit.osmocom.org/589 ); disabled for BTS until + * this is clarified; remove the #ifdef when it is fixed. + */ +#warning "fix caller that passes lchan_nr != 0" +#endif cbits = 0x10; break; } -- To view, visit https://gerrit.osmocom.org/665 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I05253343d5bcc7b319444376098dc8561dd83944 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Tue Aug 9 10:51:16 2016 From: gerrit-no-reply at lists.osmocom.org (pravin) Date: Tue, 9 Aug 2016 10:51:16 +0000 Subject: osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Patch Set 8: (1 comment) https://gerrit.osmocom.org/#/c/416/8/src/pcu_main.cpp File src/pcu_main.cpp: Line 172: tall_tree_ctx = talloc_named_const(tall_pcu_ctx, 0, "decode-tree context"); > We have taken the reference of MS object creation for hierarchical talloc u As mentioned in response to comment for line:1624 in tbfTest.cpp, I will move creation of tree context tall_tree_ctx to function decode_tree_init in egprs_rlc_compression.h . -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 8 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: pravin Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 9 10:52:04 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 9 Aug 2016 10:52:04 +0000 Subject: [PATCH] openbsc[master]: gsm_pchan2chan_nr: disable a chan_nr assert in BTS, to not b... In-Reply-To: References: Message-ID: Hello Max, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/665 to look at the new patch set (#3). gsm_pchan2chan_nr: disable a chan_nr assert in BTS, to not break octphy In https://gerrit.osmocom.org/589 , msuraev reports an assertion on octphy. So disable this recently added assertion until we clarify the invocation in question. Change-Id: I05253343d5bcc7b319444376098dc8561dd83944 --- M openbsc/src/libcommon/gsm_data_shared.c 1 file changed, 10 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/65/665/3 diff --git a/openbsc/src/libcommon/gsm_data_shared.c b/openbsc/src/libcommon/gsm_data_shared.c index 8d99ea4..529f72c 100644 --- a/openbsc/src/libcommon/gsm_data_shared.c +++ b/openbsc/src/libcommon/gsm_data_shared.c @@ -592,7 +592,17 @@ break; default: case GSM_PCHAN_CCCH: +#ifdef ROLE_BSC OSMO_ASSERT(lchan_nr == 0); +#else + /* + * FIXME: On octphy and litecell, we hit above assertion (see + * Max's comment at https://gerrit.osmocom.org/589 ); disabled + * for BTS until this is clarified; remove the #ifdef when it + * is fixed. + */ +#warning "fix caller that passes lchan_nr != 0" +#endif cbits = 0x10; break; } -- To view, visit https://gerrit.osmocom.org/665 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I05253343d5bcc7b319444376098dc8561dd83944 Gerrit-PatchSet: 3 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Tue Aug 9 10:58:38 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Tue, 9 Aug 2016 10:58:38 +0000 Subject: openbsc[master]: gsm_pchan2chan_nr: disable a chan_nr assert in BTS, to not b... In-Reply-To: References: Message-ID: Patch Set 3: Code-Review+1 Verified+1 Verified with litecell. -- To view, visit https://gerrit.osmocom.org/665 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I05253343d5bcc7b319444376098dc8561dd83944 Gerrit-PatchSet: 3 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 9 11:00:14 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 9 Aug 2016 11:00:14 +0000 Subject: osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Patch Set 9: (8 comments) I have various cosmetic comments, as inlined. There would be plenty more, but stopping for now. https://gerrit.osmocom.org/#/c/416/9/src/decoding.cpp File src/decoding.cpp: Line 655: int i, rc; why move this var declaration? I prefer each var on a separate line, and rather don't mix cosmetic changes with "real" ones. Line 710: * return what we have so far and assume the extraneous whitespace change which also breaks proper indenting Line 714: LOGP(DRLCMACDL, LOGL_DEBUG, another extraneous whitespace change: don't drop the blank line above the LOGP(). https://gerrit.osmocom.org/#/c/416/9/src/egprs_rlc_compression.cpp File src/egprs_rlc_compression.cpp: Line 34: int idx; /* interate index of the code word table */ I don't think you need to comment on these variable names, they are very obvious as they are. (btw, it's spelled 'iterator' with o) https://gerrit.osmocom.org/#/c/416/9/tests/tbf/TbfTest.cpp File tests/tbf/TbfTest.cpp: Line 44: #define NUMBER_OF_TEST_CASE 9 nitpick: add S for NUMBER_OF_TEST_CASES, or actually rather call it TBF_TEST_CASE_COUNT? Line 61: {0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xf8, 0x00, I would appreciate line breaks and indenting for readability: add a new-line after each '}' (possibly also after some '{') and indent to show the level depths; heed <80 chars width. Line 64: {(int8_t)40, (uint8_t)1, {0x53, 0x06, 0xc5, 0x40, 0x6d}, {0xff, 0xff, 0xff, 0xff, 0xff, are these casts (int8_t) and (uint8_t) really necessary? Line 125: * and to verify the result with expected result (fix whitespace) -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 9 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: pravin Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 9 11:35:44 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Tue, 9 Aug 2016 11:35:44 +0000 Subject: openbsc[master]: Add web proxy for control interface In-Reply-To: References: Message-ID: Patch Set 2: Code-Review-1 Will follow-up with fixes. -- To view, visit https://gerrit.osmocom.org/659 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I87d40c80061f8b3d02d656ab8cadabbfb871b461 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 9 12:01:13 2016 From: gerrit-no-reply at lists.osmocom.org (pravin) Date: Tue, 9 Aug 2016 12:01:13 +0000 Subject: osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Patch Set 9: > I notice that your new patch set 9 ignores various comments issued > for patch set 8. Do you intend to fix those in a subsequent patch > set? Because of the sync issue in mail I couldn't see this comment before submitting patch set 9. So, I will try to address all the comments in my next patch set. -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 9 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: pravin Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 9 15:48:16 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 9 Aug 2016 15:48:16 +0000 Subject: [PATCH] openbsc[master]: dyn TS: bts_chan_load: use correct nr of subslots for dyn ts Message-ID: Review at https://gerrit.osmocom.org/667 dyn TS: bts_chan_load: use correct nr of subslots for dyn ts For TCH/F_TCH/H_PDCH dynamic timeslots, the ts->pchan does not lead to a meaningful value from the subslots_per_pchan[] array. Use the ts_subslots() function instead, which checks for dyn pchan. Change-Id: I659acebca82dfb3e305433471be64e9d27439af8 --- M openbsc/src/libbsc/chan_alloc.c 1 file changed, 3 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/67/667/1 diff --git a/openbsc/src/libbsc/chan_alloc.c b/openbsc/src/libbsc/chan_alloc.c index c3a7e0f..d9808f4 100644 --- a/openbsc/src/libbsc/chan_alloc.c +++ b/openbsc/src/libbsc/chan_alloc.c @@ -555,12 +555,14 @@ struct gsm_bts_trx_ts *ts = &trx->ts[i]; struct load_counter *pl = &cl->pchan[ts->pchan]; int j; + int subslots; /* skip administratively deactivated timeslots */ if (!nm_is_running(&ts->mo.nm_state)) continue; - for (j = 0; j < subslots_per_pchan[ts->pchan]; j++) { + subslots = ts_subslots(ts); + for (j = 0; j < subslots; j++) { struct gsm_lchan *lchan = &ts->lchan[j]; pl->total++; -- To view, visit https://gerrit.osmocom.org/667 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I659acebca82dfb3e305433471be64e9d27439af8 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Tue Aug 9 15:48:17 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 9 Aug 2016 15:48:17 +0000 Subject: [PATCH] openbsc[master]: chan_alloc.c: use ts_subslots() instead of subslots_per_pchan[] Message-ID: Review at https://gerrit.osmocom.org/668 chan_alloc.c: use ts_subslots() instead of subslots_per_pchan[] The array will move to gsm_data_shared.c; to prepare, use the function instead. Change-Id: Icbea7dbd78abf6144e5291f531a97f96507d8cbf --- M openbsc/src/libbsc/chan_alloc.c 1 file changed, 2 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/68/668/1 diff --git a/openbsc/src/libbsc/chan_alloc.c b/openbsc/src/libbsc/chan_alloc.c index d9808f4..92a1358 100644 --- a/openbsc/src/libbsc/chan_alloc.c +++ b/openbsc/src/libbsc/chan_alloc.c @@ -170,13 +170,13 @@ /* The requested type matches the dynamic * timeslot's current mode. A channel may still * be available (think TCH/H). */ - check_subslots = subslots_per_pchan[ts->dyn.pchan_is]; + check_subslots = ts_subslots(ts); } else /* Otherwise this slot is not applicable. */ continue; } else { /* Not a dynamic channel, there is only one pchan kind: */ - check_subslots = subslots_per_pchan[pchan]; + check_subslots = ts_subslots(ts); } /* Is a sub-slot still available? */ -- To view, visit https://gerrit.osmocom.org/668 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Icbea7dbd78abf6144e5291f531a97f96507d8cbf Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Tue Aug 9 15:48:17 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 9 Aug 2016 15:48:17 +0000 Subject: [PATCH] openbsc[master]: move ts_sublots() to gsm_data_shared.c, it will be used by o... Message-ID: Review at https://gerrit.osmocom.org/669 move ts_sublots() to gsm_data_shared.c, it will be used by osmo-bts Change-Id: I8ba06d7dd6e0ceab3d8d18bb565354d6ed461f7e --- M openbsc/include/openbsc/chan_alloc.h M openbsc/include/openbsc/gsm_data_shared.h M openbsc/src/libbsc/chan_alloc.c M openbsc/src/libcommon/gsm_data_shared.c 4 files changed, 27 insertions(+), 27 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/69/669/1 diff --git a/openbsc/include/openbsc/chan_alloc.h b/openbsc/include/openbsc/chan_alloc.h index 3e03b97..78242e5 100644 --- a/openbsc/include/openbsc/chan_alloc.h +++ b/openbsc/include/openbsc/chan_alloc.h @@ -51,6 +51,4 @@ int trx_is_usable(struct gsm_bts_trx *trx); -uint8_t ts_subslots(struct gsm_bts_trx_ts *ts); - #endif /* _CHAN_ALLOC_H */ diff --git a/openbsc/include/openbsc/gsm_data_shared.h b/openbsc/include/openbsc/gsm_data_shared.h index 953bac6..ce2e9b7 100644 --- a/openbsc/include/openbsc/gsm_data_shared.h +++ b/openbsc/include/openbsc/gsm_data_shared.h @@ -853,4 +853,6 @@ struct gsm_lchan *rsl_lchan_lookup(struct gsm_bts_trx *trx, uint8_t chan_nr, int *rc); +uint8_t ts_subslots(struct gsm_bts_trx_ts *ts); + #endif diff --git a/openbsc/src/libbsc/chan_alloc.c b/openbsc/src/libbsc/chan_alloc.c index 92a1358..7b0c3e6 100644 --- a/openbsc/src/libbsc/chan_alloc.c +++ b/openbsc/src/libbsc/chan_alloc.c @@ -72,31 +72,6 @@ return 1; } -static const uint8_t subslots_per_pchan[] = { - [GSM_PCHAN_NONE] = 0, - [GSM_PCHAN_CCCH] = 0, - [GSM_PCHAN_CCCH_SDCCH4] = 4, - [GSM_PCHAN_TCH_F] = 1, - [GSM_PCHAN_TCH_H] = 2, - [GSM_PCHAN_SDCCH8_SACCH8C] = 8, - [GSM_PCHAN_TCH_F_PDCH] = 1, - [GSM_PCHAN_CCCH_SDCCH4_CBCH] = 4, - [GSM_PCHAN_SDCCH8_SACCH8C_CBCH] = 8, - /* - * GSM_PCHAN_TCH_F_TCH_H_PDCH should not be part of this, those TS are - * handled according to their ts->dyn state. - */ -}; - -/*! According to ts->pchan and possibly ts->dyn_pchan, return the number of - * logical channels available in the timeslot. */ -uint8_t ts_subslots(struct gsm_bts_trx_ts *ts) -{ - if (ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) - return subslots_per_pchan[ts->dyn.pchan_is]; - return subslots_per_pchan[ts->pchan]; -} - static struct gsm_lchan * _lc_find_trx(struct gsm_bts_trx *trx, enum gsm_phys_chan_config pchan, enum gsm_phys_chan_config dyn_as_pchan) diff --git a/openbsc/src/libcommon/gsm_data_shared.c b/openbsc/src/libcommon/gsm_data_shared.c index 8d99ea4..5fb75fb 100644 --- a/openbsc/src/libcommon/gsm_data_shared.c +++ b/openbsc/src/libcommon/gsm_data_shared.c @@ -699,3 +699,28 @@ return &ts->lchan[lch_idx]; } + +static const uint8_t subslots_per_pchan[] = { + [GSM_PCHAN_NONE] = 0, + [GSM_PCHAN_CCCH] = 0, + [GSM_PCHAN_CCCH_SDCCH4] = 4, + [GSM_PCHAN_TCH_F] = 1, + [GSM_PCHAN_TCH_H] = 2, + [GSM_PCHAN_SDCCH8_SACCH8C] = 8, + [GSM_PCHAN_TCH_F_PDCH] = 1, + [GSM_PCHAN_CCCH_SDCCH4_CBCH] = 4, + [GSM_PCHAN_SDCCH8_SACCH8C_CBCH] = 8, + /* + * GSM_PCHAN_TCH_F_TCH_H_PDCH should not be part of this, those TS are + * handled according to their ts->dyn state. + */ +}; + +/*! According to ts->pchan and possibly ts->dyn_pchan, return the number of + * logical channels available in the timeslot. */ +uint8_t ts_subslots(struct gsm_bts_trx_ts *ts) +{ + if (ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) + return subslots_per_pchan[ts->dyn.pchan_is]; + return subslots_per_pchan[ts->pchan]; +} -- To view, visit https://gerrit.osmocom.org/669 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I8ba06d7dd6e0ceab3d8d18bb565354d6ed461f7e Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Tue Aug 9 16:38:25 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Tue, 9 Aug 2016 16:38:25 +0000 Subject: [PATCH] openbsc[master]: Add web proxy for control interface In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/659 to look at the new patch set (#3). Add web proxy for control interface Add web application exposing Control Interface over web. All of SET, GET and TRAP are fully supported. Notice: TRAP is converted into 'Server-sent events' according to RFC 6202, see also https://www.w3.org/TR/eventsource/ - this requires corresponding client. Due to use of special prefix modified version of python eventsource-client is necessary ATM. Change-Id: I87d40c80061f8b3d02d656ab8cadabbfb871b461 Related: OS#1646 --- A openbsc/contrib/ctrl2sse.py 1 file changed, 150 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/59/659/3 diff --git a/openbsc/contrib/ctrl2sse.py b/openbsc/contrib/ctrl2sse.py new file mode 100755 index 0000000..142a2b5 --- /dev/null +++ b/openbsc/contrib/ctrl2sse.py @@ -0,0 +1,150 @@ +#!/usr/bin/python2 + +mod_license = """ +/* + * Copyright (C) 2016 sysmocom s.f.m.c. GmbH + * + * All Rights Reserved + * + * 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +""" + +import sys, argparse, random, logging, tornado.ioloop, tornado.web, tornado.tcpclient, tornado.httpclient, eventsource, bsc_control +from eventsource import listener, request + +""" +N. B: this is not an example of building proper REST API or building secure web application. +It's only purpose is to illustrate conversion of Osmocom's Control Interface to web-friendly API. +Exposing this to Internet while connected to production network might lead to all sorts of mischief and mayhem +from NSA' TAO breaking into your network to zombie apocalypse. Do NOT do that. +""" + +stream = None +token = "osmocom" +url = None + +def read_header(data): + t_length = bsc_control.ipa_ctrl_header(data) + if (t_length): + stream.read_bytes(t_length - 1, callback = read_trap) + else: + print >> sys.stderr, "protocol error: length missing in %s!" % data + + at tornado.gen.coroutine +def read_trap(data): + (t, z, v, p) = data.split() + if (t != 'TRAP' or int(z) != 0): + print >> sys.stderr, "protocol error: TRAP != %s or 0! = %d" % (t, int(z)) + (imsi, ip) = p.split(',') + submit_to = "%s/%s/%s" % (url, "ping", token) + yield tornado.httpclient.AsyncHTTPClient().fetch(tornado.httpclient.HTTPRequest(url = submit_to, + method = 'POST', + headers = {'Content-Type': 'application/json'}, + body = tornado.escape.json_encode({ 'event' : v, 'imsi' : imsi, 'ip' : ip }))) + stream.read_bytes(4, callback = read_header) + + at tornado.gen.coroutine +def trap_setup(host, port, target_host, target_port): + global stream + global url + url = "http://%s:%s/sse" % (host, port) + stream = yield tornado.tcpclient.TCPClient().connect(target_host, target_port) + stream.read_bytes(4, callback = read_header) + +def d(s, v): + return { + 'interface' : tornado.escape.json_encode(s.getpeername()), + 'variable' : v, + 'value' : bsc_control.get_var(s, tornado.escape.native_str(v)) + } + +class CtrlHandler(tornado.web.RequestHandler): + ''' + Return json according to following schema - see http://json-schema.org/documentation.html for details: + { + "title": "Ctrl Schema", + "type": "object", + "properties": { + "interface": { + "type": "string" + }, + "variable": { + "type": "string" + }, + "varlue": { + "type": "string" + } + }, + "required": ["interface", "variable", "value"] + } + Example validation from command-line: + json validate --schema-file=schema.json --document-file=data.json + The interface is represented as string because it might look different for IPv4 vs v6. + ''' + def initialize(self): + self.skt = bsc_control.connect(self.settings['host'], self.settings['port']) + + def get(self, v): + self.write(d(self.skt, v)) + + def post(self): + self.write(d(self.skt, self.get_argument("variable"))) + +class SetCtrl(CtrlHandler): + def get(self, var, val): + bsc_control.set_var(self.skt, tornado.escape.native_str(var), tornado.escape.native_str(val)) + super(SetCtrl, self).get(tornado.escape.native_str(var)) + + def post(self): + bsc_control.set_var(self.skt, tornado.escape.native_str(self.get_argument("variable")), tornado.escape.native_str(self.get_argument("value"))) + super(SetCtrl, self).post() + +class Slash(tornado.web.RequestHandler): + def get(self): + self.write('%sUsing Tornado framework v%s' + '
' + '' + '' + '
' + '
' + '' + '' + '' + '
' + '' % ("Osmocom Control Interface Proxy", tornado.version)) + +if __name__ == '__main__': + p = argparse.ArgumentParser(description='Osmocom Control Interface proxy.') + p.add_argument('-c', '--control-port', type = int, default = 4252, help = "Target Control Interface port") + p.add_argument('-a', '--control-host', default = 'localhost', help = "Target Control Interface adress") + p.add_argument('-b', '--host', default = 'localhost', help = "Adress to bind proxy's web interface") + p.add_argument('-p', '--port', type = int, default = 6969, help = "Port to bind proxy's web interface") + p.add_argument('-k', '--keepalive', type = int, default = 5000, help = "Timeout betwwen keepalive messages, in milliseconds, defaults to 5000") + args = p.parse_args() + tornado.netutil.Resolver.configure('tornado.netutil.ThreadedResolver') # Use non-blocking resolver + logging.basicConfig() + application = tornado.web.Application([ + (r"/", Slash), + (r"/get", CtrlHandler), + (r"/get/(.*)", CtrlHandler), + (r"/set", SetCtrl), + (r"/set/(.*)/(.*)", SetCtrl), + (r"/sse/(.*)/(.*)", listener.EventSourceHandler, dict(event_class = listener.JSONIdEvent, keepalive = args.keepalive)), + ], debug = True, ctrl_host = args.control_host, ctrl_port = args.control_port) + random.seed() + application.listen(address = args.host, port = args.port) + trap_setup(args.host, args.port, application.settings['ctrl_host'], application.settings['ctrl_port']) + tornado.ioloop.IOLoop.instance().start() -- To view, visit https://gerrit.osmocom.org/659 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I87d40c80061f8b3d02d656ab8cadabbfb871b461 Gerrit-PatchSet: 3 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max From gerrit-no-reply at lists.osmocom.org Tue Aug 9 17:23:18 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Tue, 9 Aug 2016 17:23:18 +0000 Subject: [PATCH] osmo-pcu[master]: LC: fix build error Message-ID: Review at https://gerrit.osmocom.org/670 LC: fix build error Remove extra parameter which causes build to break. The error was introduced in 878bd1f296379ffba949d6fcae2938c13406df5b Change-Id: Id63187d925d448caa4fa85720582550919b1f216 --- M src/osmo-bts-litecell15/lc15_l1_if.c 1 file changed, 1 insertion(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/70/670/1 diff --git a/src/osmo-bts-litecell15/lc15_l1_if.c b/src/osmo-bts-litecell15/lc15_l1_if.c index a2189f0..fe9dff1 100644 --- a/src/osmo-bts-litecell15/lc15_l1_if.c +++ b/src/osmo-bts-litecell15/lc15_l1_if.c @@ -156,7 +156,7 @@ case GsmL1_Sapi_Pdtch: case GsmL1_Sapi_Pacch: rc = pcu_rx_rts_req_pdtch(fl1h->trx_no, rts_ind->u8Tn, - rts_ind->u16Arfcn, rts_ind->u32Fn, rts_ind->u8BlockNbr); + rts_ind->u32Fn, rts_ind->u8BlockNbr); case GsmL1_Sapi_Ptcch: // FIXME default: -- To view, visit https://gerrit.osmocom.org/670 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Id63187d925d448caa4fa85720582550919b1f216 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Max From gerrit-no-reply at lists.osmocom.org Tue Aug 9 17:26:35 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 9 Aug 2016 17:26:35 +0000 Subject: osmo-pcu[master]: LC: fix build error In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 fixes osmo-pcu --enable-lc15bts-phy build -- To view, visit https://gerrit.osmocom.org/670 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Id63187d925d448caa4fa85720582550919b1f216 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 9 18:47:35 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 9 Aug 2016 18:47:35 +0000 Subject: [PATCH] osmo-bts[master]: sysmo: fix dyn TS: Revert "Activate PTCCH UL" [in sysmobts] Message-ID: Review at https://gerrit.osmocom.org/671 sysmo: fix dyn TS: Revert "Activate PTCCH UL" [in sysmobts] This reverts commit 53d792c3b027bfb42d77804e3e687a287e122ef3. The commit caused this error with SysmoBTS: DL1P <0007> l1_if.c:164 Tx L1 prim MPH-ACTIVATE.req DL1C <0006> oml.c:811 Error activating L1 SAPI PTCCH on TS 7: Invalid parameter DL1C <0006> oml.c:1089 (bts=0,trx=0,ts=7,ss=0) act failed mark broken due status: -4 Since dynamic timeslots wait for the activation to succeed, the broken status breaks dynamic timeslots on SysmoBTS. Initially GPRS works, but the state in the BSC is messed up and placing calls fails for dyn TS: DRLL <0000> chan_alloc.c:355 Failed to allocate TCH_H channel DRSL <0004> abis_rsl.c:1656 BTS 0 CHAN RQD: no resources for TCH_H 0x45 Normal PDCH on SysmoBTS was not broken -- the error message occurs, but that doesn't seem to matter much. Plain GPRS still works since there is no switchover involved. But I can see no benefit in enabling PTCCH UL on sysmo. Since the commit only enabled PTCCH UL in sysmobts, no other BTS models are affected. Notice that lc15 still has PTCCH UL disabled all the while, before and after this commit and its revert. Change-Id: Ia59d95c75a8a5d3bd596f55cd1dc0906a6a95f7f --- M src/osmo-bts-sysmo/oml.c 1 file changed, 1 insertion(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/71/671/1 diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c index e9a4794..585e6d0 100644 --- a/src/osmo-bts-sysmo/oml.c +++ b/src/osmo-bts-sysmo/oml.c @@ -617,9 +617,8 @@ { GsmL1_Sapi_Pdtch, GsmL1_Dir_RxUplink }, { GsmL1_Sapi_Ptcch, GsmL1_Dir_TxDownlink }, { GsmL1_Sapi_Prach, GsmL1_Dir_RxUplink }, - { GsmL1_Sapi_Ptcch, GsmL1_Dir_RxUplink }, - /* FIXME: do we still need this if? */ #if 0 + { GsmL1_Sapi_Ptcch, GsmL1_Dir_RxUplink }, { GsmL1_Sapi_Pacch, GsmL1_Dir_TxDownlink }, #endif }; -- To view, visit https://gerrit.osmocom.org/671 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ia59d95c75a8a5d3bd596f55cd1dc0906a6a95f7f Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Tue Aug 9 18:47:36 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 9 Aug 2016 18:47:36 +0000 Subject: [PATCH] osmo-bts[master]: dyn TS: complete for TRX Message-ID: Review at https://gerrit.osmocom.org/672 dyn TS: complete for TRX Apply similar fixes as for TCH/F_PDCH also for TCH/F_TCH/H_PDCH: Detect dyn TS in PDCH mode in ts_is_pdch(). In trx_set_ts(), enhance the "if (TCH_F_PDCH)" to a switch statement including both dynamic channel types. Adjust the comment to include both kinds. Change-Id: I6669739cd08780cd9ffb9451cdae9f6b9704c4fe --- M src/common/l1sap.c M src/osmo-bts-trx/l1_if.c 2 files changed, 22 insertions(+), 8 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/72/672/1 diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 304f718..6498103 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -299,7 +299,10 @@ return ts->pchan == GSM_PCHAN_PDCH || (ts->pchan == GSM_PCHAN_TCH_F_PDCH && (ts->flags & TS_F_PDCH_ACTIVE) - && !(ts->flags & TS_F_PDCH_PENDING_MASK)); + && !(ts->flags & TS_F_PDCH_PENDING_MASK)) + || (ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH + && ts->dyn.pchan_want == ts->dyn.pchan_is + && ts->dyn.pchan_is == GSM_PCHAN_PDCH); } static int to_gsmtap(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) diff --git a/src/osmo-bts-trx/l1_if.c b/src/osmo-bts-trx/l1_if.c index 4d6dc3f..b89a359 100644 --- a/src/osmo-bts-trx/l1_if.c +++ b/src/osmo-bts-trx/l1_if.c @@ -398,9 +398,10 @@ if (!(l1h->config.slotmask & (1 << tn))) return NM_NACK_RES_NOTAVAIL; - /* set physical channel. For dynamic TCH/F_PDCH, the caller should have + /* set physical channel. For dynamic timeslots, the caller should have * decided on a more specific PCHAN type already. */ OSMO_ASSERT(pchan != GSM_PCHAN_TCH_F_PDCH); + OSMO_ASSERT(pchan != GSM_PCHAN_TCH_F_TCH_H_PDCH); rc = trx_sched_set_pchan(&l1h->l1s, tn, pchan); if (rc) return NM_NACK_RES_NOTAVAIL; @@ -426,15 +427,25 @@ static uint8_t trx_set_ts(struct gsm_bts_trx_ts *ts) { - enum gsm_phys_chan_config pchan = ts->pchan; + enum gsm_phys_chan_config pchan; - /* For dynamic TCH/F_PDCH, pick the pchan type that should currently be - * active according to TS flags. This should only be called during - * init, PDCH transitions will call trx_set_ts_as_pchan() directly. */ - OSMO_ASSERT((ts->flags & TS_F_PDCH_PENDING_MASK) == 0); - if (pchan == GSM_PCHAN_TCH_F_PDCH) + /* For dynamic timeslots, pick the pchan type that should currently be + * active. This should only be called during init, PDCH transitions + * will call trx_set_ts_as_pchan() directly. */ + switch (ts->pchan) { + case GSM_PCHAN_TCH_F_PDCH: + OSMO_ASSERT((ts->flags & TS_F_PDCH_PENDING_MASK) == 0); pchan = (ts->flags & TS_F_PDCH_ACTIVE)? GSM_PCHAN_PDCH : GSM_PCHAN_TCH_F; + break; + case GSM_PCHAN_TCH_F_TCH_H_PDCH: + OSMO_ASSERT(ts->dyn.pchan_is == ts->dyn.pchan_want); + pchan = ts->dyn.pchan_is; + break; + default: + pchan = ts->pchan; + break; + } return trx_set_ts_as_pchan(ts, pchan); } -- To view, visit https://gerrit.osmocom.org/672 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I6669739cd08780cd9ffb9451cdae9f6b9704c4fe Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Tue Aug 9 18:47:36 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 9 Aug 2016 18:47:36 +0000 Subject: [PATCH] osmo-bts[master]: dyn TS: measurement.c: replace fixme with comment Message-ID: Review at https://gerrit.osmocom.org/673 dyn TS: measurement.c: replace fixme with comment Change-Id: I04668f6f01a48157a98c6326a9ee48982a09ee62 --- M src/common/measurement.c 1 file changed, 1 insertion(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/73/673/1 diff --git a/src/common/measurement.c b/src/common/measurement.c index b0906d4..d0b84d5 100644 --- a/src/common/measurement.c +++ b/src/common/measurement.c @@ -210,8 +210,8 @@ [GSM_PCHAN_TCH_H] = 2, [GSM_PCHAN_SDCCH8_SACCH8C] = 8, [GSM_PCHAN_SDCCH8_SACCH8C_CBCH] = 8, - /* FIXME: what about dynamic TCH_F_TCH_H ? */ [GSM_PCHAN_TCH_F_PDCH] = 1, + /* dynamic pchan are handled outside of this array */ }; static int ts_meas_check_compute(struct gsm_bts_trx_ts *ts, uint32_t fn) -- To view, visit https://gerrit.osmocom.org/673 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I04668f6f01a48157a98c6326a9ee48982a09ee62 Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Tue Aug 9 18:47:36 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 9 Aug 2016 18:47:36 +0000 Subject: [PATCH] osmo-bts[master]: sysmo, lc15: ts_connect_as(): log error also for pchan_as == ... Message-ID: Review at https://gerrit.osmocom.org/674 sysmo,lc15: ts_connect_as(): log error also for pchan_as == TCH/F_PDCH Change-Id: I76c868a1e70af16268a6fa42dc736cf0b288ecdb --- M src/osmo-bts-litecell15/oml.c M src/osmo-bts-sysmo/oml.c 2 files changed, 4 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/74/674/1 diff --git a/src/osmo-bts-litecell15/oml.c b/src/osmo-bts-litecell15/oml.c index 8b1f195..5ce510a 100644 --- a/src/osmo-bts-litecell15/oml.c +++ b/src/osmo-bts-litecell15/oml.c @@ -488,7 +488,8 @@ struct lc15l1_hdl *fl1h = trx_lc15l1_hdl(ts->trx); GsmL1_MphConnectReq_t *cr; - if (pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) { + if (pchan == GSM_PCHAN_TCH_F_PDCH + || pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) { LOGP(DL1C, LOGL_ERROR, "%s Requested TS connect as %s," " expected a specific pchan instead\n", diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c index 585e6d0..e5d3e40 100644 --- a/src/osmo-bts-sysmo/oml.c +++ b/src/osmo-bts-sysmo/oml.c @@ -491,7 +491,8 @@ struct femtol1_hdl *fl1h = trx_femtol1_hdl(ts->trx); GsmL1_MphConnectReq_t *cr; - if (pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) { + if (pchan == GSM_PCHAN_TCH_F_PDCH + || pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) { LOGP(DL1C, LOGL_ERROR, "%s Requested TS connect as %s," " expected a specific pchan instead\n", -- To view, visit https://gerrit.osmocom.org/674 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I76c868a1e70af16268a6fa42dc736cf0b288ecdb Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Tue Aug 9 18:47:37 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 9 Aug 2016 18:47:37 +0000 Subject: [PATCH] osmo-bts[master]: dyn TS: measurement: use correct nr of subslots, rm code dup Message-ID: Review at https://gerrit.osmocom.org/675 dyn TS: measurement: use correct nr of subslots, rm code dup In measurement.c, fix the number of sublots for TCH/F_TCH/H_PDCH, by using ts_subslots() from gsm_data_shared.c. The local dup of subslots_per_pchan[] is no longer needed. (depends on recent commit to openbsc.git for ts_sublots()) Change-Id: I9d9df470c49487bffd56dde42c7bec0da2f50642 --- M src/common/measurement.c 1 file changed, 1 insertion(+), 15 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/75/675/1 diff --git a/src/common/measurement.c b/src/common/measurement.c index d0b84d5..be1d4f6 100644 --- a/src/common/measurement.c +++ b/src/common/measurement.c @@ -200,24 +200,10 @@ return 1; } -/* Copied from OpenBSC and enlarged to _GSM_PCHAN_MAX */ -static const uint8_t subslots_per_pchan[_GSM_PCHAN_MAX] = { - [GSM_PCHAN_NONE] = 0, - [GSM_PCHAN_CCCH] = 0, - [GSM_PCHAN_CCCH_SDCCH4] = 4, - [GSM_PCHAN_CCCH_SDCCH4_CBCH] = 4, - [GSM_PCHAN_TCH_F] = 1, - [GSM_PCHAN_TCH_H] = 2, - [GSM_PCHAN_SDCCH8_SACCH8C] = 8, - [GSM_PCHAN_SDCCH8_SACCH8C_CBCH] = 8, - [GSM_PCHAN_TCH_F_PDCH] = 1, - /* dynamic pchan are handled outside of this array */ -}; - static int ts_meas_check_compute(struct gsm_bts_trx_ts *ts, uint32_t fn) { int i; - const int num_subslots = subslots_per_pchan[ts->pchan]; + const int num_subslots = ts_subslots(ts); for (i = 0; i < num_subslots; ++i) { struct gsm_lchan *lchan = &ts->lchan[i]; -- To view, visit https://gerrit.osmocom.org/675 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I9d9df470c49487bffd56dde42c7bec0da2f50642 Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Tue Aug 9 18:47:37 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 9 Aug 2016 18:47:37 +0000 Subject: [PATCH] osmo-bts[master]: cosmetic: common ts_is_pdch() Message-ID: Review at https://gerrit.osmocom.org/676 cosmetic: common ts_is_pdch() Have one common ts_is_pdch(), placed in lchan.c, since this file is pretty empty and pretty close to ts. Publish in gsm_data.h. Remove the if-style implementation from l1sap.c, and instead implement in a switch statement. This prepares for upcoming ts_is_pdch() usage in ph_data_req() for sysmo and lc15. Change-Id: Ib78d663fdbac5a1d7053f1b9d543649b66da00e2 --- M include/osmo-bts/gsm_data.h M src/common/l1sap.c M src/common/lchan.c 3 files changed, 17 insertions(+), 11 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/76/676/1 diff --git a/include/osmo-bts/gsm_data.h b/include/osmo-bts/gsm_data.h index c75f828..f1c9601 100644 --- a/include/osmo-bts/gsm_data.h +++ b/include/osmo-bts/gsm_data.h @@ -135,5 +135,6 @@ int bts_supports_cipher(struct gsm_bts_role_bts *bts, int rsl_cipher); +bool ts_is_pdch(const struct gsm_bts_trx_ts *ts); #endif /* _GSM_DATA_H */ diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 6498103..584f9f4 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -294,17 +294,6 @@ return 0; } -static bool ts_is_pdch(const struct gsm_bts_trx_ts *ts) -{ - return ts->pchan == GSM_PCHAN_PDCH - || (ts->pchan == GSM_PCHAN_TCH_F_PDCH - && (ts->flags & TS_F_PDCH_ACTIVE) - && !(ts->flags & TS_F_PDCH_PENDING_MASK)) - || (ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH - && ts->dyn.pchan_want == ts->dyn.pchan_is - && ts->dyn.pchan_is == GSM_PCHAN_PDCH); -} - static int to_gsmtap(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) { uint8_t *data; diff --git a/src/common/lchan.c b/src/common/lchan.c index fbc2636..9e98166 100644 --- a/src/common/lchan.c +++ b/src/common/lchan.c @@ -31,3 +31,19 @@ gsm_lchans_name(state)); lchan->state = state; } + +bool ts_is_pdch(const struct gsm_bts_trx_ts *ts) +{ + switch (ts->pchan) { + case GSM_PCHAN_PDCH: + return true; + case GSM_PCHAN_TCH_F_PDCH: + return (ts->flags & TS_F_PDCH_ACTIVE) + && !(ts->flags & TS_F_PDCH_PENDING_MASK); + case GSM_PCHAN_TCH_F_TCH_H_PDCH: + return ts->dyn.pchan_is == GSM_PCHAN_PDCH + && ts->dyn.pchan_want == ts->dyn.pchan_is; + default: + return false; + } +} -- To view, visit https://gerrit.osmocom.org/676 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ib78d663fdbac5a1d7053f1b9d543649b66da00e2 Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Tue Aug 9 18:47:37 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 9 Aug 2016 18:47:37 +0000 Subject: [PATCH] osmo-bts[master]: dyn TS: sysmo, lc15: ph_data_req: fix PDCH mode detection Message-ID: Review at https://gerrit.osmocom.org/677 dyn TS: sysmo,lc15: ph_data_req: fix PDCH mode detection Though this patch theoretically makes a lot of sense, it is not entirely clear why dyn TS are working without it. Committing due to common sense, not to fix any actual breakage. Change-Id: I6136cb42a4d627ebefc963eb5321fadfe63cca4b --- M src/osmo-bts-litecell15/l1_if.c M src/osmo-bts-sysmo/l1_if.c 2 files changed, 2 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/77/677/1 diff --git a/src/osmo-bts-litecell15/l1_if.c b/src/osmo-bts-litecell15/l1_if.c index dcd25ee..3672b8f 100644 --- a/src/osmo-bts-litecell15/l1_if.c +++ b/src/osmo-bts-litecell15/l1_if.c @@ -363,7 +363,7 @@ if (!L1SAP_IS_CHAN_TCHF(chan_nr)) subCh = l1sap_chan2ss(chan_nr); } else if (L1SAP_IS_CHAN_TCHF(chan_nr)) { - if (trx->ts[u8Tn].pchan == GSM_PCHAN_PDCH) { + if (ts_is_pdch(&trx->ts[u8Tn])) { if (L1SAP_IS_PTCCH(u32Fn)) { sapi = GsmL1_Sapi_Ptcch; u8BlockNbr = L1SAP_FN2PTCCHBLOCK(u32Fn); diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index f70ccf5..d9b6111 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -358,7 +358,7 @@ if (!L1SAP_IS_CHAN_TCHF(chan_nr)) subCh = l1sap_chan2ss(chan_nr); } else if (L1SAP_IS_CHAN_TCHF(chan_nr)) { - if (trx->ts[u8Tn].pchan == GSM_PCHAN_PDCH) { + if (ts_is_pdch(&trx->ts[u8Tn])) { if (L1SAP_IS_PTCCH(u32Fn)) { sapi = GsmL1_Sapi_Ptcch; u8BlockNbr = L1SAP_FN2PTCCHBLOCK(u32Fn); -- To view, visit https://gerrit.osmocom.org/677 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I6136cb42a4d627ebefc963eb5321fadfe63cca4b Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Wed Aug 10 06:31:15 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Wed, 10 Aug 2016 06:31:15 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 5: I get build failure for one of the patches related to DL SPB for EGPRS. But when I see the console output at below link I see tests are getting passed. I have also noticed " Documentation error (missing docs):" at the same link. Let me know if it is issue with patch or something else. http://jenkins.osmocom.org/jenkins/job/osmo-pcu-gerrit/label=linux_amd64_debian8,sysmobts=no,sysmodsp=no/lastUnsuccessfulBuild/consoleText -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 5 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 10 06:34:43 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Wed, 10 Aug 2016 06:34:43 +0000 Subject: openbsc[master]: gsm_pchan2chan_nr: disable a chan_nr assert in BTS, to not b... In-Reply-To: References: Message-ID: Patch Set 3: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/665 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I05253343d5bcc7b319444376098dc8561dd83944 Gerrit-PatchSet: 3 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 10 06:35:24 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Wed, 10 Aug 2016 06:35:24 +0000 Subject: openbsc[master]: gsm_pchan2chan_nr(): fix uninitialized cbits In-Reply-To: References: Message-ID: Patch Set 3: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/666 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: If69f6b1f6208138d5b91bac51ffd78dab95245e5 Gerrit-PatchSet: 3 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 10 06:36:04 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Wed, 10 Aug 2016 06:36:04 +0000 Subject: osmo-bts[master]: cosmetic: common ts_is_pdch() In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/676 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ib78d663fdbac5a1d7053f1b9d543649b66da00e2 Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 10 06:37:58 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Wed, 10 Aug 2016 06:37:58 +0000 Subject: osmo-bts[master]: sysmo: fix dyn TS: Revert "Activate PTCCH UL" [in sysmobts] In-Reply-To: References: Message-ID: Patch Set 1: the question is why is there an invalid parameter? Activation of PTCCH is definitely something we want to have in GPRS. Why does it break in case of dynamic PDCH but work in case of static PDCH? -- To view, visit https://gerrit.osmocom.org/671 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia59d95c75a8a5d3bd596f55cd1dc0906a6a95f7f Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 10 06:38:23 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Wed, 10 Aug 2016 06:38:23 +0000 Subject: osmo-bts[master]: dyn TS: complete for TRX In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/672 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I6669739cd08780cd9ffb9451cdae9f6b9704c4fe Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 10 06:38:38 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Wed, 10 Aug 2016 06:38:38 +0000 Subject: osmo-bts[master]: dyn TS: measurement.c: replace fixme with comment In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/673 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I04668f6f01a48157a98c6326a9ee48982a09ee62 Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 10 06:38:52 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Wed, 10 Aug 2016 06:38:52 +0000 Subject: osmo-bts[master]: sysmo, lc15: ts_connect_as(): log error also for pchan_as == ... In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/674 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I76c868a1e70af16268a6fa42dc736cf0b288ecdb Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 10 06:39:20 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Wed, 10 Aug 2016 06:39:20 +0000 Subject: osmo-bts[master]: dyn TS: measurement: use correct nr of subslots, rm code dup In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+1 -- To view, visit https://gerrit.osmocom.org/675 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I9d9df470c49487bffd56dde42c7bec0da2f50642 Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 10 06:39:49 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Wed, 10 Aug 2016 06:39:49 +0000 Subject: osmo-bts[master]: dyn TS: sysmo, lc15: ph_data_req: fix PDCH mode detection In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/677 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I6136cb42a4d627ebefc963eb5321fadfe63cca4b Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 10 06:40:31 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Wed, 10 Aug 2016 06:40:31 +0000 Subject: openbsc[master]: Add web proxy for control interface In-Reply-To: References: Message-ID: Patch Set 3: Code-Review+1 -- To view, visit https://gerrit.osmocom.org/659 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I87d40c80061f8b3d02d656ab8cadabbfb871b461 Gerrit-PatchSet: 3 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 10 06:41:51 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Wed, 10 Aug 2016 06:41:51 +0000 Subject: [MERGED] osmo-bts[master]: osmo-bts-trx: log decoder bit errors as DEBUG, not NOTICE In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: osmo-bts-trx: log decoder bit errors as DEBUG, not NOTICE ...................................................................... osmo-bts-trx: log decoder bit errors as DEBUG, not NOTICE It is not an exceptional situation if the air-interface is experiencing non-recoverable decoding errors. At bad signal conditions and/or interference, this is perfectly normal. Let's use DEBUG instead of NOTICE log level. Change-Id: Ifd39c53ec22f57cdb5299e5d76ff6ff1482d3beb --- M src/osmo-bts-trx/scheduler_trx.c 1 file changed, 1 insertion(+), 1 deletion(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/src/osmo-bts-trx/scheduler_trx.c b/src/osmo-bts-trx/scheduler_trx.c index e02232b..02e7aba 100644 --- a/src/osmo-bts-trx/scheduler_trx.c +++ b/src/osmo-bts-trx/scheduler_trx.c @@ -877,7 +877,7 @@ /* decode */ rc = xcch_decode(l2, *bursts_p, &n_errors, &n_bits_total); if (rc) { - LOGP(DL1C, LOGL_NOTICE, "Received bad data frame at fn=%u " + LOGP(DL1C, LOGL_DEBUG, "Received bad data frame at fn=%u " "(%u/%u) for %s\n", *first_fn, (*first_fn) % l1ts->mf_period, l1ts->mf_period, trx_chan_desc[chan].name); -- To view, visit https://gerrit.osmocom.org/651 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ifd39c53ec22f57cdb5299e5d76ff6ff1482d3beb Gerrit-PatchSet: 2 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Harald Welte Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Wed Aug 10 06:43:40 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Wed, 10 Aug 2016 06:43:40 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 5: > I get build failure for one of the patches related to DL SPB for > EGPRS. But when I see the console output at below link I see tests > are getting passed. I have also noticed " Documentation error > (missing docs):" at the same link. Let me know if it is issue with > patch or something else. Well. Documentation error is an error. In pcu_vty.c you introduce a new VTY command but not all parameters are documented. Document all parameters and the error will go away. -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 5 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 10 07:03:02 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Wed, 10 Aug 2016 07:03:02 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 5: (1 comment) https://gerrit.osmocom.org/#/c/655/5/src/pcu_vty.c File src/pcu_vty.c: Line 133: vty_out(vty, " arq %d %s", bts->dl_arq_type, VTY_NEWLINE); dl arq issue here -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 5 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Wed Aug 10 07:04:04 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Wed, 10 Aug 2016 07:04:04 +0000 Subject: [PATCH] osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/655 to look at the new patch set (#6). Modify EGPRS DL TBF flow to support SPB Modify the EGPRS DL TBF flow to support Split block during Retx. This patch will also Upgrade the test suite with test cases to validate the EGPRS Downlink SPB for Retransmission Scenarios like MCS6->MCS3, MCS4->MCS1, MCS5->MCS2, MCS9->MCS3 MCS7->MCS2, MCS8->MCS3 have been simulated and Integration tested in NuRAN 1.0 hardware thoroughly. Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 --- M src/gprs_coding_scheme.h M src/pcu_main.cpp M src/pcu_vty.c M src/rlc.cpp M src/rlc.h M src/tbf.h M src/tbf_dl.cpp M tests/edge/EdgeTest.cpp M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 11 files changed, 950 insertions(+), 77 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/55/655/6 diff --git a/src/gprs_coding_scheme.h b/src/gprs_coding_scheme.h index 60a8e79..3b15372 100644 --- a/src/gprs_coding_scheme.h +++ b/src/gprs_coding_scheme.h @@ -113,7 +113,8 @@ static const char *modeName(Mode mode); static Scheme get_retx_mcs(const GprsCodingScheme mcs, - const GprsCodingScheme retx_mcs); + const GprsCodingScheme retx_mcs, + const unsigned arq_type); static enum Scheme egprs_mcs_retx_tbl[MAX_NUM_ARQ] [MAX_NUM_MCS][MAX_NUM_MCS]; @@ -232,8 +233,9 @@ } inline GprsCodingScheme::Scheme GprsCodingScheme::get_retx_mcs( const GprsCodingScheme mcs, - const GprsCodingScheme demanded_mcs) + const GprsCodingScheme demanded_mcs, + const unsigned arq_type) { - return egprs_mcs_retx_tbl[EGPRS_ARQ2][mcs.to_num() - 1] + return egprs_mcs_retx_tbl[arq_type][mcs.to_num() - 1] [demanded_mcs.to_num() - 1]; } diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2d86cda..e34d534 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -210,6 +210,12 @@ bts->dl_tbf_idle_msec = 2000; bts->llc_idle_ack_csec = 10; + /* + * By default resegmentation is supported in DL + * can also be configured through VTY + */ + bts->dl_arq_type = EGPRS_ARQ1; + msgb_set_talloc_ctx(tall_pcu_ctx); osmo_init_logging(&gprs_log_info); diff --git a/src/pcu_vty.c b/src/pcu_vty.c index 58fea99..0dd8af6 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -129,6 +129,9 @@ vty_out(vty, " window-size %d %d%s", bts->ws_base, bts->ws_pdch, VTY_NEWLINE); + if (bts->dl_arq_type) + vty_out(vty, " dl arq %d %s", bts->dl_arq_type, VTY_NEWLINE); + if (bts->force_llc_lifetime == 0xffff) vty_out(vty, " queue lifetime infinite%s", VTY_NEWLINE); else if (bts->force_llc_lifetime) @@ -477,6 +480,22 @@ bts->max_mcs_dl = 0; bts->max_mcs_ul = 0; + return CMD_SUCCESS; +} + +#define EGPRS_DL_ARQ_STR "DL ARQ TYPE (EGPRS)\n" + +DEFUN(cfg_pcu_dl_arq_type, + cfg_pcu_dl_arq_cmd, + "dl arq <0-1> [<0-1>]", + EGPRS_DL_ARQ_STR + "Initial ARQ value to be used is (default 0:Reseg)\n" + "0:Reseg, 1:no Reseg") +{ + struct gprs_rlcmac_bts *bts = bts_main_data(); + uint8_t dl_arq_type = atoi(argv[0]); + + bts->dl_arq_type = dl_arq_type; return CMD_SUCCESS; } @@ -954,6 +973,7 @@ install_element(PCU_NODE, &cfg_pcu_no_cs_downgrade_thrsh_cmd); install_element(PCU_NODE, &cfg_pcu_cs_lqual_ranges_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_cmd); + install_element(PCU_NODE, &cfg_pcu_dl_arq_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_max_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_max_cmd); diff --git a/src/rlc.cpp b/src/rlc.cpp index 6770043..8da96f7 100644 --- a/src/rlc.cpp +++ b/src/rlc.cpp @@ -285,7 +285,8 @@ } static void gprs_rlc_data_header_init(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding, unsigned int header_bits) + GprsCodingScheme cs, bool with_padding, unsigned int header_bits, + const unsigned int spb) { unsigned int i; unsigned int padding_bits = with_padding ? cs.optionalPaddingBits() : 0; @@ -300,7 +301,7 @@ for (i = 0; i < rlc->num_data_blocks; i++) { gprs_rlc_data_block_info_init(&rlc->block_info[i], cs, - with_padding); + with_padding, spb); rlc->data_offs_bits[i] = header_bits + padding_bits + @@ -310,21 +311,25 @@ } void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsDL()); + cs.numDataHeaderBitsDL(), spb); } void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding) { + /* + * last parameter is sent as 0 since common function used + * for both DL and UL + */ return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsUL()); + cs.numDataHeaderBitsUL(), 0); } void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { unsigned int data_len = cs.maxDataBlockBytes(); if (with_padding) @@ -336,7 +341,7 @@ rdbi->e = 1; rdbi->cv = 15; rdbi->pi = 0; - rdbi->spb = 0; + rdbi->spb = spb; } unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, @@ -411,8 +416,17 @@ enum egprs_puncturing_values gprs_get_punct_scheme( enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current) + const GprsCodingScheme &cs_current, + const unsigned int spb) { + + /* + * If it is second segment of the block + * dont change the puncturing scheme + */ + if (spb == 3) + return punct; + /* TS 44.060 9.3.2.1.1 */ if ((GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS9) && (GprsCodingScheme::Scheme(cs_current) == GprsCodingScheme::MCS6)) { diff --git a/src/rlc.h b/src/rlc.h index 539b30b..66faf6f 100644 --- a/src/rlc.h +++ b/src/rlc.h @@ -206,18 +206,19 @@ }; void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding); void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, enum egprs_puncturing_values punct, enum egprs_puncturing_values punct2, int with_padding); void gprs_rlc_mcs_cps_decode(unsigned int cps, GprsCodingScheme cs, int *punct, int *punct2, int *with_padding); enum egprs_puncturing_values gprs_get_punct_scheme(enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current_trans); + const GprsCodingScheme &cs_current_trans, + const unsigned int spb); void gprs_update_punct_scheme(enum egprs_puncturing_values *punct, const GprsCodingScheme &cs); /* diff --git a/src/tbf.h b/src/tbf.h index 1bd7878..969836b 100644 --- a/src/tbf.h +++ b/src/tbf.h @@ -421,6 +421,11 @@ int analyse_errors(char *show_rbb, uint8_t ssn, ana_result *res); void schedule_next_frame(); + enum egprs_rlc_dl_reseg_bsn_state egprs_dl_get_data_buffer + (int bsn, uint8_t **block_data); + unsigned int get_egprs_dl_spb_status(int bsn); + unsigned int get_egprs_dl_spb_value(int bsn); + struct osmo_timer_list m_llc_timer; }; diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp index 07a747a..0395ed0 100644 --- a/src/tbf_dl.cpp +++ b/src/tbf_dl.cpp @@ -375,21 +375,27 @@ return -1; if (is_egprs_enabled()) { + /* Table 8.1.1.2 and Table 8.1.1.1 of 44.060 */ m_rlc.block(bsn)->cs_current_trans = - GprsCodingScheme::get_retx_mcs( - m_rlc.block(bsn)->cs_last, ms()->current_cs_dl()); + GprsCodingScheme::get_retx_mcs( + m_rlc.block(bsn)->cs_init, + ms()->current_cs_dl(), + bts->bts_data()->dl_arq_type); LOGP(DRLCMACDL, LOGL_DEBUG, - "- current_cs_dl(%d) demanded_mcs(%d) cs_trans(%d)\n", + "- initial_cs_dl(%d) last_mcs(%d) demanded_mcs(%d)" + "cs_trans(%d) arq_type(%d) bsn(%d)\n", + m_rlc.block(bsn)->cs_init.to_num(), m_rlc.block(bsn)->cs_last.to_num(), ms()->current_cs_dl().to_num(), - m_rlc.block(bsn)->cs_current_trans.to_num()); + m_rlc.block(bsn)->cs_current_trans.to_num(), + bts->bts_data()->dl_arq_type, bsn); /* TODO: Need to remove this check when MCS-8 -> MCS-6 * transistion is handled. * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 */ - if (m_rlc.block(bsn)->cs_last == GprsCodingScheme::MCS8) + if (m_rlc.block(bsn)->cs_init == GprsCodingScheme::MCS8) m_rlc.block(bsn)->cs_current_trans = GprsCodingScheme::MCS8; } else @@ -523,6 +529,11 @@ data = rlc_data->prepare(block_data_len); rlc_data->cs_last = cs; rlc_data->cs_current_trans = cs; + + /* Initialise the variable related to DL SPB */ + rlc_data->spb_status.block_status_dl = EGPRS_RESEG_DL_DEFAULT; + rlc_data->cs_init = cs; + rlc_data->len = block_data_len; rdbi = &(rlc_data->block_info); @@ -616,6 +627,7 @@ unsigned num_bsns; enum egprs_puncturing_values punct[ARRAY_SIZE(rlc.block_info)]; bool need_padding = false; + unsigned int spb = 0; /* * TODO: This is an experimental work-around to put 2 BSN into @@ -626,6 +638,7 @@ * the current limit. */ cs = m_rlc.block(index)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(index)->cs_init; bsns[0] = index; num_bsns = 1; @@ -634,7 +647,19 @@ num_bsns += 1; } - if (num_bsns == 1) { + /* + * if the intial mcs is 8 and retransmission mcs is either 6 or 3 + * we have to include the padding of 6 octets in first segment + */ + if ((GprsCodingScheme::Scheme(cs_init) == GprsCodingScheme::MCS8) && + (GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS6 || + GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS3)) { + if ((get_egprs_dl_spb_status(index) == + EGPRS_RESEG_DL_DEFAULT) || + (get_egprs_dl_spb_status(index) == + EGPRS_RESEG_SECOND_SEG_SENT)) + need_padding = true; + } else if (num_bsns == 1) { /* TODO: remove the conditional when MCS-6 padding isn't * failing to be decoded by MEs anymore */ /* TODO: support of MCS-8 -> MCS-6 transition should be @@ -646,7 +671,14 @@ cs.decToSingleBlock(&need_padding); } - gprs_rlc_data_info_init_dl(&rlc, cs, need_padding); + spb = get_egprs_dl_spb_value(index); + + LOGP(DRLCMACDL, LOGL_DEBUG, "- need_padding %d spb_status %d spb %d" + "(BSN1 %d BSN2 %d)\n", + need_padding, + get_egprs_dl_spb_status(index), spb, index, index2); + + gprs_rlc_data_info_init_dl(&rlc, cs, need_padding, spb); rlc.usf = 7; /* will be set at scheduler */ rlc.pr = 0; /* FIXME: power reduction */ @@ -665,10 +697,9 @@ data_block_idx++) { int bsn; - GprsCodingScheme cs_enc; uint8_t *block_data; gprs_rlc_data_block_info *rdbi, *block_info; - enum egprs_puncturing_values punct_scheme; + enum egprs_rlc_dl_reseg_bsn_state reseg_status; /* Check if there are more blocks than BSNs */ if (data_block_idx < num_bsns) @@ -676,38 +707,43 @@ else bsn = bsns[0]; - cs_enc = m_rlc.block(bsn)->cs_current_trans; - /* get data and header from current block */ - block_data = m_rlc.block(bsn)->block; - /* Get current puncturing scheme from block */ - punct_scheme = gprs_get_punct_scheme( + + m_rlc.block(bsn)->next_ps = gprs_get_punct_scheme( m_rlc.block(bsn)->next_ps, - m_rlc.block(bsn)->cs_last, cs); + m_rlc.block(bsn)->cs_last, cs, spb); if (cs.isEgprs()) { - OSMO_ASSERT(punct_scheme >= EGPRS_PS_1); - OSMO_ASSERT(punct_scheme <= EGPRS_PS_3); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps >= EGPRS_PS_1); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps <= EGPRS_PS_3); } - punct[data_block_idx] = punct_scheme; + punct[data_block_idx] = m_rlc.block(bsn)->next_ps; rdbi = &rlc.block_info[data_block_idx]; block_info = &m_rlc.block(bsn)->block_info; - if(rdbi->data_len != m_rlc.block(bsn)->len) { - LOGP(DRLCMACDL, LOGL_ERROR, - "ERROR: Expected len = %d for %s instead of " - "%d in data unit %d (BSN %d, %s)\n", - rdbi->data_len, cs.name(), m_rlc.block(bsn)->len, - data_block_idx, bsn, cs_enc.name()); - OSMO_ASSERT(rdbi->data_len == m_rlc.block(bsn)->len); - } - - /* TODO: Need to handle 2 same bsns - * in header type 1 + /* + * get data and header from current block + * function returns the reseg status */ - gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, - cs); + reseg_status = egprs_dl_get_data_buffer(bsn, &block_data); + m_rlc.block(bsn)->spb_status.block_status_dl = reseg_status; + + /* + * If it is first segment of the split block set the state of + * bsn to nacked. If it is the first segment dont update the + * next ps value of bsn. since next segment also needs same cps + */ + if (spb == 2) + m_window.m_v_b.mark_nacked(bsn); + else { + /* + * TODO: Need to handle 2 same bsns + * in header type 1 + */ + gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, + cs); + } m_rlc.block(bsn)->cs_last = cs; rdbi->e = block_info->e; @@ -1169,3 +1205,119 @@ keep_time_frames = msecs_to_frames(bts_data()->dl_tbf_idle_msec); return frames_since_last_drain(fn) <= keep_time_frames; } + +/* + * This function returns the pointer to data which needs + * to be copied. Also updates the status of the block related to + * Split block handling in the RLC/MAC block. + */ +enum egprs_rlc_dl_reseg_bsn_state + gprs_rlcmac_dl_tbf::egprs_dl_get_data_buffer(int bsn, + uint8_t **block_data) +{ + gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state *block_status_dl = + &rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + *block_data = &rlc_data->block[0]; + + /* + * Table 10.3a.0.1 of 44.060 + * MCS6,9: second segment starts at 74/2 = 37 + * MCS5,7: second segment starts at 56/2 = 28 + * MCS8: second segment starts at 31 + * MCS4: second segment starts at 44/2 = 22 + */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + if (*block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + switch (GprsCodingScheme::Scheme(cs_init)) { + case GprsCodingScheme::MCS6 : + case GprsCodingScheme::MCS9 : + *block_data = &rlc_data->block[37]; + break; + case GprsCodingScheme::MCS7 : + case GprsCodingScheme::MCS5 : + *block_data = &rlc_data->block[28]; + break; + case GprsCodingScheme::MCS8 : + *block_data = &rlc_data->block[31]; + break; + case GprsCodingScheme::MCS4 : + *block_data = &rlc_data->block[22]; + break; + default: + LOGP(DRLCMACDL, LOGL_ERROR, "Software error: " + "--%s hit invalid condition. headerType(%d) " + " blockstatus(%d) cs(%s) PLEASE FIX!\n", name(), + cs_current_trans.headerTypeData(), + *block_status_dl, cs_init.name()); + break; + + } + return EGPRS_RESEG_SECOND_SEG_SENT; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } + } + return EGPRS_RESEG_DL_DEFAULT; +} + +/* + * This function returns the status of split block + * for RLC/MAC block. + */ +unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_status(const int bsn) +{ + const gprs_rlc_data *rlc_data = m_rlc.block(bsn); + + return rlc_data->spb_status.block_status_dl; +} + +/* + * This function returns the spb value to be sent OTA + * for RLC/MAC block. + */ +unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_value(const int bsn) +{ + struct gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state block_status_dl = + rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + + /* Table 10.4.8b.1 of 44.060 */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + /* + * if we are sending the second segment the spb should be 3 + * other wise it should be 2 + */ + if (block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + return 3; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return 2; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return 2; + } + } + /* Non SPB cases 0 is reurned */ + return 0; +} diff --git a/tests/edge/EdgeTest.cpp b/tests/edge/EdgeTest.cpp index 807102c..9081d4d 100644 --- a/tests/edge/EdgeTest.cpp +++ b/tests/edge/EdgeTest.cpp @@ -517,7 +517,7 @@ /* TS 44.060, B.1 */ cs = GprsCodingScheme::CS4; - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -570,7 +570,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -592,7 +592,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -630,7 +630,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -669,7 +669,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -694,7 +694,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -719,7 +719,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -740,7 +740,7 @@ OSMO_ASSERT(data[0] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -777,7 +777,7 @@ cs = GprsCodingScheme::MCS4; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -835,7 +835,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -872,7 +872,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -923,7 +923,7 @@ OSMO_ASSERT(data[3] == 0); /* Block 3 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -967,7 +967,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -993,7 +993,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1020,7 +1020,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1074,7 +1074,7 @@ block_idx++) { struct gprs_rlc_data_info rlc; - gprs_rlc_data_info_init_dl(&rlc, cs, false); + gprs_rlc_data_info_init_dl(&rlc, cs, false, 0); memset(bits, pattern, sizeof(bits)); Decoding::rlc_copy_to_aligned_buffer( @@ -1118,12 +1118,14 @@ struct gprs_rlc_data_info rlc; printf("=== start %s ===\n", __func__); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::CS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::CS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 24); OSMO_ASSERT(rlc.block_info[0].data_len == 20); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::MCS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::MCS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 33); OSMO_ASSERT(rlc.block_info[0].data_len == 22); diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..18cc5cb 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -1814,6 +1814,201 @@ } +static void egprs_spb_to_normal_validation(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + uint16_t bsn1, bsn2, bsn3; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + struct gprs_rlc_dl_header_egprs_2 *egprs2; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + if ((mcs == 6) && (demanded_mcs == 3)) { + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + bsn1 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) + || (egprs2->bsn1_lo); + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(bsn1 == 0); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + bsn2 = (egprs3->bsn1_hi << 9) || (egprs3->bsn1_mid << 1) || + (egprs3->bsn1_lo); + OSMO_ASSERT(bsn2 == bsn1); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Handle (MCS3, MCS3) -> MCS6 case */ + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + mcs)); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs2->cps == 0); + bsn3 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) || + (egprs2->bsn1_lo); + OSMO_ASSERT(bsn3 == bsn2); + + tbf_cleanup(dl_tbf); + } +} +static void establish_and_use_egprs_dl_tbf_for_spb(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + /* TODO: Need to support of MCS8 -> MCS6 ->MCS3 transistion + * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 + * dated 2016-02-07 23:45:40 (UTC) + */ + if (((mcs == 5) && (demanded_mcs == 2)) || + ((mcs == 6) && (demanded_mcs == 3)) || + ((mcs == 4) && (demanded_mcs == 1))) { + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + tbf_cleanup(dl_tbf); + } +} + static void establish_and_use_egprs_dl_tbf_for_retx(BTS *the_bts, int mcs, int demanded_mcs) { @@ -1972,6 +2167,9 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; + /* First parameter is current MCS, second one is demanded_mcs */ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 6); @@ -1981,6 +2179,38 @@ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 9); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 7, 5); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 9, 6); + + printf("=== end %s ===\n", __func__); +} + +static void test_tbf_egprs_spb_dl(void) +{ + BTS the_bts; + gprs_rlcmac_bts *bts; + uint8_t ts_no = 4; + int i, j; + + printf("=== start %s ===\n", __func__); + + bts = the_bts.bts_data(); + bts->cs_downgrade_threshold = 0; + setup_bts(&the_bts, ts_no); + bts->dl_tbf_idle_msec = 200; + bts->egprs_enabled = 1; + + /* ARQ I resegmentation support */ + bts->dl_arq_type = EGPRS_ARQ1; + + /* + * First parameter is current MCS, second one is demanded_mcs + * currently only MCS5->MCS2, MCS6->3, MCS4->MCS1 is tested in UT + * rest scenarios has been integration tested + */ + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 6, 3); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 5, 2); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 4, 1); + /* check MCS6->(MCS3+MCS3)->MCS6 case */ + egprs_spb_to_normal_validation(&the_bts, 6, 3); printf("=== end %s ===\n", __func__); } @@ -1999,6 +2229,8 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; for (i = 1; i <= 9; i++) establish_and_use_egprs_dl_tbf(&the_bts, i); @@ -2071,6 +2303,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_egprs_spb_dl(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..7b3f339 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -72,6 +72,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -81,6 +82,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -157,6 +159,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -166,6 +169,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -242,6 +246,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -251,6 +256,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -259,6 +265,7 @@ - Sending new block at BSN 2, CS=CS-1 -- Chunk with length 160 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=13 block=3 data=07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b @@ -267,6 +274,7 @@ - Sending new block at BSN 3, CS=CS-1 -- Chunk with length 140 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=17 block=4 data=07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @@ -275,6 +283,7 @@ - Sending new block at BSN 4, CS=CS-1 -- Chunk with length 120 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=21 block=5 data=07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 @@ -283,6 +292,7 @@ - Sending new block at BSN 5, CS=CS-1 -- Chunk with length 100 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=26 block=6 data=07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 @@ -291,6 +301,7 @@ - Sending new block at BSN 6, CS=CS-1 -- Chunk with length 80 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=30 block=7 data=07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b @@ -299,6 +310,7 @@ - Sending new block at BSN 7, CS=CS-1 -- Chunk with length 60 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=34 block=8 data=07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f @@ -307,6 +319,7 @@ - Sending new block at BSN 8, CS=CS-1 -- Chunk with length 40 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=39 block=9 data=07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 @@ -315,6 +328,7 @@ - Sending new block at BSN 9, CS=CS-1 -- Chunk with length 20 would exactly fit into space (20): add length header with LI=0, to make frame extend to next block, and we are done data block (BSN 9, CS-1): 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=43 block=10 data=07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 @@ -326,6 +340,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=47 block=11 data=07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 @@ -334,6 +349,7 @@ - Sending new block at BSN 11, CS=CS-1 -- Chunk with length 182 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=52 block=0 data=07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 @@ -342,6 +358,7 @@ - Sending new block at BSN 12, CS=CS-1 -- Chunk with length 162 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=56 block=1 data=07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 @@ -350,6 +367,7 @@ - Sending new block at BSN 13, CS=CS-1 -- Chunk with length 142 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 13, CS-1): 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=60 block=2 data=07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d @@ -358,6 +376,7 @@ - Sending new block at BSN 14, CS=CS-1 -- Chunk with length 122 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=65 block=3 data=07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 @@ -366,6 +385,7 @@ - Sending new block at BSN 15, CS=CS-1 -- Chunk with length 102 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=69 block=4 data=07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 @@ -374,6 +394,7 @@ - Sending new block at BSN 16, CS=CS-1 -- Chunk with length 82 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=73 block=5 data=07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 @@ -382,6 +403,7 @@ - Sending new block at BSN 17, CS=CS-1 -- Chunk with length 62 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=78 block=6 data=07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d @@ -390,6 +412,7 @@ - Sending new block at BSN 18, CS=CS-1 -- Chunk with length 42 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=82 block=7 data=07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 @@ -398,6 +421,7 @@ - Sending new block at BSN 19, CS=CS-1 -- Chunk with length 22 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=86 block=8 data=07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 @@ -411,6 +435,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=16 data block (BSN 20, CS-1): 0a 41 c6 c7 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -449,6 +474,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 data block (BSN 21, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -468,6 +494,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 22, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FINISHED) @@ -1481,6 +1508,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 0, CS-1): 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 MSG = 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 @@ -1491,6 +1519,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 1, CS-1): 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 MSG = 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 @@ -1501,6 +1530,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FINISHED data block (BSN 2, CS-1): 4d 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling cannot be scheduled in this TS 7 (first control TS 4) @@ -1784,6 +1814,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=10 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 0, CS-4): 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654292 TS 7 @@ -1797,6 +1828,7 @@ TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) downlink (V(A)==0 .. V(S)==1) - Restarting at BSN 0, because all blocks have been transmitted. - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-4): 07 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 @@ -2365,6 +2397,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654279 block=10 data=00 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 @@ -2384,6 +2417,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -2406,6 +2440,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654288 block=0 data=00 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 @@ -2425,6 +2460,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654292 block=1 data=00 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2447,6 +2483,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654296 block=2 data=00 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c @@ -2466,6 +2503,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654301 block=3 data=00 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b @@ -2488,6 +2526,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 6, CS-1): 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654305 block=4 data=00 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 @@ -2507,6 +2546,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654309 block=5 data=00 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 @@ -2526,6 +2566,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654314 block=6 data=00 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 @@ -2548,6 +2589,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654318 block=7 data=00 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 @@ -2567,6 +2609,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654322 block=8 data=00 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2589,6 +2632,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654327 block=9 data=00 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c @@ -2608,6 +2652,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654331 block=10 data=00 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b @@ -2630,6 +2675,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 13, CS-1): 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654335 block=11 data=00 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 @@ -2649,6 +2695,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654340 block=0 data=00 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 @@ -2668,6 +2715,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654344 block=1 data=00 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 @@ -2690,6 +2738,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654348 block=2 data=00 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 @@ -2709,6 +2758,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654353 block=3 data=00 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2731,6 +2781,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654357 block=4 data=00 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c @@ -2750,6 +2801,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654361 block=5 data=00 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b @@ -2772,6 +2824,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 20, CS-1): 16 35 45 54 20 32 38 4c 4c 43 20 50 41 43 4b 45 54 20 32 39 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because 20 blocks sent. TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW): Scheduling polling at FN 2654379 TS 7 @@ -2795,6 +2848,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 21, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) msg block (BSN 21, CS-1): 07 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654370 block=7 data=00 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 @@ -2814,6 +2868,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 22, CS-1): 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) msg block (BSN 22, CS-1): 07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654374 block=8 data=07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 @@ -2836,6 +2891,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 23, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) msg block (BSN 23, CS-1): 07 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654379 block=9 data=00 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 @@ -2855,6 +2911,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 24, CS-1): 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) msg block (BSN 24, CS-1): 07 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654383 block=10 data=00 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2877,6 +2934,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 25, CS-1): 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 25 BSN2 -1) - Copying data unit 0 (BSN 25) msg block (BSN 25, CS-1): 07 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654387 block=11 data=00 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c @@ -2896,6 +2954,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 26, CS-1): 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 26 BSN2 -1) - Copying data unit 0 (BSN 26) msg block (BSN 26, CS-1): 07 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654392 block=0 data=00 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b @@ -2918,6 +2977,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 27, CS-1): 16 35 45 54 20 33 38 4c 4c 43 20 50 41 43 4b 45 54 20 33 39 +- need_padding 0 spb_status 0 spb 0(BSN1 27 BSN2 -1) - Copying data unit 0 (BSN 27) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) @@ -3028,6 +3088,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654405 block=3 data=00 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 @@ -3047,6 +3108,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654409 block=4 data=00 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 @@ -3066,6 +3128,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (16) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654413 block=5 data=00 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 @@ -3085,6 +3148,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (14) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654418 block=6 data=00 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 @@ -3104,6 +3168,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654422 block=7 data=00 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -3123,6 +3188,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654426 block=8 data=00 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 @@ -3142,6 +3208,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654431 block=9 data=00 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b @@ -3161,6 +3228,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654435 block=10 data=00 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 @@ -3180,6 +3248,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654439 block=11 data=00 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 @@ -3199,6 +3268,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654444 block=0 data=00 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c @@ -3218,6 +3288,7 @@ Complete DL frame for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=21 TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 10, CS-1): 4d 43 20 50 41 43 4b 45 54 20 30 39 20 28 54 42 46 20 32 29 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654461 TS 7 @@ -3698,6 +3769,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 0, MCS-1): 14 15 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3711,6 +3783,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3721,6 +3794,7 @@ - Sending new block at BSN 2, CS=MCS-1 -- Chunk with length 490 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3731,6 +3805,7 @@ - Sending new block at BSN 3, CS=MCS-1 -- Chunk with length 468 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3741,6 +3816,7 @@ - Sending new block at BSN 4, CS=MCS-1 -- Chunk with length 446 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3751,6 +3827,7 @@ - Sending new block at BSN 5, CS=MCS-1 -- Chunk with length 424 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3761,6 +3838,7 @@ - Sending new block at BSN 6, CS=MCS-1 -- Chunk with length 402 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3771,6 +3849,7 @@ - Sending new block at BSN 7, CS=MCS-1 -- Chunk with length 380 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3781,6 +3860,7 @@ - Sending new block at BSN 8, CS=MCS-1 -- Chunk with length 358 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3791,6 +3871,7 @@ - Sending new block at BSN 9, CS=MCS-1 -- Chunk with length 336 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3801,6 +3882,7 @@ - Sending new block at BSN 10, CS=MCS-1 -- Chunk with length 314 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3811,6 +3893,7 @@ - Sending new block at BSN 11, CS=MCS-1 -- Chunk with length 292 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3821,6 +3904,7 @@ - Sending new block at BSN 12, CS=MCS-1 -- Chunk with length 270 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3831,6 +3915,7 @@ - Sending new block at BSN 13, CS=MCS-1 -- Chunk with length 248 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3841,6 +3926,7 @@ - Sending new block at BSN 14, CS=MCS-1 -- Chunk with length 226 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3851,6 +3937,7 @@ - Sending new block at BSN 15, CS=MCS-1 -- Chunk with length 204 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3861,6 +3948,7 @@ - Sending new block at BSN 16, CS=MCS-1 -- Chunk with length 182 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3871,6 +3959,7 @@ - Sending new block at BSN 17, CS=MCS-1 -- Chunk with length 160 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3881,6 +3970,7 @@ - Sending new block at BSN 18, CS=MCS-1 -- Chunk with length 138 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3891,6 +3981,7 @@ - Sending new block at BSN 19, CS=MCS-1 -- Chunk with length 116 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 19, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3901,6 +3992,7 @@ - Sending new block at BSN 20, CS=MCS-1 -- Chunk with length 94 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 20, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3911,6 +4003,7 @@ - Sending new block at BSN 21, CS=MCS-1 -- Chunk with length 72 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 21, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3921,6 +4014,7 @@ - Sending new block at BSN 22, CS=MCS-1 -- Chunk with length 50 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 22, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3931,6 +4025,7 @@ - Sending new block at BSN 23, CS=MCS-1 -- Chunk with length 28 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 23, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3946,6 +4041,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 24, MCS-1): 0c 1d 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4006,6 +4102,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=16 data block (BSN 0, MCS-2): 14 21 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4019,6 +4116,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4029,6 +4127,7 @@ - Sending new block at BSN 2, CS=MCS-2 -- Chunk with length 484 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4039,6 +4138,7 @@ - Sending new block at BSN 3, CS=MCS-2 -- Chunk with length 456 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4049,6 +4149,7 @@ - Sending new block at BSN 4, CS=MCS-2 -- Chunk with length 428 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4059,6 +4160,7 @@ - Sending new block at BSN 5, CS=MCS-2 -- Chunk with length 400 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4069,6 +4171,7 @@ - Sending new block at BSN 6, CS=MCS-2 -- Chunk with length 372 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4079,6 +4182,7 @@ - Sending new block at BSN 7, CS=MCS-2 -- Chunk with length 344 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4089,6 +4193,7 @@ - Sending new block at BSN 8, CS=MCS-2 -- Chunk with length 316 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4099,6 +4204,7 @@ - Sending new block at BSN 9, CS=MCS-2 -- Chunk with length 288 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4109,6 +4215,7 @@ - Sending new block at BSN 10, CS=MCS-2 -- Chunk with length 260 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4119,6 +4226,7 @@ - Sending new block at BSN 11, CS=MCS-2 -- Chunk with length 232 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4129,6 +4237,7 @@ - Sending new block at BSN 12, CS=MCS-2 -- Chunk with length 204 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4139,6 +4248,7 @@ - Sending new block at BSN 13, CS=MCS-2 -- Chunk with length 176 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4149,6 +4259,7 @@ - Sending new block at BSN 14, CS=MCS-2 -- Chunk with length 148 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4159,6 +4270,7 @@ - Sending new block at BSN 15, CS=MCS-2 -- Chunk with length 120 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4169,6 +4281,7 @@ - Sending new block at BSN 16, CS=MCS-2 -- Chunk with length 92 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4179,6 +4292,7 @@ - Sending new block at BSN 17, CS=MCS-2 -- Chunk with length 64 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4189,6 +4303,7 @@ - Sending new block at BSN 18, CS=MCS-2 -- Chunk with length 36 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4204,6 +4319,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=18 data block (BSN 19, MCS-2): 10 25 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4264,6 +4380,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=25 data block (BSN 0, MCS-3): 14 33 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4277,6 +4394,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4287,6 +4405,7 @@ - Sending new block at BSN 2, CS=MCS-3 -- Chunk with length 475 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4297,6 +4416,7 @@ - Sending new block at BSN 3, CS=MCS-3 -- Chunk with length 438 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4307,6 +4427,7 @@ - Sending new block at BSN 4, CS=MCS-3 -- Chunk with length 401 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4317,6 +4438,7 @@ - Sending new block at BSN 5, CS=MCS-3 -- Chunk with length 364 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4327,6 +4449,7 @@ - Sending new block at BSN 6, CS=MCS-3 -- Chunk with length 327 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4337,6 +4460,7 @@ - Sending new block at BSN 7, CS=MCS-3 -- Chunk with length 290 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4347,6 +4471,7 @@ - Sending new block at BSN 8, CS=MCS-3 -- Chunk with length 253 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4357,6 +4482,7 @@ - Sending new block at BSN 9, CS=MCS-3 -- Chunk with length 216 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4367,6 +4493,7 @@ - Sending new block at BSN 10, CS=MCS-3 -- Chunk with length 179 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4377,6 +4504,7 @@ - Sending new block at BSN 11, CS=MCS-3 -- Chunk with length 142 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4387,6 +4515,7 @@ - Sending new block at BSN 12, CS=MCS-3 -- Chunk with length 105 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4397,6 +4526,7 @@ - Sending new block at BSN 13, CS=MCS-3 -- Chunk with length 68 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4410,6 +4540,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-3): 3f 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4425,6 +4556,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=34 data block (BSN 15, MCS-3): 02 45 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4485,6 +4617,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=32 data block (BSN 0, MCS-4): 14 41 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4498,6 +4631,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4508,6 +4642,7 @@ - Sending new block at BSN 2, CS=MCS-4 -- Chunk with length 468 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4518,6 +4653,7 @@ - Sending new block at BSN 3, CS=MCS-4 -- Chunk with length 424 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4528,6 +4664,7 @@ - Sending new block at BSN 4, CS=MCS-4 -- Chunk with length 380 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4538,6 +4675,7 @@ - Sending new block at BSN 5, CS=MCS-4 -- Chunk with length 336 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4548,6 +4686,7 @@ - Sending new block at BSN 6, CS=MCS-4 -- Chunk with length 292 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4558,6 +4697,7 @@ - Sending new block at BSN 7, CS=MCS-4 -- Chunk with length 248 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4568,6 +4708,7 @@ - Sending new block at BSN 8, CS=MCS-4 -- Chunk with length 204 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4578,6 +4719,7 @@ - Sending new block at BSN 9, CS=MCS-4 -- Chunk with length 160 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4588,6 +4730,7 @@ - Sending new block at BSN 10, CS=MCS-4 -- Chunk with length 116 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4598,6 +4741,7 @@ - Sending new block at BSN 11, CS=MCS-4 -- Chunk with length 72 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4613,6 +4757,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 12, MCS-4): 38 1d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4673,6 +4818,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-5): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4686,6 +4832,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4696,6 +4843,7 @@ - Sending new block at BSN 2, CS=MCS-5 -- Chunk with length 456 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4706,6 +4854,7 @@ - Sending new block at BSN 3, CS=MCS-5 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4716,6 +4865,7 @@ - Sending new block at BSN 4, CS=MCS-5 -- Chunk with length 344 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4726,6 +4876,7 @@ - Sending new block at BSN 5, CS=MCS-5 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4736,6 +4887,7 @@ - Sending new block at BSN 6, CS=MCS-5 -- Chunk with length 232 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4746,6 +4898,7 @@ - Sending new block at BSN 7, CS=MCS-5 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4756,6 +4909,7 @@ - Sending new block at BSN 8, CS=MCS-5 -- Chunk with length 120 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4766,6 +4920,7 @@ - Sending new block at BSN 9, CS=MCS-5 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4781,6 +4936,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-5): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4841,6 +4997,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-6): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4854,6 +5011,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4864,6 +5022,7 @@ - Sending new block at BSN 2, CS=MCS-6 -- Chunk with length 438 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4874,6 +5033,7 @@ - Sending new block at BSN 3, CS=MCS-6 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4884,6 +5044,7 @@ - Sending new block at BSN 4, CS=MCS-6 -- Chunk with length 290 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4894,6 +5055,7 @@ - Sending new block at BSN 5, CS=MCS-6 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4904,6 +5066,7 @@ - Sending new block at BSN 6, CS=MCS-6 -- Chunk with length 142 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4917,6 +5080,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-6): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4932,6 +5096,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-6): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4993,6 +5158,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-7): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5002,12 +5168,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(7) last_mcs(5) demanded_mcs(7)cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-7 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5022,6 +5189,7 @@ - Sending new block at BSN 3, CS=MCS-7 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5036,6 +5204,7 @@ - Sending new block at BSN 5, CS=MCS-7 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5050,6 +5219,7 @@ - Sending new block at BSN 7, CS=MCS-7 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5064,6 +5234,7 @@ - Sending new block at BSN 9, CS=MCS-7 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 9) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5081,6 +5252,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-7): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5142,6 +5314,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=56 data block (BSN 0, MCS-8): 14 71 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5152,12 +5325,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(8) demanded_mcs(8) cs_trans(8) +- initial_cs_dl(8) last_mcs(8) demanded_mcs(8)cs_trans(8) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-8 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5172,6 +5346,7 @@ - Sending new block at BSN 3, CS=MCS-8 -- Chunk with length 376 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5186,6 +5361,7 @@ - Sending new block at BSN 5, CS=MCS-8 -- Chunk with length 240 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5200,6 +5376,7 @@ - Sending new block at BSN 7, CS=MCS-8 -- Chunk with length 104 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5217,6 +5394,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=30 data block (BSN 8, MCS-8): 48 3d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5279,6 +5457,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-9): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5288,12 +5467,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(9) last_mcs(6) demanded_mcs(9)cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-9 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5308,6 +5488,7 @@ - Sending new block at BSN 3, CS=MCS-9 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5322,6 +5503,7 @@ - Sending new block at BSN 5, CS=MCS-9 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5339,6 +5521,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-9): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5356,6 +5539,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-9): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5402,11 +5586,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(6)cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5450,11 +5636,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 96 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(1) demanded_mcs(1) cs_trans(1) +- initial_cs_dl(1) last_mcs(1) demanded_mcs(1)cs_trans(1) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 98 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5498,11 +5686,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-2): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 92 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(2) demanded_mcs(2) cs_trans(2) +- initial_cs_dl(2) last_mcs(2) demanded_mcs(2)cs_trans(2) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 94 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5546,6 +5736,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5557,6 +5748,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-5): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5564,10 +5756,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-5): 0f 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7)cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7)cs_trans(7) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-7): 07 00 00 02 c0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 @@ -5612,6 +5805,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5623,6 +5817,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-6): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5630,10 +5825,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-6): 0f 40 00 00 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9)cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9)cs_trans(9) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-9): 07 00 00 02 28 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 @@ -5686,6 +5882,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-7): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5694,13 +5891,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-7): 0f 00 00 02 a0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5)cs_trans(5) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5)cs_trans(5) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-5): 07 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5752,6 +5951,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-9): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5760,13 +5960,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-9): 0f 00 00 02 00 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6)cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6)cs_trans(6) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-6): 07 40 00 02 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5780,3 +5982,233 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-5 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(2)cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 d2 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(2) demanded_mcs(2)cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 f2 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-4 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (44) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-4): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-4): 07 00 00 80 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(4) demanded_mcs(1)cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 d6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(1) demanded_mcs(1)cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 f6 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(6)cs_trans(6) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 2 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..c38417d 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,9 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_egprs_spb_dl === +Testing retx for MCS 6 to reseg_mcs 3 +Testing retx for MCS 5 to reseg_mcs 2 +Testing retx for MCS 4 to reseg_mcs 1 +Testing retx for MCS 6 to reseg_mcs 3 +=== end test_tbf_egprs_spb_dl === -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 6 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Wed Aug 10 07:18:36 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Wed, 10 Aug 2016 07:18:36 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 6: Code-Review-1 (2 comments) https://gerrit.osmocom.org/#/c/655/6/src/pcu_vty.c File src/pcu_vty.c: PS6, Line 490: <0-1> [<0-1>] * why is there a second optional argument that is not used in the code? * when the choice os only 0 or 1, better to use (0|1) instead of <0-1>. This way you can document each choice value separately for proper interactive context-sensitive help. Line 493: "0:Reseg, 1:no Reseg") have you seen this syntax/description for help used anywhere else in the code? if so, please report it to our attention. -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 6 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Wed Aug 10 07:19:58 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Wed, 10 Aug 2016 07:19:58 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 6: (1 comment) https://gerrit.osmocom.org/#/c/655/6/src/pcu_vty.c File src/pcu_vty.c: PS6, Line 133: why are you putting a space before the end-of-line? Which part of the code teached you to do so? Please always follow what all other related/similar code does. -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 6 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Wed Aug 10 07:21:36 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Wed, 10 Aug 2016 07:21:36 +0000 Subject: [PATCH] osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/655 to look at the new patch set (#7). Modify EGPRS DL TBF flow to support SPB Modify the EGPRS DL TBF flow to support Split block during Retx. This patch will also Upgrade the test suite with test cases to validate the EGPRS Downlink SPB for Retransmission Scenarios like MCS6->MCS3, MCS4->MCS1, MCS5->MCS2, MCS9->MCS3 MCS7->MCS2, MCS8->MCS3 have been simulated and Integration tested in NuRAN 1.0 hardware thoroughly. Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 --- M src/gprs_coding_scheme.h M src/pcu_main.cpp M src/pcu_vty.c M src/rlc.cpp M src/rlc.h M src/tbf.h M src/tbf_dl.cpp M tests/edge/EdgeTest.cpp M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 11 files changed, 950 insertions(+), 77 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/55/655/7 diff --git a/src/gprs_coding_scheme.h b/src/gprs_coding_scheme.h index 60a8e79..3b15372 100644 --- a/src/gprs_coding_scheme.h +++ b/src/gprs_coding_scheme.h @@ -113,7 +113,8 @@ static const char *modeName(Mode mode); static Scheme get_retx_mcs(const GprsCodingScheme mcs, - const GprsCodingScheme retx_mcs); + const GprsCodingScheme retx_mcs, + const unsigned arq_type); static enum Scheme egprs_mcs_retx_tbl[MAX_NUM_ARQ] [MAX_NUM_MCS][MAX_NUM_MCS]; @@ -232,8 +233,9 @@ } inline GprsCodingScheme::Scheme GprsCodingScheme::get_retx_mcs( const GprsCodingScheme mcs, - const GprsCodingScheme demanded_mcs) + const GprsCodingScheme demanded_mcs, + const unsigned arq_type) { - return egprs_mcs_retx_tbl[EGPRS_ARQ2][mcs.to_num() - 1] + return egprs_mcs_retx_tbl[arq_type][mcs.to_num() - 1] [demanded_mcs.to_num() - 1]; } diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2d86cda..e34d534 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -210,6 +210,12 @@ bts->dl_tbf_idle_msec = 2000; bts->llc_idle_ack_csec = 10; + /* + * By default resegmentation is supported in DL + * can also be configured through VTY + */ + bts->dl_arq_type = EGPRS_ARQ1; + msgb_set_talloc_ctx(tall_pcu_ctx); osmo_init_logging(&gprs_log_info); diff --git a/src/pcu_vty.c b/src/pcu_vty.c index 58fea99..cc25812 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -129,6 +129,9 @@ vty_out(vty, " window-size %d %d%s", bts->ws_base, bts->ws_pdch, VTY_NEWLINE); + if (bts->dl_arq_type) + vty_out(vty, " dl arq %d%s", bts->dl_arq_type, VTY_NEWLINE); + if (bts->force_llc_lifetime == 0xffff) vty_out(vty, " queue lifetime infinite%s", VTY_NEWLINE); else if (bts->force_llc_lifetime) @@ -477,6 +480,22 @@ bts->max_mcs_dl = 0; bts->max_mcs_ul = 0; + return CMD_SUCCESS; +} + +#define EGPRS_DL_ARQ_STR "DL ARQ TYPE (EGPRS)\n" + +DEFUN(cfg_pcu_dl_arq_type, + cfg_pcu_dl_arq_cmd, + "dl arq <0-1> [<0-1>]", + EGPRS_DL_ARQ_STR + "Initial ARQ value to be used is (default 0:Reseg)\n" + "0:Reseg, 1:no Reseg") +{ + struct gprs_rlcmac_bts *bts = bts_main_data(); + uint8_t dl_arq_type = atoi(argv[0]); + + bts->dl_arq_type = dl_arq_type; return CMD_SUCCESS; } @@ -954,6 +973,7 @@ install_element(PCU_NODE, &cfg_pcu_no_cs_downgrade_thrsh_cmd); install_element(PCU_NODE, &cfg_pcu_cs_lqual_ranges_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_cmd); + install_element(PCU_NODE, &cfg_pcu_dl_arq_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_max_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_max_cmd); diff --git a/src/rlc.cpp b/src/rlc.cpp index 6770043..8da96f7 100644 --- a/src/rlc.cpp +++ b/src/rlc.cpp @@ -285,7 +285,8 @@ } static void gprs_rlc_data_header_init(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding, unsigned int header_bits) + GprsCodingScheme cs, bool with_padding, unsigned int header_bits, + const unsigned int spb) { unsigned int i; unsigned int padding_bits = with_padding ? cs.optionalPaddingBits() : 0; @@ -300,7 +301,7 @@ for (i = 0; i < rlc->num_data_blocks; i++) { gprs_rlc_data_block_info_init(&rlc->block_info[i], cs, - with_padding); + with_padding, spb); rlc->data_offs_bits[i] = header_bits + padding_bits + @@ -310,21 +311,25 @@ } void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsDL()); + cs.numDataHeaderBitsDL(), spb); } void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding) { + /* + * last parameter is sent as 0 since common function used + * for both DL and UL + */ return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsUL()); + cs.numDataHeaderBitsUL(), 0); } void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { unsigned int data_len = cs.maxDataBlockBytes(); if (with_padding) @@ -336,7 +341,7 @@ rdbi->e = 1; rdbi->cv = 15; rdbi->pi = 0; - rdbi->spb = 0; + rdbi->spb = spb; } unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, @@ -411,8 +416,17 @@ enum egprs_puncturing_values gprs_get_punct_scheme( enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current) + const GprsCodingScheme &cs_current, + const unsigned int spb) { + + /* + * If it is second segment of the block + * dont change the puncturing scheme + */ + if (spb == 3) + return punct; + /* TS 44.060 9.3.2.1.1 */ if ((GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS9) && (GprsCodingScheme::Scheme(cs_current) == GprsCodingScheme::MCS6)) { diff --git a/src/rlc.h b/src/rlc.h index 539b30b..66faf6f 100644 --- a/src/rlc.h +++ b/src/rlc.h @@ -206,18 +206,19 @@ }; void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding); void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, enum egprs_puncturing_values punct, enum egprs_puncturing_values punct2, int with_padding); void gprs_rlc_mcs_cps_decode(unsigned int cps, GprsCodingScheme cs, int *punct, int *punct2, int *with_padding); enum egprs_puncturing_values gprs_get_punct_scheme(enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current_trans); + const GprsCodingScheme &cs_current_trans, + const unsigned int spb); void gprs_update_punct_scheme(enum egprs_puncturing_values *punct, const GprsCodingScheme &cs); /* diff --git a/src/tbf.h b/src/tbf.h index 1bd7878..969836b 100644 --- a/src/tbf.h +++ b/src/tbf.h @@ -421,6 +421,11 @@ int analyse_errors(char *show_rbb, uint8_t ssn, ana_result *res); void schedule_next_frame(); + enum egprs_rlc_dl_reseg_bsn_state egprs_dl_get_data_buffer + (int bsn, uint8_t **block_data); + unsigned int get_egprs_dl_spb_status(int bsn); + unsigned int get_egprs_dl_spb_value(int bsn); + struct osmo_timer_list m_llc_timer; }; diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp index 07a747a..0395ed0 100644 --- a/src/tbf_dl.cpp +++ b/src/tbf_dl.cpp @@ -375,21 +375,27 @@ return -1; if (is_egprs_enabled()) { + /* Table 8.1.1.2 and Table 8.1.1.1 of 44.060 */ m_rlc.block(bsn)->cs_current_trans = - GprsCodingScheme::get_retx_mcs( - m_rlc.block(bsn)->cs_last, ms()->current_cs_dl()); + GprsCodingScheme::get_retx_mcs( + m_rlc.block(bsn)->cs_init, + ms()->current_cs_dl(), + bts->bts_data()->dl_arq_type); LOGP(DRLCMACDL, LOGL_DEBUG, - "- current_cs_dl(%d) demanded_mcs(%d) cs_trans(%d)\n", + "- initial_cs_dl(%d) last_mcs(%d) demanded_mcs(%d)" + "cs_trans(%d) arq_type(%d) bsn(%d)\n", + m_rlc.block(bsn)->cs_init.to_num(), m_rlc.block(bsn)->cs_last.to_num(), ms()->current_cs_dl().to_num(), - m_rlc.block(bsn)->cs_current_trans.to_num()); + m_rlc.block(bsn)->cs_current_trans.to_num(), + bts->bts_data()->dl_arq_type, bsn); /* TODO: Need to remove this check when MCS-8 -> MCS-6 * transistion is handled. * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 */ - if (m_rlc.block(bsn)->cs_last == GprsCodingScheme::MCS8) + if (m_rlc.block(bsn)->cs_init == GprsCodingScheme::MCS8) m_rlc.block(bsn)->cs_current_trans = GprsCodingScheme::MCS8; } else @@ -523,6 +529,11 @@ data = rlc_data->prepare(block_data_len); rlc_data->cs_last = cs; rlc_data->cs_current_trans = cs; + + /* Initialise the variable related to DL SPB */ + rlc_data->spb_status.block_status_dl = EGPRS_RESEG_DL_DEFAULT; + rlc_data->cs_init = cs; + rlc_data->len = block_data_len; rdbi = &(rlc_data->block_info); @@ -616,6 +627,7 @@ unsigned num_bsns; enum egprs_puncturing_values punct[ARRAY_SIZE(rlc.block_info)]; bool need_padding = false; + unsigned int spb = 0; /* * TODO: This is an experimental work-around to put 2 BSN into @@ -626,6 +638,7 @@ * the current limit. */ cs = m_rlc.block(index)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(index)->cs_init; bsns[0] = index; num_bsns = 1; @@ -634,7 +647,19 @@ num_bsns += 1; } - if (num_bsns == 1) { + /* + * if the intial mcs is 8 and retransmission mcs is either 6 or 3 + * we have to include the padding of 6 octets in first segment + */ + if ((GprsCodingScheme::Scheme(cs_init) == GprsCodingScheme::MCS8) && + (GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS6 || + GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS3)) { + if ((get_egprs_dl_spb_status(index) == + EGPRS_RESEG_DL_DEFAULT) || + (get_egprs_dl_spb_status(index) == + EGPRS_RESEG_SECOND_SEG_SENT)) + need_padding = true; + } else if (num_bsns == 1) { /* TODO: remove the conditional when MCS-6 padding isn't * failing to be decoded by MEs anymore */ /* TODO: support of MCS-8 -> MCS-6 transition should be @@ -646,7 +671,14 @@ cs.decToSingleBlock(&need_padding); } - gprs_rlc_data_info_init_dl(&rlc, cs, need_padding); + spb = get_egprs_dl_spb_value(index); + + LOGP(DRLCMACDL, LOGL_DEBUG, "- need_padding %d spb_status %d spb %d" + "(BSN1 %d BSN2 %d)\n", + need_padding, + get_egprs_dl_spb_status(index), spb, index, index2); + + gprs_rlc_data_info_init_dl(&rlc, cs, need_padding, spb); rlc.usf = 7; /* will be set at scheduler */ rlc.pr = 0; /* FIXME: power reduction */ @@ -665,10 +697,9 @@ data_block_idx++) { int bsn; - GprsCodingScheme cs_enc; uint8_t *block_data; gprs_rlc_data_block_info *rdbi, *block_info; - enum egprs_puncturing_values punct_scheme; + enum egprs_rlc_dl_reseg_bsn_state reseg_status; /* Check if there are more blocks than BSNs */ if (data_block_idx < num_bsns) @@ -676,38 +707,43 @@ else bsn = bsns[0]; - cs_enc = m_rlc.block(bsn)->cs_current_trans; - /* get data and header from current block */ - block_data = m_rlc.block(bsn)->block; - /* Get current puncturing scheme from block */ - punct_scheme = gprs_get_punct_scheme( + + m_rlc.block(bsn)->next_ps = gprs_get_punct_scheme( m_rlc.block(bsn)->next_ps, - m_rlc.block(bsn)->cs_last, cs); + m_rlc.block(bsn)->cs_last, cs, spb); if (cs.isEgprs()) { - OSMO_ASSERT(punct_scheme >= EGPRS_PS_1); - OSMO_ASSERT(punct_scheme <= EGPRS_PS_3); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps >= EGPRS_PS_1); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps <= EGPRS_PS_3); } - punct[data_block_idx] = punct_scheme; + punct[data_block_idx] = m_rlc.block(bsn)->next_ps; rdbi = &rlc.block_info[data_block_idx]; block_info = &m_rlc.block(bsn)->block_info; - if(rdbi->data_len != m_rlc.block(bsn)->len) { - LOGP(DRLCMACDL, LOGL_ERROR, - "ERROR: Expected len = %d for %s instead of " - "%d in data unit %d (BSN %d, %s)\n", - rdbi->data_len, cs.name(), m_rlc.block(bsn)->len, - data_block_idx, bsn, cs_enc.name()); - OSMO_ASSERT(rdbi->data_len == m_rlc.block(bsn)->len); - } - - /* TODO: Need to handle 2 same bsns - * in header type 1 + /* + * get data and header from current block + * function returns the reseg status */ - gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, - cs); + reseg_status = egprs_dl_get_data_buffer(bsn, &block_data); + m_rlc.block(bsn)->spb_status.block_status_dl = reseg_status; + + /* + * If it is first segment of the split block set the state of + * bsn to nacked. If it is the first segment dont update the + * next ps value of bsn. since next segment also needs same cps + */ + if (spb == 2) + m_window.m_v_b.mark_nacked(bsn); + else { + /* + * TODO: Need to handle 2 same bsns + * in header type 1 + */ + gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, + cs); + } m_rlc.block(bsn)->cs_last = cs; rdbi->e = block_info->e; @@ -1169,3 +1205,119 @@ keep_time_frames = msecs_to_frames(bts_data()->dl_tbf_idle_msec); return frames_since_last_drain(fn) <= keep_time_frames; } + +/* + * This function returns the pointer to data which needs + * to be copied. Also updates the status of the block related to + * Split block handling in the RLC/MAC block. + */ +enum egprs_rlc_dl_reseg_bsn_state + gprs_rlcmac_dl_tbf::egprs_dl_get_data_buffer(int bsn, + uint8_t **block_data) +{ + gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state *block_status_dl = + &rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + *block_data = &rlc_data->block[0]; + + /* + * Table 10.3a.0.1 of 44.060 + * MCS6,9: second segment starts at 74/2 = 37 + * MCS5,7: second segment starts at 56/2 = 28 + * MCS8: second segment starts at 31 + * MCS4: second segment starts at 44/2 = 22 + */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + if (*block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + switch (GprsCodingScheme::Scheme(cs_init)) { + case GprsCodingScheme::MCS6 : + case GprsCodingScheme::MCS9 : + *block_data = &rlc_data->block[37]; + break; + case GprsCodingScheme::MCS7 : + case GprsCodingScheme::MCS5 : + *block_data = &rlc_data->block[28]; + break; + case GprsCodingScheme::MCS8 : + *block_data = &rlc_data->block[31]; + break; + case GprsCodingScheme::MCS4 : + *block_data = &rlc_data->block[22]; + break; + default: + LOGP(DRLCMACDL, LOGL_ERROR, "Software error: " + "--%s hit invalid condition. headerType(%d) " + " blockstatus(%d) cs(%s) PLEASE FIX!\n", name(), + cs_current_trans.headerTypeData(), + *block_status_dl, cs_init.name()); + break; + + } + return EGPRS_RESEG_SECOND_SEG_SENT; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } + } + return EGPRS_RESEG_DL_DEFAULT; +} + +/* + * This function returns the status of split block + * for RLC/MAC block. + */ +unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_status(const int bsn) +{ + const gprs_rlc_data *rlc_data = m_rlc.block(bsn); + + return rlc_data->spb_status.block_status_dl; +} + +/* + * This function returns the spb value to be sent OTA + * for RLC/MAC block. + */ +unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_value(const int bsn) +{ + struct gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state block_status_dl = + rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + + /* Table 10.4.8b.1 of 44.060 */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + /* + * if we are sending the second segment the spb should be 3 + * other wise it should be 2 + */ + if (block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + return 3; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return 2; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return 2; + } + } + /* Non SPB cases 0 is reurned */ + return 0; +} diff --git a/tests/edge/EdgeTest.cpp b/tests/edge/EdgeTest.cpp index 807102c..9081d4d 100644 --- a/tests/edge/EdgeTest.cpp +++ b/tests/edge/EdgeTest.cpp @@ -517,7 +517,7 @@ /* TS 44.060, B.1 */ cs = GprsCodingScheme::CS4; - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -570,7 +570,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -592,7 +592,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -630,7 +630,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -669,7 +669,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -694,7 +694,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -719,7 +719,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -740,7 +740,7 @@ OSMO_ASSERT(data[0] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -777,7 +777,7 @@ cs = GprsCodingScheme::MCS4; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -835,7 +835,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -872,7 +872,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -923,7 +923,7 @@ OSMO_ASSERT(data[3] == 0); /* Block 3 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -967,7 +967,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -993,7 +993,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1020,7 +1020,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1074,7 +1074,7 @@ block_idx++) { struct gprs_rlc_data_info rlc; - gprs_rlc_data_info_init_dl(&rlc, cs, false); + gprs_rlc_data_info_init_dl(&rlc, cs, false, 0); memset(bits, pattern, sizeof(bits)); Decoding::rlc_copy_to_aligned_buffer( @@ -1118,12 +1118,14 @@ struct gprs_rlc_data_info rlc; printf("=== start %s ===\n", __func__); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::CS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::CS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 24); OSMO_ASSERT(rlc.block_info[0].data_len == 20); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::MCS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::MCS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 33); OSMO_ASSERT(rlc.block_info[0].data_len == 22); diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..18cc5cb 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -1814,6 +1814,201 @@ } +static void egprs_spb_to_normal_validation(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + uint16_t bsn1, bsn2, bsn3; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + struct gprs_rlc_dl_header_egprs_2 *egprs2; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + if ((mcs == 6) && (demanded_mcs == 3)) { + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + bsn1 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) + || (egprs2->bsn1_lo); + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(bsn1 == 0); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + bsn2 = (egprs3->bsn1_hi << 9) || (egprs3->bsn1_mid << 1) || + (egprs3->bsn1_lo); + OSMO_ASSERT(bsn2 == bsn1); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Handle (MCS3, MCS3) -> MCS6 case */ + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + mcs)); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs2->cps == 0); + bsn3 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) || + (egprs2->bsn1_lo); + OSMO_ASSERT(bsn3 == bsn2); + + tbf_cleanup(dl_tbf); + } +} +static void establish_and_use_egprs_dl_tbf_for_spb(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + /* TODO: Need to support of MCS8 -> MCS6 ->MCS3 transistion + * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 + * dated 2016-02-07 23:45:40 (UTC) + */ + if (((mcs == 5) && (demanded_mcs == 2)) || + ((mcs == 6) && (demanded_mcs == 3)) || + ((mcs == 4) && (demanded_mcs == 1))) { + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + tbf_cleanup(dl_tbf); + } +} + static void establish_and_use_egprs_dl_tbf_for_retx(BTS *the_bts, int mcs, int demanded_mcs) { @@ -1972,6 +2167,9 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; + /* First parameter is current MCS, second one is demanded_mcs */ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 6); @@ -1981,6 +2179,38 @@ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 9); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 7, 5); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 9, 6); + + printf("=== end %s ===\n", __func__); +} + +static void test_tbf_egprs_spb_dl(void) +{ + BTS the_bts; + gprs_rlcmac_bts *bts; + uint8_t ts_no = 4; + int i, j; + + printf("=== start %s ===\n", __func__); + + bts = the_bts.bts_data(); + bts->cs_downgrade_threshold = 0; + setup_bts(&the_bts, ts_no); + bts->dl_tbf_idle_msec = 200; + bts->egprs_enabled = 1; + + /* ARQ I resegmentation support */ + bts->dl_arq_type = EGPRS_ARQ1; + + /* + * First parameter is current MCS, second one is demanded_mcs + * currently only MCS5->MCS2, MCS6->3, MCS4->MCS1 is tested in UT + * rest scenarios has been integration tested + */ + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 6, 3); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 5, 2); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 4, 1); + /* check MCS6->(MCS3+MCS3)->MCS6 case */ + egprs_spb_to_normal_validation(&the_bts, 6, 3); printf("=== end %s ===\n", __func__); } @@ -1999,6 +2229,8 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; for (i = 1; i <= 9; i++) establish_and_use_egprs_dl_tbf(&the_bts, i); @@ -2071,6 +2303,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_egprs_spb_dl(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..7b3f339 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -72,6 +72,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -81,6 +82,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -157,6 +159,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -166,6 +169,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -242,6 +246,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -251,6 +256,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -259,6 +265,7 @@ - Sending new block at BSN 2, CS=CS-1 -- Chunk with length 160 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=13 block=3 data=07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b @@ -267,6 +274,7 @@ - Sending new block at BSN 3, CS=CS-1 -- Chunk with length 140 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=17 block=4 data=07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @@ -275,6 +283,7 @@ - Sending new block at BSN 4, CS=CS-1 -- Chunk with length 120 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=21 block=5 data=07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 @@ -283,6 +292,7 @@ - Sending new block at BSN 5, CS=CS-1 -- Chunk with length 100 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=26 block=6 data=07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 @@ -291,6 +301,7 @@ - Sending new block at BSN 6, CS=CS-1 -- Chunk with length 80 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=30 block=7 data=07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b @@ -299,6 +310,7 @@ - Sending new block at BSN 7, CS=CS-1 -- Chunk with length 60 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=34 block=8 data=07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f @@ -307,6 +319,7 @@ - Sending new block at BSN 8, CS=CS-1 -- Chunk with length 40 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=39 block=9 data=07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 @@ -315,6 +328,7 @@ - Sending new block at BSN 9, CS=CS-1 -- Chunk with length 20 would exactly fit into space (20): add length header with LI=0, to make frame extend to next block, and we are done data block (BSN 9, CS-1): 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=43 block=10 data=07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 @@ -326,6 +340,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=47 block=11 data=07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 @@ -334,6 +349,7 @@ - Sending new block at BSN 11, CS=CS-1 -- Chunk with length 182 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=52 block=0 data=07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 @@ -342,6 +358,7 @@ - Sending new block at BSN 12, CS=CS-1 -- Chunk with length 162 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=56 block=1 data=07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 @@ -350,6 +367,7 @@ - Sending new block at BSN 13, CS=CS-1 -- Chunk with length 142 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 13, CS-1): 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=60 block=2 data=07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d @@ -358,6 +376,7 @@ - Sending new block at BSN 14, CS=CS-1 -- Chunk with length 122 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=65 block=3 data=07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 @@ -366,6 +385,7 @@ - Sending new block at BSN 15, CS=CS-1 -- Chunk with length 102 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=69 block=4 data=07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 @@ -374,6 +394,7 @@ - Sending new block at BSN 16, CS=CS-1 -- Chunk with length 82 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=73 block=5 data=07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 @@ -382,6 +403,7 @@ - Sending new block at BSN 17, CS=CS-1 -- Chunk with length 62 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=78 block=6 data=07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d @@ -390,6 +412,7 @@ - Sending new block at BSN 18, CS=CS-1 -- Chunk with length 42 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=82 block=7 data=07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 @@ -398,6 +421,7 @@ - Sending new block at BSN 19, CS=CS-1 -- Chunk with length 22 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=86 block=8 data=07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 @@ -411,6 +435,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=16 data block (BSN 20, CS-1): 0a 41 c6 c7 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -449,6 +474,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 data block (BSN 21, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -468,6 +494,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 22, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FINISHED) @@ -1481,6 +1508,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 0, CS-1): 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 MSG = 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 @@ -1491,6 +1519,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 1, CS-1): 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 MSG = 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 @@ -1501,6 +1530,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FINISHED data block (BSN 2, CS-1): 4d 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling cannot be scheduled in this TS 7 (first control TS 4) @@ -1784,6 +1814,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=10 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 0, CS-4): 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654292 TS 7 @@ -1797,6 +1828,7 @@ TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) downlink (V(A)==0 .. V(S)==1) - Restarting at BSN 0, because all blocks have been transmitted. - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-4): 07 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 @@ -2365,6 +2397,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654279 block=10 data=00 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 @@ -2384,6 +2417,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -2406,6 +2440,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654288 block=0 data=00 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 @@ -2425,6 +2460,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654292 block=1 data=00 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2447,6 +2483,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654296 block=2 data=00 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c @@ -2466,6 +2503,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654301 block=3 data=00 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b @@ -2488,6 +2526,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 6, CS-1): 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654305 block=4 data=00 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 @@ -2507,6 +2546,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654309 block=5 data=00 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 @@ -2526,6 +2566,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654314 block=6 data=00 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 @@ -2548,6 +2589,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654318 block=7 data=00 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 @@ -2567,6 +2609,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654322 block=8 data=00 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2589,6 +2632,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654327 block=9 data=00 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c @@ -2608,6 +2652,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654331 block=10 data=00 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b @@ -2630,6 +2675,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 13, CS-1): 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654335 block=11 data=00 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 @@ -2649,6 +2695,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654340 block=0 data=00 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 @@ -2668,6 +2715,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654344 block=1 data=00 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 @@ -2690,6 +2738,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654348 block=2 data=00 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 @@ -2709,6 +2758,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654353 block=3 data=00 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2731,6 +2781,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654357 block=4 data=00 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c @@ -2750,6 +2801,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654361 block=5 data=00 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b @@ -2772,6 +2824,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 20, CS-1): 16 35 45 54 20 32 38 4c 4c 43 20 50 41 43 4b 45 54 20 32 39 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because 20 blocks sent. TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW): Scheduling polling at FN 2654379 TS 7 @@ -2795,6 +2848,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 21, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) msg block (BSN 21, CS-1): 07 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654370 block=7 data=00 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 @@ -2814,6 +2868,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 22, CS-1): 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) msg block (BSN 22, CS-1): 07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654374 block=8 data=07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 @@ -2836,6 +2891,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 23, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) msg block (BSN 23, CS-1): 07 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654379 block=9 data=00 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 @@ -2855,6 +2911,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 24, CS-1): 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) msg block (BSN 24, CS-1): 07 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654383 block=10 data=00 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2877,6 +2934,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 25, CS-1): 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 25 BSN2 -1) - Copying data unit 0 (BSN 25) msg block (BSN 25, CS-1): 07 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654387 block=11 data=00 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c @@ -2896,6 +2954,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 26, CS-1): 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 26 BSN2 -1) - Copying data unit 0 (BSN 26) msg block (BSN 26, CS-1): 07 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654392 block=0 data=00 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b @@ -2918,6 +2977,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 27, CS-1): 16 35 45 54 20 33 38 4c 4c 43 20 50 41 43 4b 45 54 20 33 39 +- need_padding 0 spb_status 0 spb 0(BSN1 27 BSN2 -1) - Copying data unit 0 (BSN 27) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) @@ -3028,6 +3088,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654405 block=3 data=00 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 @@ -3047,6 +3108,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654409 block=4 data=00 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 @@ -3066,6 +3128,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (16) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654413 block=5 data=00 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 @@ -3085,6 +3148,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (14) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654418 block=6 data=00 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 @@ -3104,6 +3168,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654422 block=7 data=00 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -3123,6 +3188,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654426 block=8 data=00 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 @@ -3142,6 +3208,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654431 block=9 data=00 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b @@ -3161,6 +3228,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654435 block=10 data=00 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 @@ -3180,6 +3248,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654439 block=11 data=00 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 @@ -3199,6 +3268,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654444 block=0 data=00 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c @@ -3218,6 +3288,7 @@ Complete DL frame for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=21 TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 10, CS-1): 4d 43 20 50 41 43 4b 45 54 20 30 39 20 28 54 42 46 20 32 29 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654461 TS 7 @@ -3698,6 +3769,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 0, MCS-1): 14 15 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3711,6 +3783,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3721,6 +3794,7 @@ - Sending new block at BSN 2, CS=MCS-1 -- Chunk with length 490 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3731,6 +3805,7 @@ - Sending new block at BSN 3, CS=MCS-1 -- Chunk with length 468 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3741,6 +3816,7 @@ - Sending new block at BSN 4, CS=MCS-1 -- Chunk with length 446 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3751,6 +3827,7 @@ - Sending new block at BSN 5, CS=MCS-1 -- Chunk with length 424 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3761,6 +3838,7 @@ - Sending new block at BSN 6, CS=MCS-1 -- Chunk with length 402 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3771,6 +3849,7 @@ - Sending new block at BSN 7, CS=MCS-1 -- Chunk with length 380 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3781,6 +3860,7 @@ - Sending new block at BSN 8, CS=MCS-1 -- Chunk with length 358 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3791,6 +3871,7 @@ - Sending new block at BSN 9, CS=MCS-1 -- Chunk with length 336 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3801,6 +3882,7 @@ - Sending new block at BSN 10, CS=MCS-1 -- Chunk with length 314 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3811,6 +3893,7 @@ - Sending new block at BSN 11, CS=MCS-1 -- Chunk with length 292 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3821,6 +3904,7 @@ - Sending new block at BSN 12, CS=MCS-1 -- Chunk with length 270 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3831,6 +3915,7 @@ - Sending new block at BSN 13, CS=MCS-1 -- Chunk with length 248 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3841,6 +3926,7 @@ - Sending new block at BSN 14, CS=MCS-1 -- Chunk with length 226 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3851,6 +3937,7 @@ - Sending new block at BSN 15, CS=MCS-1 -- Chunk with length 204 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3861,6 +3948,7 @@ - Sending new block at BSN 16, CS=MCS-1 -- Chunk with length 182 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3871,6 +3959,7 @@ - Sending new block at BSN 17, CS=MCS-1 -- Chunk with length 160 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3881,6 +3970,7 @@ - Sending new block at BSN 18, CS=MCS-1 -- Chunk with length 138 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3891,6 +3981,7 @@ - Sending new block at BSN 19, CS=MCS-1 -- Chunk with length 116 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 19, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3901,6 +3992,7 @@ - Sending new block at BSN 20, CS=MCS-1 -- Chunk with length 94 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 20, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3911,6 +4003,7 @@ - Sending new block at BSN 21, CS=MCS-1 -- Chunk with length 72 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 21, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3921,6 +4014,7 @@ - Sending new block at BSN 22, CS=MCS-1 -- Chunk with length 50 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 22, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3931,6 +4025,7 @@ - Sending new block at BSN 23, CS=MCS-1 -- Chunk with length 28 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 23, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3946,6 +4041,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 24, MCS-1): 0c 1d 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4006,6 +4102,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=16 data block (BSN 0, MCS-2): 14 21 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4019,6 +4116,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4029,6 +4127,7 @@ - Sending new block at BSN 2, CS=MCS-2 -- Chunk with length 484 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4039,6 +4138,7 @@ - Sending new block at BSN 3, CS=MCS-2 -- Chunk with length 456 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4049,6 +4149,7 @@ - Sending new block at BSN 4, CS=MCS-2 -- Chunk with length 428 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4059,6 +4160,7 @@ - Sending new block at BSN 5, CS=MCS-2 -- Chunk with length 400 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4069,6 +4171,7 @@ - Sending new block at BSN 6, CS=MCS-2 -- Chunk with length 372 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4079,6 +4182,7 @@ - Sending new block at BSN 7, CS=MCS-2 -- Chunk with length 344 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4089,6 +4193,7 @@ - Sending new block at BSN 8, CS=MCS-2 -- Chunk with length 316 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4099,6 +4204,7 @@ - Sending new block at BSN 9, CS=MCS-2 -- Chunk with length 288 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4109,6 +4215,7 @@ - Sending new block at BSN 10, CS=MCS-2 -- Chunk with length 260 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4119,6 +4226,7 @@ - Sending new block at BSN 11, CS=MCS-2 -- Chunk with length 232 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4129,6 +4237,7 @@ - Sending new block at BSN 12, CS=MCS-2 -- Chunk with length 204 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4139,6 +4248,7 @@ - Sending new block at BSN 13, CS=MCS-2 -- Chunk with length 176 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4149,6 +4259,7 @@ - Sending new block at BSN 14, CS=MCS-2 -- Chunk with length 148 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4159,6 +4270,7 @@ - Sending new block at BSN 15, CS=MCS-2 -- Chunk with length 120 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4169,6 +4281,7 @@ - Sending new block at BSN 16, CS=MCS-2 -- Chunk with length 92 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4179,6 +4292,7 @@ - Sending new block at BSN 17, CS=MCS-2 -- Chunk with length 64 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4189,6 +4303,7 @@ - Sending new block at BSN 18, CS=MCS-2 -- Chunk with length 36 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4204,6 +4319,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=18 data block (BSN 19, MCS-2): 10 25 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4264,6 +4380,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=25 data block (BSN 0, MCS-3): 14 33 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4277,6 +4394,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4287,6 +4405,7 @@ - Sending new block at BSN 2, CS=MCS-3 -- Chunk with length 475 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4297,6 +4416,7 @@ - Sending new block at BSN 3, CS=MCS-3 -- Chunk with length 438 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4307,6 +4427,7 @@ - Sending new block at BSN 4, CS=MCS-3 -- Chunk with length 401 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4317,6 +4438,7 @@ - Sending new block at BSN 5, CS=MCS-3 -- Chunk with length 364 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4327,6 +4449,7 @@ - Sending new block at BSN 6, CS=MCS-3 -- Chunk with length 327 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4337,6 +4460,7 @@ - Sending new block at BSN 7, CS=MCS-3 -- Chunk with length 290 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4347,6 +4471,7 @@ - Sending new block at BSN 8, CS=MCS-3 -- Chunk with length 253 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4357,6 +4482,7 @@ - Sending new block at BSN 9, CS=MCS-3 -- Chunk with length 216 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4367,6 +4493,7 @@ - Sending new block at BSN 10, CS=MCS-3 -- Chunk with length 179 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4377,6 +4504,7 @@ - Sending new block at BSN 11, CS=MCS-3 -- Chunk with length 142 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4387,6 +4515,7 @@ - Sending new block at BSN 12, CS=MCS-3 -- Chunk with length 105 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4397,6 +4526,7 @@ - Sending new block at BSN 13, CS=MCS-3 -- Chunk with length 68 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4410,6 +4540,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-3): 3f 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4425,6 +4556,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=34 data block (BSN 15, MCS-3): 02 45 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4485,6 +4617,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=32 data block (BSN 0, MCS-4): 14 41 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4498,6 +4631,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4508,6 +4642,7 @@ - Sending new block at BSN 2, CS=MCS-4 -- Chunk with length 468 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4518,6 +4653,7 @@ - Sending new block at BSN 3, CS=MCS-4 -- Chunk with length 424 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4528,6 +4664,7 @@ - Sending new block at BSN 4, CS=MCS-4 -- Chunk with length 380 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4538,6 +4675,7 @@ - Sending new block at BSN 5, CS=MCS-4 -- Chunk with length 336 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4548,6 +4686,7 @@ - Sending new block at BSN 6, CS=MCS-4 -- Chunk with length 292 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4558,6 +4697,7 @@ - Sending new block at BSN 7, CS=MCS-4 -- Chunk with length 248 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4568,6 +4708,7 @@ - Sending new block at BSN 8, CS=MCS-4 -- Chunk with length 204 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4578,6 +4719,7 @@ - Sending new block at BSN 9, CS=MCS-4 -- Chunk with length 160 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4588,6 +4730,7 @@ - Sending new block at BSN 10, CS=MCS-4 -- Chunk with length 116 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4598,6 +4741,7 @@ - Sending new block at BSN 11, CS=MCS-4 -- Chunk with length 72 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4613,6 +4757,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 12, MCS-4): 38 1d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4673,6 +4818,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-5): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4686,6 +4832,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4696,6 +4843,7 @@ - Sending new block at BSN 2, CS=MCS-5 -- Chunk with length 456 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4706,6 +4854,7 @@ - Sending new block at BSN 3, CS=MCS-5 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4716,6 +4865,7 @@ - Sending new block at BSN 4, CS=MCS-5 -- Chunk with length 344 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4726,6 +4876,7 @@ - Sending new block at BSN 5, CS=MCS-5 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4736,6 +4887,7 @@ - Sending new block at BSN 6, CS=MCS-5 -- Chunk with length 232 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4746,6 +4898,7 @@ - Sending new block at BSN 7, CS=MCS-5 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4756,6 +4909,7 @@ - Sending new block at BSN 8, CS=MCS-5 -- Chunk with length 120 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4766,6 +4920,7 @@ - Sending new block at BSN 9, CS=MCS-5 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4781,6 +4936,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-5): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4841,6 +4997,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-6): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4854,6 +5011,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4864,6 +5022,7 @@ - Sending new block at BSN 2, CS=MCS-6 -- Chunk with length 438 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4874,6 +5033,7 @@ - Sending new block at BSN 3, CS=MCS-6 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4884,6 +5044,7 @@ - Sending new block at BSN 4, CS=MCS-6 -- Chunk with length 290 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4894,6 +5055,7 @@ - Sending new block at BSN 5, CS=MCS-6 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4904,6 +5066,7 @@ - Sending new block at BSN 6, CS=MCS-6 -- Chunk with length 142 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4917,6 +5080,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-6): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4932,6 +5096,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-6): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4993,6 +5158,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-7): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5002,12 +5168,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(7) last_mcs(5) demanded_mcs(7)cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-7 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5022,6 +5189,7 @@ - Sending new block at BSN 3, CS=MCS-7 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5036,6 +5204,7 @@ - Sending new block at BSN 5, CS=MCS-7 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5050,6 +5219,7 @@ - Sending new block at BSN 7, CS=MCS-7 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5064,6 +5234,7 @@ - Sending new block at BSN 9, CS=MCS-7 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 9) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5081,6 +5252,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-7): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5142,6 +5314,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=56 data block (BSN 0, MCS-8): 14 71 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5152,12 +5325,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(8) demanded_mcs(8) cs_trans(8) +- initial_cs_dl(8) last_mcs(8) demanded_mcs(8)cs_trans(8) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-8 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5172,6 +5346,7 @@ - Sending new block at BSN 3, CS=MCS-8 -- Chunk with length 376 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5186,6 +5361,7 @@ - Sending new block at BSN 5, CS=MCS-8 -- Chunk with length 240 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5200,6 +5376,7 @@ - Sending new block at BSN 7, CS=MCS-8 -- Chunk with length 104 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5217,6 +5394,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=30 data block (BSN 8, MCS-8): 48 3d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5279,6 +5457,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-9): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5288,12 +5467,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(9) last_mcs(6) demanded_mcs(9)cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-9 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5308,6 +5488,7 @@ - Sending new block at BSN 3, CS=MCS-9 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5322,6 +5503,7 @@ - Sending new block at BSN 5, CS=MCS-9 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5339,6 +5521,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-9): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5356,6 +5539,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-9): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5402,11 +5586,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(6)cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5450,11 +5636,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 96 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(1) demanded_mcs(1) cs_trans(1) +- initial_cs_dl(1) last_mcs(1) demanded_mcs(1)cs_trans(1) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 98 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5498,11 +5686,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-2): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 92 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(2) demanded_mcs(2) cs_trans(2) +- initial_cs_dl(2) last_mcs(2) demanded_mcs(2)cs_trans(2) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 94 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5546,6 +5736,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5557,6 +5748,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-5): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5564,10 +5756,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-5): 0f 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7)cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7)cs_trans(7) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-7): 07 00 00 02 c0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 @@ -5612,6 +5805,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5623,6 +5817,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-6): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5630,10 +5825,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-6): 0f 40 00 00 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9)cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9)cs_trans(9) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-9): 07 00 00 02 28 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 @@ -5686,6 +5882,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-7): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5694,13 +5891,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-7): 0f 00 00 02 a0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5)cs_trans(5) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5)cs_trans(5) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-5): 07 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5752,6 +5951,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-9): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5760,13 +5960,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-9): 0f 00 00 02 00 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6)cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6)cs_trans(6) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-6): 07 40 00 02 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5780,3 +5982,233 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-5 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(2)cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 d2 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(2) demanded_mcs(2)cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 f2 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-4 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (44) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-4): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-4): 07 00 00 80 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(4) demanded_mcs(1)cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 d6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(1) demanded_mcs(1)cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 f6 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(6)cs_trans(6) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 2 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..c38417d 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,9 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_egprs_spb_dl === +Testing retx for MCS 6 to reseg_mcs 3 +Testing retx for MCS 5 to reseg_mcs 2 +Testing retx for MCS 4 to reseg_mcs 1 +Testing retx for MCS 6 to reseg_mcs 3 +=== end test_tbf_egprs_spb_dl === -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 7 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Wed Aug 10 07:39:15 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Wed, 10 Aug 2016 07:39:15 +0000 Subject: [PATCH] osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/655 to look at the new patch set (#8). Modify EGPRS DL TBF flow to support SPB Modify the EGPRS DL TBF flow to support Split block during Retx. This patch will also Upgrade the test suite with test cases to validate the EGPRS Downlink SPB for Retransmission Scenarios like MCS6->MCS3, MCS4->MCS1, MCS5->MCS2, MCS9->MCS3 MCS7->MCS2, MCS8->MCS3 have been simulated and Integration tested in NuRAN 1.0 hardware thoroughly. Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 --- M src/gprs_coding_scheme.h M src/pcu_main.cpp M src/pcu_vty.c M src/rlc.cpp M src/rlc.h M src/tbf.h M src/tbf_dl.cpp M tests/edge/EdgeTest.cpp M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 11 files changed, 950 insertions(+), 77 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/55/655/8 diff --git a/src/gprs_coding_scheme.h b/src/gprs_coding_scheme.h index 60a8e79..3b15372 100644 --- a/src/gprs_coding_scheme.h +++ b/src/gprs_coding_scheme.h @@ -113,7 +113,8 @@ static const char *modeName(Mode mode); static Scheme get_retx_mcs(const GprsCodingScheme mcs, - const GprsCodingScheme retx_mcs); + const GprsCodingScheme retx_mcs, + const unsigned arq_type); static enum Scheme egprs_mcs_retx_tbl[MAX_NUM_ARQ] [MAX_NUM_MCS][MAX_NUM_MCS]; @@ -232,8 +233,9 @@ } inline GprsCodingScheme::Scheme GprsCodingScheme::get_retx_mcs( const GprsCodingScheme mcs, - const GprsCodingScheme demanded_mcs) + const GprsCodingScheme demanded_mcs, + const unsigned arq_type) { - return egprs_mcs_retx_tbl[EGPRS_ARQ2][mcs.to_num() - 1] + return egprs_mcs_retx_tbl[arq_type][mcs.to_num() - 1] [demanded_mcs.to_num() - 1]; } diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2d86cda..e34d534 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -210,6 +210,12 @@ bts->dl_tbf_idle_msec = 2000; bts->llc_idle_ack_csec = 10; + /* + * By default resegmentation is supported in DL + * can also be configured through VTY + */ + bts->dl_arq_type = EGPRS_ARQ1; + msgb_set_talloc_ctx(tall_pcu_ctx); osmo_init_logging(&gprs_log_info); diff --git a/src/pcu_vty.c b/src/pcu_vty.c index 58fea99..84d2d78 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -129,6 +129,9 @@ vty_out(vty, " window-size %d %d%s", bts->ws_base, bts->ws_pdch, VTY_NEWLINE); + if (bts->dl_arq_type) + vty_out(vty, " dl arq %d %s", bts->dl_arq_type, VTY_NEWLINE); + if (bts->force_llc_lifetime == 0xffff) vty_out(vty, " queue lifetime infinite%s", VTY_NEWLINE); else if (bts->force_llc_lifetime) @@ -477,6 +480,22 @@ bts->max_mcs_dl = 0; bts->max_mcs_ul = 0; + return CMD_SUCCESS; +} + +#define EGPRS_DL_ARQ_STR "DL ARQ TYPE (EGPRS)\n" + +DEFUN(cfg_pcu_dl_arq_type, + cfg_pcu_dl_arq_cmd, + "dl arq (0|1)", + EGPRS_DL_ARQ_STR + "enable DL SPB support\n" + "enable DL ARQ2 support") +{ + struct gprs_rlcmac_bts *bts = bts_main_data(); + uint8_t dl_arq_type = atoi(argv[0]); + + bts->dl_arq_type = dl_arq_type; return CMD_SUCCESS; } @@ -954,6 +973,7 @@ install_element(PCU_NODE, &cfg_pcu_no_cs_downgrade_thrsh_cmd); install_element(PCU_NODE, &cfg_pcu_cs_lqual_ranges_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_cmd); + install_element(PCU_NODE, &cfg_pcu_dl_arq_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_max_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_max_cmd); diff --git a/src/rlc.cpp b/src/rlc.cpp index 6770043..8da96f7 100644 --- a/src/rlc.cpp +++ b/src/rlc.cpp @@ -285,7 +285,8 @@ } static void gprs_rlc_data_header_init(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding, unsigned int header_bits) + GprsCodingScheme cs, bool with_padding, unsigned int header_bits, + const unsigned int spb) { unsigned int i; unsigned int padding_bits = with_padding ? cs.optionalPaddingBits() : 0; @@ -300,7 +301,7 @@ for (i = 0; i < rlc->num_data_blocks; i++) { gprs_rlc_data_block_info_init(&rlc->block_info[i], cs, - with_padding); + with_padding, spb); rlc->data_offs_bits[i] = header_bits + padding_bits + @@ -310,21 +311,25 @@ } void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsDL()); + cs.numDataHeaderBitsDL(), spb); } void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding) { + /* + * last parameter is sent as 0 since common function used + * for both DL and UL + */ return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsUL()); + cs.numDataHeaderBitsUL(), 0); } void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { unsigned int data_len = cs.maxDataBlockBytes(); if (with_padding) @@ -336,7 +341,7 @@ rdbi->e = 1; rdbi->cv = 15; rdbi->pi = 0; - rdbi->spb = 0; + rdbi->spb = spb; } unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, @@ -411,8 +416,17 @@ enum egprs_puncturing_values gprs_get_punct_scheme( enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current) + const GprsCodingScheme &cs_current, + const unsigned int spb) { + + /* + * If it is second segment of the block + * dont change the puncturing scheme + */ + if (spb == 3) + return punct; + /* TS 44.060 9.3.2.1.1 */ if ((GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS9) && (GprsCodingScheme::Scheme(cs_current) == GprsCodingScheme::MCS6)) { diff --git a/src/rlc.h b/src/rlc.h index 539b30b..66faf6f 100644 --- a/src/rlc.h +++ b/src/rlc.h @@ -206,18 +206,19 @@ }; void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding); void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, enum egprs_puncturing_values punct, enum egprs_puncturing_values punct2, int with_padding); void gprs_rlc_mcs_cps_decode(unsigned int cps, GprsCodingScheme cs, int *punct, int *punct2, int *with_padding); enum egprs_puncturing_values gprs_get_punct_scheme(enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current_trans); + const GprsCodingScheme &cs_current_trans, + const unsigned int spb); void gprs_update_punct_scheme(enum egprs_puncturing_values *punct, const GprsCodingScheme &cs); /* diff --git a/src/tbf.h b/src/tbf.h index 1bd7878..969836b 100644 --- a/src/tbf.h +++ b/src/tbf.h @@ -421,6 +421,11 @@ int analyse_errors(char *show_rbb, uint8_t ssn, ana_result *res); void schedule_next_frame(); + enum egprs_rlc_dl_reseg_bsn_state egprs_dl_get_data_buffer + (int bsn, uint8_t **block_data); + unsigned int get_egprs_dl_spb_status(int bsn); + unsigned int get_egprs_dl_spb_value(int bsn); + struct osmo_timer_list m_llc_timer; }; diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp index 07a747a..0395ed0 100644 --- a/src/tbf_dl.cpp +++ b/src/tbf_dl.cpp @@ -375,21 +375,27 @@ return -1; if (is_egprs_enabled()) { + /* Table 8.1.1.2 and Table 8.1.1.1 of 44.060 */ m_rlc.block(bsn)->cs_current_trans = - GprsCodingScheme::get_retx_mcs( - m_rlc.block(bsn)->cs_last, ms()->current_cs_dl()); + GprsCodingScheme::get_retx_mcs( + m_rlc.block(bsn)->cs_init, + ms()->current_cs_dl(), + bts->bts_data()->dl_arq_type); LOGP(DRLCMACDL, LOGL_DEBUG, - "- current_cs_dl(%d) demanded_mcs(%d) cs_trans(%d)\n", + "- initial_cs_dl(%d) last_mcs(%d) demanded_mcs(%d)" + "cs_trans(%d) arq_type(%d) bsn(%d)\n", + m_rlc.block(bsn)->cs_init.to_num(), m_rlc.block(bsn)->cs_last.to_num(), ms()->current_cs_dl().to_num(), - m_rlc.block(bsn)->cs_current_trans.to_num()); + m_rlc.block(bsn)->cs_current_trans.to_num(), + bts->bts_data()->dl_arq_type, bsn); /* TODO: Need to remove this check when MCS-8 -> MCS-6 * transistion is handled. * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 */ - if (m_rlc.block(bsn)->cs_last == GprsCodingScheme::MCS8) + if (m_rlc.block(bsn)->cs_init == GprsCodingScheme::MCS8) m_rlc.block(bsn)->cs_current_trans = GprsCodingScheme::MCS8; } else @@ -523,6 +529,11 @@ data = rlc_data->prepare(block_data_len); rlc_data->cs_last = cs; rlc_data->cs_current_trans = cs; + + /* Initialise the variable related to DL SPB */ + rlc_data->spb_status.block_status_dl = EGPRS_RESEG_DL_DEFAULT; + rlc_data->cs_init = cs; + rlc_data->len = block_data_len; rdbi = &(rlc_data->block_info); @@ -616,6 +627,7 @@ unsigned num_bsns; enum egprs_puncturing_values punct[ARRAY_SIZE(rlc.block_info)]; bool need_padding = false; + unsigned int spb = 0; /* * TODO: This is an experimental work-around to put 2 BSN into @@ -626,6 +638,7 @@ * the current limit. */ cs = m_rlc.block(index)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(index)->cs_init; bsns[0] = index; num_bsns = 1; @@ -634,7 +647,19 @@ num_bsns += 1; } - if (num_bsns == 1) { + /* + * if the intial mcs is 8 and retransmission mcs is either 6 or 3 + * we have to include the padding of 6 octets in first segment + */ + if ((GprsCodingScheme::Scheme(cs_init) == GprsCodingScheme::MCS8) && + (GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS6 || + GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS3)) { + if ((get_egprs_dl_spb_status(index) == + EGPRS_RESEG_DL_DEFAULT) || + (get_egprs_dl_spb_status(index) == + EGPRS_RESEG_SECOND_SEG_SENT)) + need_padding = true; + } else if (num_bsns == 1) { /* TODO: remove the conditional when MCS-6 padding isn't * failing to be decoded by MEs anymore */ /* TODO: support of MCS-8 -> MCS-6 transition should be @@ -646,7 +671,14 @@ cs.decToSingleBlock(&need_padding); } - gprs_rlc_data_info_init_dl(&rlc, cs, need_padding); + spb = get_egprs_dl_spb_value(index); + + LOGP(DRLCMACDL, LOGL_DEBUG, "- need_padding %d spb_status %d spb %d" + "(BSN1 %d BSN2 %d)\n", + need_padding, + get_egprs_dl_spb_status(index), spb, index, index2); + + gprs_rlc_data_info_init_dl(&rlc, cs, need_padding, spb); rlc.usf = 7; /* will be set at scheduler */ rlc.pr = 0; /* FIXME: power reduction */ @@ -665,10 +697,9 @@ data_block_idx++) { int bsn; - GprsCodingScheme cs_enc; uint8_t *block_data; gprs_rlc_data_block_info *rdbi, *block_info; - enum egprs_puncturing_values punct_scheme; + enum egprs_rlc_dl_reseg_bsn_state reseg_status; /* Check if there are more blocks than BSNs */ if (data_block_idx < num_bsns) @@ -676,38 +707,43 @@ else bsn = bsns[0]; - cs_enc = m_rlc.block(bsn)->cs_current_trans; - /* get data and header from current block */ - block_data = m_rlc.block(bsn)->block; - /* Get current puncturing scheme from block */ - punct_scheme = gprs_get_punct_scheme( + + m_rlc.block(bsn)->next_ps = gprs_get_punct_scheme( m_rlc.block(bsn)->next_ps, - m_rlc.block(bsn)->cs_last, cs); + m_rlc.block(bsn)->cs_last, cs, spb); if (cs.isEgprs()) { - OSMO_ASSERT(punct_scheme >= EGPRS_PS_1); - OSMO_ASSERT(punct_scheme <= EGPRS_PS_3); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps >= EGPRS_PS_1); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps <= EGPRS_PS_3); } - punct[data_block_idx] = punct_scheme; + punct[data_block_idx] = m_rlc.block(bsn)->next_ps; rdbi = &rlc.block_info[data_block_idx]; block_info = &m_rlc.block(bsn)->block_info; - if(rdbi->data_len != m_rlc.block(bsn)->len) { - LOGP(DRLCMACDL, LOGL_ERROR, - "ERROR: Expected len = %d for %s instead of " - "%d in data unit %d (BSN %d, %s)\n", - rdbi->data_len, cs.name(), m_rlc.block(bsn)->len, - data_block_idx, bsn, cs_enc.name()); - OSMO_ASSERT(rdbi->data_len == m_rlc.block(bsn)->len); - } - - /* TODO: Need to handle 2 same bsns - * in header type 1 + /* + * get data and header from current block + * function returns the reseg status */ - gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, - cs); + reseg_status = egprs_dl_get_data_buffer(bsn, &block_data); + m_rlc.block(bsn)->spb_status.block_status_dl = reseg_status; + + /* + * If it is first segment of the split block set the state of + * bsn to nacked. If it is the first segment dont update the + * next ps value of bsn. since next segment also needs same cps + */ + if (spb == 2) + m_window.m_v_b.mark_nacked(bsn); + else { + /* + * TODO: Need to handle 2 same bsns + * in header type 1 + */ + gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, + cs); + } m_rlc.block(bsn)->cs_last = cs; rdbi->e = block_info->e; @@ -1169,3 +1205,119 @@ keep_time_frames = msecs_to_frames(bts_data()->dl_tbf_idle_msec); return frames_since_last_drain(fn) <= keep_time_frames; } + +/* + * This function returns the pointer to data which needs + * to be copied. Also updates the status of the block related to + * Split block handling in the RLC/MAC block. + */ +enum egprs_rlc_dl_reseg_bsn_state + gprs_rlcmac_dl_tbf::egprs_dl_get_data_buffer(int bsn, + uint8_t **block_data) +{ + gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state *block_status_dl = + &rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + *block_data = &rlc_data->block[0]; + + /* + * Table 10.3a.0.1 of 44.060 + * MCS6,9: second segment starts at 74/2 = 37 + * MCS5,7: second segment starts at 56/2 = 28 + * MCS8: second segment starts at 31 + * MCS4: second segment starts at 44/2 = 22 + */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + if (*block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + switch (GprsCodingScheme::Scheme(cs_init)) { + case GprsCodingScheme::MCS6 : + case GprsCodingScheme::MCS9 : + *block_data = &rlc_data->block[37]; + break; + case GprsCodingScheme::MCS7 : + case GprsCodingScheme::MCS5 : + *block_data = &rlc_data->block[28]; + break; + case GprsCodingScheme::MCS8 : + *block_data = &rlc_data->block[31]; + break; + case GprsCodingScheme::MCS4 : + *block_data = &rlc_data->block[22]; + break; + default: + LOGP(DRLCMACDL, LOGL_ERROR, "Software error: " + "--%s hit invalid condition. headerType(%d) " + " blockstatus(%d) cs(%s) PLEASE FIX!\n", name(), + cs_current_trans.headerTypeData(), + *block_status_dl, cs_init.name()); + break; + + } + return EGPRS_RESEG_SECOND_SEG_SENT; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } + } + return EGPRS_RESEG_DL_DEFAULT; +} + +/* + * This function returns the status of split block + * for RLC/MAC block. + */ +unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_status(const int bsn) +{ + const gprs_rlc_data *rlc_data = m_rlc.block(bsn); + + return rlc_data->spb_status.block_status_dl; +} + +/* + * This function returns the spb value to be sent OTA + * for RLC/MAC block. + */ +unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_value(const int bsn) +{ + struct gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state block_status_dl = + rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + + /* Table 10.4.8b.1 of 44.060 */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + /* + * if we are sending the second segment the spb should be 3 + * other wise it should be 2 + */ + if (block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + return 3; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return 2; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return 2; + } + } + /* Non SPB cases 0 is reurned */ + return 0; +} diff --git a/tests/edge/EdgeTest.cpp b/tests/edge/EdgeTest.cpp index 807102c..9081d4d 100644 --- a/tests/edge/EdgeTest.cpp +++ b/tests/edge/EdgeTest.cpp @@ -517,7 +517,7 @@ /* TS 44.060, B.1 */ cs = GprsCodingScheme::CS4; - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -570,7 +570,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -592,7 +592,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -630,7 +630,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -669,7 +669,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -694,7 +694,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -719,7 +719,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -740,7 +740,7 @@ OSMO_ASSERT(data[0] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -777,7 +777,7 @@ cs = GprsCodingScheme::MCS4; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -835,7 +835,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -872,7 +872,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -923,7 +923,7 @@ OSMO_ASSERT(data[3] == 0); /* Block 3 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -967,7 +967,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -993,7 +993,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1020,7 +1020,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1074,7 +1074,7 @@ block_idx++) { struct gprs_rlc_data_info rlc; - gprs_rlc_data_info_init_dl(&rlc, cs, false); + gprs_rlc_data_info_init_dl(&rlc, cs, false, 0); memset(bits, pattern, sizeof(bits)); Decoding::rlc_copy_to_aligned_buffer( @@ -1118,12 +1118,14 @@ struct gprs_rlc_data_info rlc; printf("=== start %s ===\n", __func__); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::CS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::CS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 24); OSMO_ASSERT(rlc.block_info[0].data_len == 20); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::MCS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::MCS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 33); OSMO_ASSERT(rlc.block_info[0].data_len == 22); diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..18cc5cb 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -1814,6 +1814,201 @@ } +static void egprs_spb_to_normal_validation(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + uint16_t bsn1, bsn2, bsn3; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + struct gprs_rlc_dl_header_egprs_2 *egprs2; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + if ((mcs == 6) && (demanded_mcs == 3)) { + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + bsn1 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) + || (egprs2->bsn1_lo); + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(bsn1 == 0); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + bsn2 = (egprs3->bsn1_hi << 9) || (egprs3->bsn1_mid << 1) || + (egprs3->bsn1_lo); + OSMO_ASSERT(bsn2 == bsn1); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Handle (MCS3, MCS3) -> MCS6 case */ + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + mcs)); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs2->cps == 0); + bsn3 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) || + (egprs2->bsn1_lo); + OSMO_ASSERT(bsn3 == bsn2); + + tbf_cleanup(dl_tbf); + } +} +static void establish_and_use_egprs_dl_tbf_for_spb(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + /* TODO: Need to support of MCS8 -> MCS6 ->MCS3 transistion + * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 + * dated 2016-02-07 23:45:40 (UTC) + */ + if (((mcs == 5) && (demanded_mcs == 2)) || + ((mcs == 6) && (demanded_mcs == 3)) || + ((mcs == 4) && (demanded_mcs == 1))) { + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + tbf_cleanup(dl_tbf); + } +} + static void establish_and_use_egprs_dl_tbf_for_retx(BTS *the_bts, int mcs, int demanded_mcs) { @@ -1972,6 +2167,9 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; + /* First parameter is current MCS, second one is demanded_mcs */ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 6); @@ -1981,6 +2179,38 @@ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 9); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 7, 5); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 9, 6); + + printf("=== end %s ===\n", __func__); +} + +static void test_tbf_egprs_spb_dl(void) +{ + BTS the_bts; + gprs_rlcmac_bts *bts; + uint8_t ts_no = 4; + int i, j; + + printf("=== start %s ===\n", __func__); + + bts = the_bts.bts_data(); + bts->cs_downgrade_threshold = 0; + setup_bts(&the_bts, ts_no); + bts->dl_tbf_idle_msec = 200; + bts->egprs_enabled = 1; + + /* ARQ I resegmentation support */ + bts->dl_arq_type = EGPRS_ARQ1; + + /* + * First parameter is current MCS, second one is demanded_mcs + * currently only MCS5->MCS2, MCS6->3, MCS4->MCS1 is tested in UT + * rest scenarios has been integration tested + */ + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 6, 3); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 5, 2); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 4, 1); + /* check MCS6->(MCS3+MCS3)->MCS6 case */ + egprs_spb_to_normal_validation(&the_bts, 6, 3); printf("=== end %s ===\n", __func__); } @@ -1999,6 +2229,8 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; for (i = 1; i <= 9; i++) establish_and_use_egprs_dl_tbf(&the_bts, i); @@ -2071,6 +2303,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_egprs_spb_dl(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..7b3f339 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -72,6 +72,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -81,6 +82,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -157,6 +159,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -166,6 +169,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -242,6 +246,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -251,6 +256,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -259,6 +265,7 @@ - Sending new block at BSN 2, CS=CS-1 -- Chunk with length 160 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=13 block=3 data=07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b @@ -267,6 +274,7 @@ - Sending new block at BSN 3, CS=CS-1 -- Chunk with length 140 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=17 block=4 data=07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @@ -275,6 +283,7 @@ - Sending new block at BSN 4, CS=CS-1 -- Chunk with length 120 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=21 block=5 data=07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 @@ -283,6 +292,7 @@ - Sending new block at BSN 5, CS=CS-1 -- Chunk with length 100 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=26 block=6 data=07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 @@ -291,6 +301,7 @@ - Sending new block at BSN 6, CS=CS-1 -- Chunk with length 80 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=30 block=7 data=07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b @@ -299,6 +310,7 @@ - Sending new block at BSN 7, CS=CS-1 -- Chunk with length 60 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=34 block=8 data=07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f @@ -307,6 +319,7 @@ - Sending new block at BSN 8, CS=CS-1 -- Chunk with length 40 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=39 block=9 data=07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 @@ -315,6 +328,7 @@ - Sending new block at BSN 9, CS=CS-1 -- Chunk with length 20 would exactly fit into space (20): add length header with LI=0, to make frame extend to next block, and we are done data block (BSN 9, CS-1): 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=43 block=10 data=07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 @@ -326,6 +340,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=47 block=11 data=07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 @@ -334,6 +349,7 @@ - Sending new block at BSN 11, CS=CS-1 -- Chunk with length 182 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=52 block=0 data=07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 @@ -342,6 +358,7 @@ - Sending new block at BSN 12, CS=CS-1 -- Chunk with length 162 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=56 block=1 data=07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 @@ -350,6 +367,7 @@ - Sending new block at BSN 13, CS=CS-1 -- Chunk with length 142 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 13, CS-1): 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=60 block=2 data=07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d @@ -358,6 +376,7 @@ - Sending new block at BSN 14, CS=CS-1 -- Chunk with length 122 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=65 block=3 data=07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 @@ -366,6 +385,7 @@ - Sending new block at BSN 15, CS=CS-1 -- Chunk with length 102 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=69 block=4 data=07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 @@ -374,6 +394,7 @@ - Sending new block at BSN 16, CS=CS-1 -- Chunk with length 82 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=73 block=5 data=07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 @@ -382,6 +403,7 @@ - Sending new block at BSN 17, CS=CS-1 -- Chunk with length 62 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=78 block=6 data=07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d @@ -390,6 +412,7 @@ - Sending new block at BSN 18, CS=CS-1 -- Chunk with length 42 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=82 block=7 data=07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 @@ -398,6 +421,7 @@ - Sending new block at BSN 19, CS=CS-1 -- Chunk with length 22 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=86 block=8 data=07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 @@ -411,6 +435,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=16 data block (BSN 20, CS-1): 0a 41 c6 c7 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -449,6 +474,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 data block (BSN 21, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -468,6 +494,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 22, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FINISHED) @@ -1481,6 +1508,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 0, CS-1): 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 MSG = 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 @@ -1491,6 +1519,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 1, CS-1): 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 MSG = 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 @@ -1501,6 +1530,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FINISHED data block (BSN 2, CS-1): 4d 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling cannot be scheduled in this TS 7 (first control TS 4) @@ -1784,6 +1814,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=10 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 0, CS-4): 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654292 TS 7 @@ -1797,6 +1828,7 @@ TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) downlink (V(A)==0 .. V(S)==1) - Restarting at BSN 0, because all blocks have been transmitted. - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-4): 07 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 @@ -2365,6 +2397,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654279 block=10 data=00 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 @@ -2384,6 +2417,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -2406,6 +2440,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654288 block=0 data=00 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 @@ -2425,6 +2460,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654292 block=1 data=00 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2447,6 +2483,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654296 block=2 data=00 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c @@ -2466,6 +2503,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654301 block=3 data=00 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b @@ -2488,6 +2526,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 6, CS-1): 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654305 block=4 data=00 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 @@ -2507,6 +2546,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654309 block=5 data=00 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 @@ -2526,6 +2566,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654314 block=6 data=00 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 @@ -2548,6 +2589,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654318 block=7 data=00 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 @@ -2567,6 +2609,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654322 block=8 data=00 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2589,6 +2632,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654327 block=9 data=00 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c @@ -2608,6 +2652,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654331 block=10 data=00 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b @@ -2630,6 +2675,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 13, CS-1): 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654335 block=11 data=00 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 @@ -2649,6 +2695,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654340 block=0 data=00 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 @@ -2668,6 +2715,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654344 block=1 data=00 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 @@ -2690,6 +2738,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654348 block=2 data=00 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 @@ -2709,6 +2758,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654353 block=3 data=00 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2731,6 +2781,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654357 block=4 data=00 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c @@ -2750,6 +2801,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654361 block=5 data=00 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b @@ -2772,6 +2824,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 20, CS-1): 16 35 45 54 20 32 38 4c 4c 43 20 50 41 43 4b 45 54 20 32 39 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because 20 blocks sent. TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW): Scheduling polling at FN 2654379 TS 7 @@ -2795,6 +2848,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 21, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) msg block (BSN 21, CS-1): 07 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654370 block=7 data=00 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 @@ -2814,6 +2868,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 22, CS-1): 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) msg block (BSN 22, CS-1): 07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654374 block=8 data=07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 @@ -2836,6 +2891,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 23, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) msg block (BSN 23, CS-1): 07 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654379 block=9 data=00 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 @@ -2855,6 +2911,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 24, CS-1): 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) msg block (BSN 24, CS-1): 07 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654383 block=10 data=00 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2877,6 +2934,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 25, CS-1): 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 25 BSN2 -1) - Copying data unit 0 (BSN 25) msg block (BSN 25, CS-1): 07 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654387 block=11 data=00 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c @@ -2896,6 +2954,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 26, CS-1): 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 26 BSN2 -1) - Copying data unit 0 (BSN 26) msg block (BSN 26, CS-1): 07 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654392 block=0 data=00 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b @@ -2918,6 +2977,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 27, CS-1): 16 35 45 54 20 33 38 4c 4c 43 20 50 41 43 4b 45 54 20 33 39 +- need_padding 0 spb_status 0 spb 0(BSN1 27 BSN2 -1) - Copying data unit 0 (BSN 27) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) @@ -3028,6 +3088,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654405 block=3 data=00 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 @@ -3047,6 +3108,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654409 block=4 data=00 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 @@ -3066,6 +3128,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (16) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654413 block=5 data=00 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 @@ -3085,6 +3148,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (14) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654418 block=6 data=00 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 @@ -3104,6 +3168,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654422 block=7 data=00 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -3123,6 +3188,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654426 block=8 data=00 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 @@ -3142,6 +3208,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654431 block=9 data=00 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b @@ -3161,6 +3228,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654435 block=10 data=00 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 @@ -3180,6 +3248,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654439 block=11 data=00 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 @@ -3199,6 +3268,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654444 block=0 data=00 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c @@ -3218,6 +3288,7 @@ Complete DL frame for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=21 TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 10, CS-1): 4d 43 20 50 41 43 4b 45 54 20 30 39 20 28 54 42 46 20 32 29 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654461 TS 7 @@ -3698,6 +3769,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 0, MCS-1): 14 15 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3711,6 +3783,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3721,6 +3794,7 @@ - Sending new block at BSN 2, CS=MCS-1 -- Chunk with length 490 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3731,6 +3805,7 @@ - Sending new block at BSN 3, CS=MCS-1 -- Chunk with length 468 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3741,6 +3816,7 @@ - Sending new block at BSN 4, CS=MCS-1 -- Chunk with length 446 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3751,6 +3827,7 @@ - Sending new block at BSN 5, CS=MCS-1 -- Chunk with length 424 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3761,6 +3838,7 @@ - Sending new block at BSN 6, CS=MCS-1 -- Chunk with length 402 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3771,6 +3849,7 @@ - Sending new block at BSN 7, CS=MCS-1 -- Chunk with length 380 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3781,6 +3860,7 @@ - Sending new block at BSN 8, CS=MCS-1 -- Chunk with length 358 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3791,6 +3871,7 @@ - Sending new block at BSN 9, CS=MCS-1 -- Chunk with length 336 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3801,6 +3882,7 @@ - Sending new block at BSN 10, CS=MCS-1 -- Chunk with length 314 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3811,6 +3893,7 @@ - Sending new block at BSN 11, CS=MCS-1 -- Chunk with length 292 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3821,6 +3904,7 @@ - Sending new block at BSN 12, CS=MCS-1 -- Chunk with length 270 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3831,6 +3915,7 @@ - Sending new block at BSN 13, CS=MCS-1 -- Chunk with length 248 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3841,6 +3926,7 @@ - Sending new block at BSN 14, CS=MCS-1 -- Chunk with length 226 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3851,6 +3937,7 @@ - Sending new block at BSN 15, CS=MCS-1 -- Chunk with length 204 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3861,6 +3948,7 @@ - Sending new block at BSN 16, CS=MCS-1 -- Chunk with length 182 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3871,6 +3959,7 @@ - Sending new block at BSN 17, CS=MCS-1 -- Chunk with length 160 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3881,6 +3970,7 @@ - Sending new block at BSN 18, CS=MCS-1 -- Chunk with length 138 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3891,6 +3981,7 @@ - Sending new block at BSN 19, CS=MCS-1 -- Chunk with length 116 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 19, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3901,6 +3992,7 @@ - Sending new block at BSN 20, CS=MCS-1 -- Chunk with length 94 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 20, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3911,6 +4003,7 @@ - Sending new block at BSN 21, CS=MCS-1 -- Chunk with length 72 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 21, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3921,6 +4014,7 @@ - Sending new block at BSN 22, CS=MCS-1 -- Chunk with length 50 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 22, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3931,6 +4025,7 @@ - Sending new block at BSN 23, CS=MCS-1 -- Chunk with length 28 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 23, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3946,6 +4041,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 24, MCS-1): 0c 1d 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4006,6 +4102,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=16 data block (BSN 0, MCS-2): 14 21 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4019,6 +4116,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4029,6 +4127,7 @@ - Sending new block at BSN 2, CS=MCS-2 -- Chunk with length 484 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4039,6 +4138,7 @@ - Sending new block at BSN 3, CS=MCS-2 -- Chunk with length 456 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4049,6 +4149,7 @@ - Sending new block at BSN 4, CS=MCS-2 -- Chunk with length 428 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4059,6 +4160,7 @@ - Sending new block at BSN 5, CS=MCS-2 -- Chunk with length 400 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4069,6 +4171,7 @@ - Sending new block at BSN 6, CS=MCS-2 -- Chunk with length 372 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4079,6 +4182,7 @@ - Sending new block at BSN 7, CS=MCS-2 -- Chunk with length 344 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4089,6 +4193,7 @@ - Sending new block at BSN 8, CS=MCS-2 -- Chunk with length 316 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4099,6 +4204,7 @@ - Sending new block at BSN 9, CS=MCS-2 -- Chunk with length 288 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4109,6 +4215,7 @@ - Sending new block at BSN 10, CS=MCS-2 -- Chunk with length 260 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4119,6 +4226,7 @@ - Sending new block at BSN 11, CS=MCS-2 -- Chunk with length 232 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4129,6 +4237,7 @@ - Sending new block at BSN 12, CS=MCS-2 -- Chunk with length 204 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4139,6 +4248,7 @@ - Sending new block at BSN 13, CS=MCS-2 -- Chunk with length 176 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4149,6 +4259,7 @@ - Sending new block at BSN 14, CS=MCS-2 -- Chunk with length 148 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4159,6 +4270,7 @@ - Sending new block at BSN 15, CS=MCS-2 -- Chunk with length 120 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4169,6 +4281,7 @@ - Sending new block at BSN 16, CS=MCS-2 -- Chunk with length 92 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4179,6 +4292,7 @@ - Sending new block at BSN 17, CS=MCS-2 -- Chunk with length 64 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4189,6 +4303,7 @@ - Sending new block at BSN 18, CS=MCS-2 -- Chunk with length 36 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4204,6 +4319,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=18 data block (BSN 19, MCS-2): 10 25 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4264,6 +4380,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=25 data block (BSN 0, MCS-3): 14 33 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4277,6 +4394,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4287,6 +4405,7 @@ - Sending new block at BSN 2, CS=MCS-3 -- Chunk with length 475 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4297,6 +4416,7 @@ - Sending new block at BSN 3, CS=MCS-3 -- Chunk with length 438 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4307,6 +4427,7 @@ - Sending new block at BSN 4, CS=MCS-3 -- Chunk with length 401 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4317,6 +4438,7 @@ - Sending new block at BSN 5, CS=MCS-3 -- Chunk with length 364 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4327,6 +4449,7 @@ - Sending new block at BSN 6, CS=MCS-3 -- Chunk with length 327 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4337,6 +4460,7 @@ - Sending new block at BSN 7, CS=MCS-3 -- Chunk with length 290 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4347,6 +4471,7 @@ - Sending new block at BSN 8, CS=MCS-3 -- Chunk with length 253 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4357,6 +4482,7 @@ - Sending new block at BSN 9, CS=MCS-3 -- Chunk with length 216 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4367,6 +4493,7 @@ - Sending new block at BSN 10, CS=MCS-3 -- Chunk with length 179 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4377,6 +4504,7 @@ - Sending new block at BSN 11, CS=MCS-3 -- Chunk with length 142 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4387,6 +4515,7 @@ - Sending new block at BSN 12, CS=MCS-3 -- Chunk with length 105 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4397,6 +4526,7 @@ - Sending new block at BSN 13, CS=MCS-3 -- Chunk with length 68 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4410,6 +4540,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-3): 3f 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4425,6 +4556,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=34 data block (BSN 15, MCS-3): 02 45 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4485,6 +4617,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=32 data block (BSN 0, MCS-4): 14 41 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4498,6 +4631,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4508,6 +4642,7 @@ - Sending new block at BSN 2, CS=MCS-4 -- Chunk with length 468 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4518,6 +4653,7 @@ - Sending new block at BSN 3, CS=MCS-4 -- Chunk with length 424 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4528,6 +4664,7 @@ - Sending new block at BSN 4, CS=MCS-4 -- Chunk with length 380 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4538,6 +4675,7 @@ - Sending new block at BSN 5, CS=MCS-4 -- Chunk with length 336 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4548,6 +4686,7 @@ - Sending new block at BSN 6, CS=MCS-4 -- Chunk with length 292 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4558,6 +4697,7 @@ - Sending new block at BSN 7, CS=MCS-4 -- Chunk with length 248 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4568,6 +4708,7 @@ - Sending new block at BSN 8, CS=MCS-4 -- Chunk with length 204 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4578,6 +4719,7 @@ - Sending new block at BSN 9, CS=MCS-4 -- Chunk with length 160 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4588,6 +4730,7 @@ - Sending new block at BSN 10, CS=MCS-4 -- Chunk with length 116 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4598,6 +4741,7 @@ - Sending new block at BSN 11, CS=MCS-4 -- Chunk with length 72 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4613,6 +4757,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 12, MCS-4): 38 1d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4673,6 +4818,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-5): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4686,6 +4832,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4696,6 +4843,7 @@ - Sending new block at BSN 2, CS=MCS-5 -- Chunk with length 456 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4706,6 +4854,7 @@ - Sending new block at BSN 3, CS=MCS-5 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4716,6 +4865,7 @@ - Sending new block at BSN 4, CS=MCS-5 -- Chunk with length 344 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4726,6 +4876,7 @@ - Sending new block at BSN 5, CS=MCS-5 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4736,6 +4887,7 @@ - Sending new block at BSN 6, CS=MCS-5 -- Chunk with length 232 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4746,6 +4898,7 @@ - Sending new block at BSN 7, CS=MCS-5 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4756,6 +4909,7 @@ - Sending new block at BSN 8, CS=MCS-5 -- Chunk with length 120 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4766,6 +4920,7 @@ - Sending new block at BSN 9, CS=MCS-5 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4781,6 +4936,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-5): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4841,6 +4997,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-6): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4854,6 +5011,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4864,6 +5022,7 @@ - Sending new block at BSN 2, CS=MCS-6 -- Chunk with length 438 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4874,6 +5033,7 @@ - Sending new block at BSN 3, CS=MCS-6 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4884,6 +5044,7 @@ - Sending new block at BSN 4, CS=MCS-6 -- Chunk with length 290 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4894,6 +5055,7 @@ - Sending new block at BSN 5, CS=MCS-6 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4904,6 +5066,7 @@ - Sending new block at BSN 6, CS=MCS-6 -- Chunk with length 142 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4917,6 +5080,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-6): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4932,6 +5096,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-6): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4993,6 +5158,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-7): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5002,12 +5168,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(7) last_mcs(5) demanded_mcs(7)cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-7 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5022,6 +5189,7 @@ - Sending new block at BSN 3, CS=MCS-7 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5036,6 +5204,7 @@ - Sending new block at BSN 5, CS=MCS-7 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5050,6 +5219,7 @@ - Sending new block at BSN 7, CS=MCS-7 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5064,6 +5234,7 @@ - Sending new block at BSN 9, CS=MCS-7 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 9) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5081,6 +5252,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-7): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5142,6 +5314,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=56 data block (BSN 0, MCS-8): 14 71 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5152,12 +5325,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(8) demanded_mcs(8) cs_trans(8) +- initial_cs_dl(8) last_mcs(8) demanded_mcs(8)cs_trans(8) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-8 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5172,6 +5346,7 @@ - Sending new block at BSN 3, CS=MCS-8 -- Chunk with length 376 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5186,6 +5361,7 @@ - Sending new block at BSN 5, CS=MCS-8 -- Chunk with length 240 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5200,6 +5376,7 @@ - Sending new block at BSN 7, CS=MCS-8 -- Chunk with length 104 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5217,6 +5394,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=30 data block (BSN 8, MCS-8): 48 3d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5279,6 +5457,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-9): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5288,12 +5467,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(9) last_mcs(6) demanded_mcs(9)cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-9 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5308,6 +5488,7 @@ - Sending new block at BSN 3, CS=MCS-9 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5322,6 +5503,7 @@ - Sending new block at BSN 5, CS=MCS-9 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5339,6 +5521,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-9): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5356,6 +5539,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-9): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5402,11 +5586,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(6)cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5450,11 +5636,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 96 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(1) demanded_mcs(1) cs_trans(1) +- initial_cs_dl(1) last_mcs(1) demanded_mcs(1)cs_trans(1) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 98 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5498,11 +5686,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-2): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 92 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(2) demanded_mcs(2) cs_trans(2) +- initial_cs_dl(2) last_mcs(2) demanded_mcs(2)cs_trans(2) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 94 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5546,6 +5736,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5557,6 +5748,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-5): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5564,10 +5756,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-5): 0f 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7)cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7)cs_trans(7) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-7): 07 00 00 02 c0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 @@ -5612,6 +5805,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5623,6 +5817,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-6): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5630,10 +5825,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-6): 0f 40 00 00 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9)cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9)cs_trans(9) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-9): 07 00 00 02 28 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 @@ -5686,6 +5882,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-7): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5694,13 +5891,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-7): 0f 00 00 02 a0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5)cs_trans(5) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5)cs_trans(5) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-5): 07 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5752,6 +5951,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-9): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5760,13 +5960,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-9): 0f 00 00 02 00 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6)cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6)cs_trans(6) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-6): 07 40 00 02 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5780,3 +5982,233 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-5 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(2)cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 d2 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(2) demanded_mcs(2)cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 f2 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-4 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (44) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-4): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-4): 07 00 00 80 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(4) demanded_mcs(1)cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 d6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(1) demanded_mcs(1)cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 f6 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(6)cs_trans(6) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 2 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..c38417d 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,9 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_egprs_spb_dl === +Testing retx for MCS 6 to reseg_mcs 3 +Testing retx for MCS 5 to reseg_mcs 2 +Testing retx for MCS 4 to reseg_mcs 1 +Testing retx for MCS 6 to reseg_mcs 3 +=== end test_tbf_egprs_spb_dl === -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 8 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Wed Aug 10 08:07:51 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Wed, 10 Aug 2016 08:07:51 +0000 Subject: [PATCH] osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/655 to look at the new patch set (#9). Modify EGPRS DL TBF flow to support SPB Modify the EGPRS DL TBF flow to support Split block during Retx. This patch will also Upgrade the test suite with test cases to validate the EGPRS Downlink SPB for Retransmission Scenarios like MCS6->MCS3, MCS4->MCS1, MCS5->MCS2, MCS9->MCS3 MCS7->MCS2, MCS8->MCS3 have been simulated and Integration tested in NuRAN 1.0 hardware thoroughly. Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 --- M src/gprs_coding_scheme.h M src/pcu_main.cpp M src/pcu_vty.c M src/rlc.cpp M src/rlc.h M src/tbf.h M src/tbf_dl.cpp M tests/edge/EdgeTest.cpp M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 11 files changed, 948 insertions(+), 77 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/55/655/9 diff --git a/src/gprs_coding_scheme.h b/src/gprs_coding_scheme.h index 60a8e79..3b15372 100644 --- a/src/gprs_coding_scheme.h +++ b/src/gprs_coding_scheme.h @@ -113,7 +113,8 @@ static const char *modeName(Mode mode); static Scheme get_retx_mcs(const GprsCodingScheme mcs, - const GprsCodingScheme retx_mcs); + const GprsCodingScheme retx_mcs, + const unsigned arq_type); static enum Scheme egprs_mcs_retx_tbl[MAX_NUM_ARQ] [MAX_NUM_MCS][MAX_NUM_MCS]; @@ -232,8 +233,9 @@ } inline GprsCodingScheme::Scheme GprsCodingScheme::get_retx_mcs( const GprsCodingScheme mcs, - const GprsCodingScheme demanded_mcs) + const GprsCodingScheme demanded_mcs, + const unsigned arq_type) { - return egprs_mcs_retx_tbl[EGPRS_ARQ2][mcs.to_num() - 1] + return egprs_mcs_retx_tbl[arq_type][mcs.to_num() - 1] [demanded_mcs.to_num() - 1]; } diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2d86cda..e34d534 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -210,6 +210,12 @@ bts->dl_tbf_idle_msec = 2000; bts->llc_idle_ack_csec = 10; + /* + * By default resegmentation is supported in DL + * can also be configured through VTY + */ + bts->dl_arq_type = EGPRS_ARQ1; + msgb_set_talloc_ctx(tall_pcu_ctx); osmo_init_logging(&gprs_log_info); diff --git a/src/pcu_vty.c b/src/pcu_vty.c index 58fea99..1083f42 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -129,6 +129,9 @@ vty_out(vty, " window-size %d %d%s", bts->ws_base, bts->ws_pdch, VTY_NEWLINE); + if (bts->dl_arq_type) + vty_out(vty, " dl arq %d %s", bts->dl_arq_type, VTY_NEWLINE); + if (bts->force_llc_lifetime == 0xffff) vty_out(vty, " queue lifetime infinite%s", VTY_NEWLINE); else if (bts->force_llc_lifetime) @@ -477,6 +480,20 @@ bts->max_mcs_dl = 0; bts->max_mcs_ul = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_pcu_dl_arq_type, + cfg_pcu_dl_arq_cmd, + "dl arq-type (0|1)", + EGPRS_STR "DL ARQ options\n" + "enable DL SPB support\n" + "enable DL ARQ2 support") +{ + struct gprs_rlcmac_bts *bts = bts_main_data(); + uint8_t dl_arq_type = atoi(argv[0]); + + bts->dl_arq_type = dl_arq_type; return CMD_SUCCESS; } @@ -954,6 +971,7 @@ install_element(PCU_NODE, &cfg_pcu_no_cs_downgrade_thrsh_cmd); install_element(PCU_NODE, &cfg_pcu_cs_lqual_ranges_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_cmd); + install_element(PCU_NODE, &cfg_pcu_dl_arq_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_max_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_max_cmd); diff --git a/src/rlc.cpp b/src/rlc.cpp index 6770043..8da96f7 100644 --- a/src/rlc.cpp +++ b/src/rlc.cpp @@ -285,7 +285,8 @@ } static void gprs_rlc_data_header_init(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding, unsigned int header_bits) + GprsCodingScheme cs, bool with_padding, unsigned int header_bits, + const unsigned int spb) { unsigned int i; unsigned int padding_bits = with_padding ? cs.optionalPaddingBits() : 0; @@ -300,7 +301,7 @@ for (i = 0; i < rlc->num_data_blocks; i++) { gprs_rlc_data_block_info_init(&rlc->block_info[i], cs, - with_padding); + with_padding, spb); rlc->data_offs_bits[i] = header_bits + padding_bits + @@ -310,21 +311,25 @@ } void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsDL()); + cs.numDataHeaderBitsDL(), spb); } void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding) { + /* + * last parameter is sent as 0 since common function used + * for both DL and UL + */ return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsUL()); + cs.numDataHeaderBitsUL(), 0); } void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { unsigned int data_len = cs.maxDataBlockBytes(); if (with_padding) @@ -336,7 +341,7 @@ rdbi->e = 1; rdbi->cv = 15; rdbi->pi = 0; - rdbi->spb = 0; + rdbi->spb = spb; } unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, @@ -411,8 +416,17 @@ enum egprs_puncturing_values gprs_get_punct_scheme( enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current) + const GprsCodingScheme &cs_current, + const unsigned int spb) { + + /* + * If it is second segment of the block + * dont change the puncturing scheme + */ + if (spb == 3) + return punct; + /* TS 44.060 9.3.2.1.1 */ if ((GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS9) && (GprsCodingScheme::Scheme(cs_current) == GprsCodingScheme::MCS6)) { diff --git a/src/rlc.h b/src/rlc.h index 539b30b..66faf6f 100644 --- a/src/rlc.h +++ b/src/rlc.h @@ -206,18 +206,19 @@ }; void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding); void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, enum egprs_puncturing_values punct, enum egprs_puncturing_values punct2, int with_padding); void gprs_rlc_mcs_cps_decode(unsigned int cps, GprsCodingScheme cs, int *punct, int *punct2, int *with_padding); enum egprs_puncturing_values gprs_get_punct_scheme(enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current_trans); + const GprsCodingScheme &cs_current_trans, + const unsigned int spb); void gprs_update_punct_scheme(enum egprs_puncturing_values *punct, const GprsCodingScheme &cs); /* diff --git a/src/tbf.h b/src/tbf.h index 1bd7878..969836b 100644 --- a/src/tbf.h +++ b/src/tbf.h @@ -421,6 +421,11 @@ int analyse_errors(char *show_rbb, uint8_t ssn, ana_result *res); void schedule_next_frame(); + enum egprs_rlc_dl_reseg_bsn_state egprs_dl_get_data_buffer + (int bsn, uint8_t **block_data); + unsigned int get_egprs_dl_spb_status(int bsn); + unsigned int get_egprs_dl_spb_value(int bsn); + struct osmo_timer_list m_llc_timer; }; diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp index 07a747a..0395ed0 100644 --- a/src/tbf_dl.cpp +++ b/src/tbf_dl.cpp @@ -375,21 +375,27 @@ return -1; if (is_egprs_enabled()) { + /* Table 8.1.1.2 and Table 8.1.1.1 of 44.060 */ m_rlc.block(bsn)->cs_current_trans = - GprsCodingScheme::get_retx_mcs( - m_rlc.block(bsn)->cs_last, ms()->current_cs_dl()); + GprsCodingScheme::get_retx_mcs( + m_rlc.block(bsn)->cs_init, + ms()->current_cs_dl(), + bts->bts_data()->dl_arq_type); LOGP(DRLCMACDL, LOGL_DEBUG, - "- current_cs_dl(%d) demanded_mcs(%d) cs_trans(%d)\n", + "- initial_cs_dl(%d) last_mcs(%d) demanded_mcs(%d)" + "cs_trans(%d) arq_type(%d) bsn(%d)\n", + m_rlc.block(bsn)->cs_init.to_num(), m_rlc.block(bsn)->cs_last.to_num(), ms()->current_cs_dl().to_num(), - m_rlc.block(bsn)->cs_current_trans.to_num()); + m_rlc.block(bsn)->cs_current_trans.to_num(), + bts->bts_data()->dl_arq_type, bsn); /* TODO: Need to remove this check when MCS-8 -> MCS-6 * transistion is handled. * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 */ - if (m_rlc.block(bsn)->cs_last == GprsCodingScheme::MCS8) + if (m_rlc.block(bsn)->cs_init == GprsCodingScheme::MCS8) m_rlc.block(bsn)->cs_current_trans = GprsCodingScheme::MCS8; } else @@ -523,6 +529,11 @@ data = rlc_data->prepare(block_data_len); rlc_data->cs_last = cs; rlc_data->cs_current_trans = cs; + + /* Initialise the variable related to DL SPB */ + rlc_data->spb_status.block_status_dl = EGPRS_RESEG_DL_DEFAULT; + rlc_data->cs_init = cs; + rlc_data->len = block_data_len; rdbi = &(rlc_data->block_info); @@ -616,6 +627,7 @@ unsigned num_bsns; enum egprs_puncturing_values punct[ARRAY_SIZE(rlc.block_info)]; bool need_padding = false; + unsigned int spb = 0; /* * TODO: This is an experimental work-around to put 2 BSN into @@ -626,6 +638,7 @@ * the current limit. */ cs = m_rlc.block(index)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(index)->cs_init; bsns[0] = index; num_bsns = 1; @@ -634,7 +647,19 @@ num_bsns += 1; } - if (num_bsns == 1) { + /* + * if the intial mcs is 8 and retransmission mcs is either 6 or 3 + * we have to include the padding of 6 octets in first segment + */ + if ((GprsCodingScheme::Scheme(cs_init) == GprsCodingScheme::MCS8) && + (GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS6 || + GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS3)) { + if ((get_egprs_dl_spb_status(index) == + EGPRS_RESEG_DL_DEFAULT) || + (get_egprs_dl_spb_status(index) == + EGPRS_RESEG_SECOND_SEG_SENT)) + need_padding = true; + } else if (num_bsns == 1) { /* TODO: remove the conditional when MCS-6 padding isn't * failing to be decoded by MEs anymore */ /* TODO: support of MCS-8 -> MCS-6 transition should be @@ -646,7 +671,14 @@ cs.decToSingleBlock(&need_padding); } - gprs_rlc_data_info_init_dl(&rlc, cs, need_padding); + spb = get_egprs_dl_spb_value(index); + + LOGP(DRLCMACDL, LOGL_DEBUG, "- need_padding %d spb_status %d spb %d" + "(BSN1 %d BSN2 %d)\n", + need_padding, + get_egprs_dl_spb_status(index), spb, index, index2); + + gprs_rlc_data_info_init_dl(&rlc, cs, need_padding, spb); rlc.usf = 7; /* will be set at scheduler */ rlc.pr = 0; /* FIXME: power reduction */ @@ -665,10 +697,9 @@ data_block_idx++) { int bsn; - GprsCodingScheme cs_enc; uint8_t *block_data; gprs_rlc_data_block_info *rdbi, *block_info; - enum egprs_puncturing_values punct_scheme; + enum egprs_rlc_dl_reseg_bsn_state reseg_status; /* Check if there are more blocks than BSNs */ if (data_block_idx < num_bsns) @@ -676,38 +707,43 @@ else bsn = bsns[0]; - cs_enc = m_rlc.block(bsn)->cs_current_trans; - /* get data and header from current block */ - block_data = m_rlc.block(bsn)->block; - /* Get current puncturing scheme from block */ - punct_scheme = gprs_get_punct_scheme( + + m_rlc.block(bsn)->next_ps = gprs_get_punct_scheme( m_rlc.block(bsn)->next_ps, - m_rlc.block(bsn)->cs_last, cs); + m_rlc.block(bsn)->cs_last, cs, spb); if (cs.isEgprs()) { - OSMO_ASSERT(punct_scheme >= EGPRS_PS_1); - OSMO_ASSERT(punct_scheme <= EGPRS_PS_3); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps >= EGPRS_PS_1); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps <= EGPRS_PS_3); } - punct[data_block_idx] = punct_scheme; + punct[data_block_idx] = m_rlc.block(bsn)->next_ps; rdbi = &rlc.block_info[data_block_idx]; block_info = &m_rlc.block(bsn)->block_info; - if(rdbi->data_len != m_rlc.block(bsn)->len) { - LOGP(DRLCMACDL, LOGL_ERROR, - "ERROR: Expected len = %d for %s instead of " - "%d in data unit %d (BSN %d, %s)\n", - rdbi->data_len, cs.name(), m_rlc.block(bsn)->len, - data_block_idx, bsn, cs_enc.name()); - OSMO_ASSERT(rdbi->data_len == m_rlc.block(bsn)->len); - } - - /* TODO: Need to handle 2 same bsns - * in header type 1 + /* + * get data and header from current block + * function returns the reseg status */ - gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, - cs); + reseg_status = egprs_dl_get_data_buffer(bsn, &block_data); + m_rlc.block(bsn)->spb_status.block_status_dl = reseg_status; + + /* + * If it is first segment of the split block set the state of + * bsn to nacked. If it is the first segment dont update the + * next ps value of bsn. since next segment also needs same cps + */ + if (spb == 2) + m_window.m_v_b.mark_nacked(bsn); + else { + /* + * TODO: Need to handle 2 same bsns + * in header type 1 + */ + gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, + cs); + } m_rlc.block(bsn)->cs_last = cs; rdbi->e = block_info->e; @@ -1169,3 +1205,119 @@ keep_time_frames = msecs_to_frames(bts_data()->dl_tbf_idle_msec); return frames_since_last_drain(fn) <= keep_time_frames; } + +/* + * This function returns the pointer to data which needs + * to be copied. Also updates the status of the block related to + * Split block handling in the RLC/MAC block. + */ +enum egprs_rlc_dl_reseg_bsn_state + gprs_rlcmac_dl_tbf::egprs_dl_get_data_buffer(int bsn, + uint8_t **block_data) +{ + gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state *block_status_dl = + &rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + *block_data = &rlc_data->block[0]; + + /* + * Table 10.3a.0.1 of 44.060 + * MCS6,9: second segment starts at 74/2 = 37 + * MCS5,7: second segment starts at 56/2 = 28 + * MCS8: second segment starts at 31 + * MCS4: second segment starts at 44/2 = 22 + */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + if (*block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + switch (GprsCodingScheme::Scheme(cs_init)) { + case GprsCodingScheme::MCS6 : + case GprsCodingScheme::MCS9 : + *block_data = &rlc_data->block[37]; + break; + case GprsCodingScheme::MCS7 : + case GprsCodingScheme::MCS5 : + *block_data = &rlc_data->block[28]; + break; + case GprsCodingScheme::MCS8 : + *block_data = &rlc_data->block[31]; + break; + case GprsCodingScheme::MCS4 : + *block_data = &rlc_data->block[22]; + break; + default: + LOGP(DRLCMACDL, LOGL_ERROR, "Software error: " + "--%s hit invalid condition. headerType(%d) " + " blockstatus(%d) cs(%s) PLEASE FIX!\n", name(), + cs_current_trans.headerTypeData(), + *block_status_dl, cs_init.name()); + break; + + } + return EGPRS_RESEG_SECOND_SEG_SENT; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } + } + return EGPRS_RESEG_DL_DEFAULT; +} + +/* + * This function returns the status of split block + * for RLC/MAC block. + */ +unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_status(const int bsn) +{ + const gprs_rlc_data *rlc_data = m_rlc.block(bsn); + + return rlc_data->spb_status.block_status_dl; +} + +/* + * This function returns the spb value to be sent OTA + * for RLC/MAC block. + */ +unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_value(const int bsn) +{ + struct gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state block_status_dl = + rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + + /* Table 10.4.8b.1 of 44.060 */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + /* + * if we are sending the second segment the spb should be 3 + * other wise it should be 2 + */ + if (block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + return 3; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return 2; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return 2; + } + } + /* Non SPB cases 0 is reurned */ + return 0; +} diff --git a/tests/edge/EdgeTest.cpp b/tests/edge/EdgeTest.cpp index 807102c..9081d4d 100644 --- a/tests/edge/EdgeTest.cpp +++ b/tests/edge/EdgeTest.cpp @@ -517,7 +517,7 @@ /* TS 44.060, B.1 */ cs = GprsCodingScheme::CS4; - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -570,7 +570,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -592,7 +592,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -630,7 +630,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -669,7 +669,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -694,7 +694,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -719,7 +719,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -740,7 +740,7 @@ OSMO_ASSERT(data[0] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -777,7 +777,7 @@ cs = GprsCodingScheme::MCS4; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -835,7 +835,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -872,7 +872,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -923,7 +923,7 @@ OSMO_ASSERT(data[3] == 0); /* Block 3 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -967,7 +967,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -993,7 +993,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1020,7 +1020,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1074,7 +1074,7 @@ block_idx++) { struct gprs_rlc_data_info rlc; - gprs_rlc_data_info_init_dl(&rlc, cs, false); + gprs_rlc_data_info_init_dl(&rlc, cs, false, 0); memset(bits, pattern, sizeof(bits)); Decoding::rlc_copy_to_aligned_buffer( @@ -1118,12 +1118,14 @@ struct gprs_rlc_data_info rlc; printf("=== start %s ===\n", __func__); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::CS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::CS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 24); OSMO_ASSERT(rlc.block_info[0].data_len == 20); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::MCS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::MCS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 33); OSMO_ASSERT(rlc.block_info[0].data_len == 22); diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..18cc5cb 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -1814,6 +1814,201 @@ } +static void egprs_spb_to_normal_validation(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + uint16_t bsn1, bsn2, bsn3; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + struct gprs_rlc_dl_header_egprs_2 *egprs2; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + if ((mcs == 6) && (demanded_mcs == 3)) { + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + bsn1 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) + || (egprs2->bsn1_lo); + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(bsn1 == 0); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + bsn2 = (egprs3->bsn1_hi << 9) || (egprs3->bsn1_mid << 1) || + (egprs3->bsn1_lo); + OSMO_ASSERT(bsn2 == bsn1); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Handle (MCS3, MCS3) -> MCS6 case */ + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + mcs)); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs2->cps == 0); + bsn3 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) || + (egprs2->bsn1_lo); + OSMO_ASSERT(bsn3 == bsn2); + + tbf_cleanup(dl_tbf); + } +} +static void establish_and_use_egprs_dl_tbf_for_spb(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + /* TODO: Need to support of MCS8 -> MCS6 ->MCS3 transistion + * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 + * dated 2016-02-07 23:45:40 (UTC) + */ + if (((mcs == 5) && (demanded_mcs == 2)) || + ((mcs == 6) && (demanded_mcs == 3)) || + ((mcs == 4) && (demanded_mcs == 1))) { + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + tbf_cleanup(dl_tbf); + } +} + static void establish_and_use_egprs_dl_tbf_for_retx(BTS *the_bts, int mcs, int demanded_mcs) { @@ -1972,6 +2167,9 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; + /* First parameter is current MCS, second one is demanded_mcs */ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 6); @@ -1981,6 +2179,38 @@ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 9); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 7, 5); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 9, 6); + + printf("=== end %s ===\n", __func__); +} + +static void test_tbf_egprs_spb_dl(void) +{ + BTS the_bts; + gprs_rlcmac_bts *bts; + uint8_t ts_no = 4; + int i, j; + + printf("=== start %s ===\n", __func__); + + bts = the_bts.bts_data(); + bts->cs_downgrade_threshold = 0; + setup_bts(&the_bts, ts_no); + bts->dl_tbf_idle_msec = 200; + bts->egprs_enabled = 1; + + /* ARQ I resegmentation support */ + bts->dl_arq_type = EGPRS_ARQ1; + + /* + * First parameter is current MCS, second one is demanded_mcs + * currently only MCS5->MCS2, MCS6->3, MCS4->MCS1 is tested in UT + * rest scenarios has been integration tested + */ + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 6, 3); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 5, 2); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 4, 1); + /* check MCS6->(MCS3+MCS3)->MCS6 case */ + egprs_spb_to_normal_validation(&the_bts, 6, 3); printf("=== end %s ===\n", __func__); } @@ -1999,6 +2229,8 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; for (i = 1; i <= 9; i++) establish_and_use_egprs_dl_tbf(&the_bts, i); @@ -2071,6 +2303,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_egprs_spb_dl(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..7b3f339 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -72,6 +72,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -81,6 +82,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -157,6 +159,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -166,6 +169,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -242,6 +246,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -251,6 +256,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -259,6 +265,7 @@ - Sending new block at BSN 2, CS=CS-1 -- Chunk with length 160 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=13 block=3 data=07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b @@ -267,6 +274,7 @@ - Sending new block at BSN 3, CS=CS-1 -- Chunk with length 140 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=17 block=4 data=07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @@ -275,6 +283,7 @@ - Sending new block at BSN 4, CS=CS-1 -- Chunk with length 120 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=21 block=5 data=07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 @@ -283,6 +292,7 @@ - Sending new block at BSN 5, CS=CS-1 -- Chunk with length 100 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=26 block=6 data=07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 @@ -291,6 +301,7 @@ - Sending new block at BSN 6, CS=CS-1 -- Chunk with length 80 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=30 block=7 data=07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b @@ -299,6 +310,7 @@ - Sending new block at BSN 7, CS=CS-1 -- Chunk with length 60 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=34 block=8 data=07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f @@ -307,6 +319,7 @@ - Sending new block at BSN 8, CS=CS-1 -- Chunk with length 40 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=39 block=9 data=07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 @@ -315,6 +328,7 @@ - Sending new block at BSN 9, CS=CS-1 -- Chunk with length 20 would exactly fit into space (20): add length header with LI=0, to make frame extend to next block, and we are done data block (BSN 9, CS-1): 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=43 block=10 data=07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 @@ -326,6 +340,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=47 block=11 data=07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 @@ -334,6 +349,7 @@ - Sending new block at BSN 11, CS=CS-1 -- Chunk with length 182 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=52 block=0 data=07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 @@ -342,6 +358,7 @@ - Sending new block at BSN 12, CS=CS-1 -- Chunk with length 162 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=56 block=1 data=07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 @@ -350,6 +367,7 @@ - Sending new block at BSN 13, CS=CS-1 -- Chunk with length 142 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 13, CS-1): 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=60 block=2 data=07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d @@ -358,6 +376,7 @@ - Sending new block at BSN 14, CS=CS-1 -- Chunk with length 122 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=65 block=3 data=07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 @@ -366,6 +385,7 @@ - Sending new block at BSN 15, CS=CS-1 -- Chunk with length 102 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=69 block=4 data=07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 @@ -374,6 +394,7 @@ - Sending new block at BSN 16, CS=CS-1 -- Chunk with length 82 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=73 block=5 data=07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 @@ -382,6 +403,7 @@ - Sending new block at BSN 17, CS=CS-1 -- Chunk with length 62 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=78 block=6 data=07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d @@ -390,6 +412,7 @@ - Sending new block at BSN 18, CS=CS-1 -- Chunk with length 42 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=82 block=7 data=07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 @@ -398,6 +421,7 @@ - Sending new block at BSN 19, CS=CS-1 -- Chunk with length 22 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=86 block=8 data=07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 @@ -411,6 +435,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=16 data block (BSN 20, CS-1): 0a 41 c6 c7 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -449,6 +474,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 data block (BSN 21, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -468,6 +494,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 22, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FINISHED) @@ -1481,6 +1508,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 0, CS-1): 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 MSG = 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 @@ -1491,6 +1519,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 1, CS-1): 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 MSG = 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 @@ -1501,6 +1530,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FINISHED data block (BSN 2, CS-1): 4d 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling cannot be scheduled in this TS 7 (first control TS 4) @@ -1784,6 +1814,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=10 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 0, CS-4): 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654292 TS 7 @@ -1797,6 +1828,7 @@ TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) downlink (V(A)==0 .. V(S)==1) - Restarting at BSN 0, because all blocks have been transmitted. - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-4): 07 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 @@ -2365,6 +2397,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654279 block=10 data=00 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 @@ -2384,6 +2417,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -2406,6 +2440,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654288 block=0 data=00 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 @@ -2425,6 +2460,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654292 block=1 data=00 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2447,6 +2483,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654296 block=2 data=00 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c @@ -2466,6 +2503,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654301 block=3 data=00 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b @@ -2488,6 +2526,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 6, CS-1): 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654305 block=4 data=00 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 @@ -2507,6 +2546,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654309 block=5 data=00 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 @@ -2526,6 +2566,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654314 block=6 data=00 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 @@ -2548,6 +2589,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654318 block=7 data=00 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 @@ -2567,6 +2609,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654322 block=8 data=00 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2589,6 +2632,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654327 block=9 data=00 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c @@ -2608,6 +2652,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654331 block=10 data=00 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b @@ -2630,6 +2675,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 13, CS-1): 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654335 block=11 data=00 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 @@ -2649,6 +2695,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654340 block=0 data=00 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 @@ -2668,6 +2715,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654344 block=1 data=00 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 @@ -2690,6 +2738,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654348 block=2 data=00 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 @@ -2709,6 +2758,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654353 block=3 data=00 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2731,6 +2781,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654357 block=4 data=00 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c @@ -2750,6 +2801,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654361 block=5 data=00 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b @@ -2772,6 +2824,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 20, CS-1): 16 35 45 54 20 32 38 4c 4c 43 20 50 41 43 4b 45 54 20 32 39 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because 20 blocks sent. TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW): Scheduling polling at FN 2654379 TS 7 @@ -2795,6 +2848,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 21, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) msg block (BSN 21, CS-1): 07 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654370 block=7 data=00 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 @@ -2814,6 +2868,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 22, CS-1): 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) msg block (BSN 22, CS-1): 07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654374 block=8 data=07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 @@ -2836,6 +2891,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 23, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) msg block (BSN 23, CS-1): 07 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654379 block=9 data=00 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 @@ -2855,6 +2911,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 24, CS-1): 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) msg block (BSN 24, CS-1): 07 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654383 block=10 data=00 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2877,6 +2934,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 25, CS-1): 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 25 BSN2 -1) - Copying data unit 0 (BSN 25) msg block (BSN 25, CS-1): 07 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654387 block=11 data=00 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c @@ -2896,6 +2954,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 26, CS-1): 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 26 BSN2 -1) - Copying data unit 0 (BSN 26) msg block (BSN 26, CS-1): 07 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654392 block=0 data=00 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b @@ -2918,6 +2977,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 27, CS-1): 16 35 45 54 20 33 38 4c 4c 43 20 50 41 43 4b 45 54 20 33 39 +- need_padding 0 spb_status 0 spb 0(BSN1 27 BSN2 -1) - Copying data unit 0 (BSN 27) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) @@ -3028,6 +3088,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654405 block=3 data=00 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 @@ -3047,6 +3108,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654409 block=4 data=00 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 @@ -3066,6 +3128,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (16) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654413 block=5 data=00 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 @@ -3085,6 +3148,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (14) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654418 block=6 data=00 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 @@ -3104,6 +3168,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654422 block=7 data=00 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -3123,6 +3188,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654426 block=8 data=00 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 @@ -3142,6 +3208,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654431 block=9 data=00 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b @@ -3161,6 +3228,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654435 block=10 data=00 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 @@ -3180,6 +3248,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654439 block=11 data=00 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 @@ -3199,6 +3268,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654444 block=0 data=00 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c @@ -3218,6 +3288,7 @@ Complete DL frame for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=21 TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 10, CS-1): 4d 43 20 50 41 43 4b 45 54 20 30 39 20 28 54 42 46 20 32 29 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654461 TS 7 @@ -3698,6 +3769,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 0, MCS-1): 14 15 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3711,6 +3783,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3721,6 +3794,7 @@ - Sending new block at BSN 2, CS=MCS-1 -- Chunk with length 490 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3731,6 +3805,7 @@ - Sending new block at BSN 3, CS=MCS-1 -- Chunk with length 468 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3741,6 +3816,7 @@ - Sending new block at BSN 4, CS=MCS-1 -- Chunk with length 446 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3751,6 +3827,7 @@ - Sending new block at BSN 5, CS=MCS-1 -- Chunk with length 424 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3761,6 +3838,7 @@ - Sending new block at BSN 6, CS=MCS-1 -- Chunk with length 402 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3771,6 +3849,7 @@ - Sending new block at BSN 7, CS=MCS-1 -- Chunk with length 380 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3781,6 +3860,7 @@ - Sending new block at BSN 8, CS=MCS-1 -- Chunk with length 358 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3791,6 +3871,7 @@ - Sending new block at BSN 9, CS=MCS-1 -- Chunk with length 336 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3801,6 +3882,7 @@ - Sending new block at BSN 10, CS=MCS-1 -- Chunk with length 314 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3811,6 +3893,7 @@ - Sending new block at BSN 11, CS=MCS-1 -- Chunk with length 292 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3821,6 +3904,7 @@ - Sending new block at BSN 12, CS=MCS-1 -- Chunk with length 270 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3831,6 +3915,7 @@ - Sending new block at BSN 13, CS=MCS-1 -- Chunk with length 248 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3841,6 +3926,7 @@ - Sending new block at BSN 14, CS=MCS-1 -- Chunk with length 226 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3851,6 +3937,7 @@ - Sending new block at BSN 15, CS=MCS-1 -- Chunk with length 204 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3861,6 +3948,7 @@ - Sending new block at BSN 16, CS=MCS-1 -- Chunk with length 182 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3871,6 +3959,7 @@ - Sending new block at BSN 17, CS=MCS-1 -- Chunk with length 160 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3881,6 +3970,7 @@ - Sending new block at BSN 18, CS=MCS-1 -- Chunk with length 138 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3891,6 +3981,7 @@ - Sending new block at BSN 19, CS=MCS-1 -- Chunk with length 116 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 19, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3901,6 +3992,7 @@ - Sending new block at BSN 20, CS=MCS-1 -- Chunk with length 94 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 20, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3911,6 +4003,7 @@ - Sending new block at BSN 21, CS=MCS-1 -- Chunk with length 72 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 21, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3921,6 +4014,7 @@ - Sending new block at BSN 22, CS=MCS-1 -- Chunk with length 50 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 22, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3931,6 +4025,7 @@ - Sending new block at BSN 23, CS=MCS-1 -- Chunk with length 28 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 23, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3946,6 +4041,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 24, MCS-1): 0c 1d 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4006,6 +4102,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=16 data block (BSN 0, MCS-2): 14 21 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4019,6 +4116,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4029,6 +4127,7 @@ - Sending new block at BSN 2, CS=MCS-2 -- Chunk with length 484 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4039,6 +4138,7 @@ - Sending new block at BSN 3, CS=MCS-2 -- Chunk with length 456 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4049,6 +4149,7 @@ - Sending new block at BSN 4, CS=MCS-2 -- Chunk with length 428 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4059,6 +4160,7 @@ - Sending new block at BSN 5, CS=MCS-2 -- Chunk with length 400 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4069,6 +4171,7 @@ - Sending new block at BSN 6, CS=MCS-2 -- Chunk with length 372 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4079,6 +4182,7 @@ - Sending new block at BSN 7, CS=MCS-2 -- Chunk with length 344 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4089,6 +4193,7 @@ - Sending new block at BSN 8, CS=MCS-2 -- Chunk with length 316 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4099,6 +4204,7 @@ - Sending new block at BSN 9, CS=MCS-2 -- Chunk with length 288 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4109,6 +4215,7 @@ - Sending new block at BSN 10, CS=MCS-2 -- Chunk with length 260 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4119,6 +4226,7 @@ - Sending new block at BSN 11, CS=MCS-2 -- Chunk with length 232 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4129,6 +4237,7 @@ - Sending new block at BSN 12, CS=MCS-2 -- Chunk with length 204 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4139,6 +4248,7 @@ - Sending new block at BSN 13, CS=MCS-2 -- Chunk with length 176 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4149,6 +4259,7 @@ - Sending new block at BSN 14, CS=MCS-2 -- Chunk with length 148 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4159,6 +4270,7 @@ - Sending new block at BSN 15, CS=MCS-2 -- Chunk with length 120 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4169,6 +4281,7 @@ - Sending new block at BSN 16, CS=MCS-2 -- Chunk with length 92 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4179,6 +4292,7 @@ - Sending new block at BSN 17, CS=MCS-2 -- Chunk with length 64 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4189,6 +4303,7 @@ - Sending new block at BSN 18, CS=MCS-2 -- Chunk with length 36 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4204,6 +4319,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=18 data block (BSN 19, MCS-2): 10 25 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4264,6 +4380,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=25 data block (BSN 0, MCS-3): 14 33 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4277,6 +4394,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4287,6 +4405,7 @@ - Sending new block at BSN 2, CS=MCS-3 -- Chunk with length 475 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4297,6 +4416,7 @@ - Sending new block at BSN 3, CS=MCS-3 -- Chunk with length 438 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4307,6 +4427,7 @@ - Sending new block at BSN 4, CS=MCS-3 -- Chunk with length 401 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4317,6 +4438,7 @@ - Sending new block at BSN 5, CS=MCS-3 -- Chunk with length 364 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4327,6 +4449,7 @@ - Sending new block at BSN 6, CS=MCS-3 -- Chunk with length 327 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4337,6 +4460,7 @@ - Sending new block at BSN 7, CS=MCS-3 -- Chunk with length 290 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4347,6 +4471,7 @@ - Sending new block at BSN 8, CS=MCS-3 -- Chunk with length 253 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4357,6 +4482,7 @@ - Sending new block at BSN 9, CS=MCS-3 -- Chunk with length 216 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4367,6 +4493,7 @@ - Sending new block at BSN 10, CS=MCS-3 -- Chunk with length 179 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4377,6 +4504,7 @@ - Sending new block at BSN 11, CS=MCS-3 -- Chunk with length 142 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4387,6 +4515,7 @@ - Sending new block at BSN 12, CS=MCS-3 -- Chunk with length 105 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4397,6 +4526,7 @@ - Sending new block at BSN 13, CS=MCS-3 -- Chunk with length 68 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4410,6 +4540,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-3): 3f 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4425,6 +4556,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=34 data block (BSN 15, MCS-3): 02 45 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4485,6 +4617,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=32 data block (BSN 0, MCS-4): 14 41 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4498,6 +4631,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4508,6 +4642,7 @@ - Sending new block at BSN 2, CS=MCS-4 -- Chunk with length 468 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4518,6 +4653,7 @@ - Sending new block at BSN 3, CS=MCS-4 -- Chunk with length 424 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4528,6 +4664,7 @@ - Sending new block at BSN 4, CS=MCS-4 -- Chunk with length 380 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4538,6 +4675,7 @@ - Sending new block at BSN 5, CS=MCS-4 -- Chunk with length 336 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4548,6 +4686,7 @@ - Sending new block at BSN 6, CS=MCS-4 -- Chunk with length 292 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4558,6 +4697,7 @@ - Sending new block at BSN 7, CS=MCS-4 -- Chunk with length 248 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4568,6 +4708,7 @@ - Sending new block at BSN 8, CS=MCS-4 -- Chunk with length 204 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4578,6 +4719,7 @@ - Sending new block at BSN 9, CS=MCS-4 -- Chunk with length 160 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4588,6 +4730,7 @@ - Sending new block at BSN 10, CS=MCS-4 -- Chunk with length 116 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4598,6 +4741,7 @@ - Sending new block at BSN 11, CS=MCS-4 -- Chunk with length 72 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4613,6 +4757,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 12, MCS-4): 38 1d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4673,6 +4818,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-5): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4686,6 +4832,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4696,6 +4843,7 @@ - Sending new block at BSN 2, CS=MCS-5 -- Chunk with length 456 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4706,6 +4854,7 @@ - Sending new block at BSN 3, CS=MCS-5 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4716,6 +4865,7 @@ - Sending new block at BSN 4, CS=MCS-5 -- Chunk with length 344 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4726,6 +4876,7 @@ - Sending new block at BSN 5, CS=MCS-5 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4736,6 +4887,7 @@ - Sending new block at BSN 6, CS=MCS-5 -- Chunk with length 232 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4746,6 +4898,7 @@ - Sending new block at BSN 7, CS=MCS-5 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4756,6 +4909,7 @@ - Sending new block at BSN 8, CS=MCS-5 -- Chunk with length 120 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4766,6 +4920,7 @@ - Sending new block at BSN 9, CS=MCS-5 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4781,6 +4936,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-5): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4841,6 +4997,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-6): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4854,6 +5011,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4864,6 +5022,7 @@ - Sending new block at BSN 2, CS=MCS-6 -- Chunk with length 438 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4874,6 +5033,7 @@ - Sending new block at BSN 3, CS=MCS-6 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4884,6 +5044,7 @@ - Sending new block at BSN 4, CS=MCS-6 -- Chunk with length 290 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4894,6 +5055,7 @@ - Sending new block at BSN 5, CS=MCS-6 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4904,6 +5066,7 @@ - Sending new block at BSN 6, CS=MCS-6 -- Chunk with length 142 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4917,6 +5080,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-6): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4932,6 +5096,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-6): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4993,6 +5158,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-7): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5002,12 +5168,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(7) last_mcs(5) demanded_mcs(7)cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-7 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5022,6 +5189,7 @@ - Sending new block at BSN 3, CS=MCS-7 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5036,6 +5204,7 @@ - Sending new block at BSN 5, CS=MCS-7 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5050,6 +5219,7 @@ - Sending new block at BSN 7, CS=MCS-7 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5064,6 +5234,7 @@ - Sending new block at BSN 9, CS=MCS-7 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 9) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5081,6 +5252,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-7): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5142,6 +5314,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=56 data block (BSN 0, MCS-8): 14 71 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5152,12 +5325,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(8) demanded_mcs(8) cs_trans(8) +- initial_cs_dl(8) last_mcs(8) demanded_mcs(8)cs_trans(8) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-8 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5172,6 +5346,7 @@ - Sending new block at BSN 3, CS=MCS-8 -- Chunk with length 376 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5186,6 +5361,7 @@ - Sending new block at BSN 5, CS=MCS-8 -- Chunk with length 240 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5200,6 +5376,7 @@ - Sending new block at BSN 7, CS=MCS-8 -- Chunk with length 104 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5217,6 +5394,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=30 data block (BSN 8, MCS-8): 48 3d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5279,6 +5457,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-9): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5288,12 +5467,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(9) last_mcs(6) demanded_mcs(9)cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-9 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5308,6 +5488,7 @@ - Sending new block at BSN 3, CS=MCS-9 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5322,6 +5503,7 @@ - Sending new block at BSN 5, CS=MCS-9 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5339,6 +5521,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-9): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5356,6 +5539,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-9): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5402,11 +5586,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(6)cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5450,11 +5636,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 96 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(1) demanded_mcs(1) cs_trans(1) +- initial_cs_dl(1) last_mcs(1) demanded_mcs(1)cs_trans(1) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 98 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5498,11 +5686,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-2): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 92 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(2) demanded_mcs(2) cs_trans(2) +- initial_cs_dl(2) last_mcs(2) demanded_mcs(2)cs_trans(2) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 94 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5546,6 +5736,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5557,6 +5748,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-5): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5564,10 +5756,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-5): 0f 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7)cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7)cs_trans(7) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-7): 07 00 00 02 c0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 @@ -5612,6 +5805,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5623,6 +5817,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-6): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5630,10 +5825,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-6): 0f 40 00 00 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9)cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9)cs_trans(9) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-9): 07 00 00 02 28 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 @@ -5686,6 +5882,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-7): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5694,13 +5891,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-7): 0f 00 00 02 a0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5)cs_trans(5) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5)cs_trans(5) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-5): 07 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5752,6 +5951,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-9): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5760,13 +5960,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-9): 0f 00 00 02 00 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6)cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6)cs_trans(6) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-6): 07 40 00 02 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5780,3 +5982,233 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-5 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(2)cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 d2 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(2) demanded_mcs(2)cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 f2 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-4 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (44) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-4): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-4): 07 00 00 80 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(4) demanded_mcs(1)cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 d6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(1) demanded_mcs(1)cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 f6 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(6)cs_trans(6) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 2 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..c38417d 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,9 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_egprs_spb_dl === +Testing retx for MCS 6 to reseg_mcs 3 +Testing retx for MCS 5 to reseg_mcs 2 +Testing retx for MCS 4 to reseg_mcs 1 +Testing retx for MCS 6 to reseg_mcs 3 +=== end test_tbf_egprs_spb_dl === -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 9 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Wed Aug 10 08:10:03 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Wed, 10 Aug 2016 08:10:03 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 9: (1 comment) https://gerrit.osmocom.org/#/c/655/9/src/pcu_vty.c File src/pcu_vty.c: Line 133: vty_out(vty, " dl arq %d %s", bts->dl_arq_type, VTY_NEWLINE); edit here also -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 9 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Wed Aug 10 08:10:36 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Wed, 10 Aug 2016 08:10:36 +0000 Subject: [PATCH] osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/655 to look at the new patch set (#10). Modify EGPRS DL TBF flow to support SPB Modify the EGPRS DL TBF flow to support Split block during Retx. This patch will also Upgrade the test suite with test cases to validate the EGPRS Downlink SPB for Retransmission Scenarios like MCS6->MCS3, MCS4->MCS1, MCS5->MCS2, MCS9->MCS3 MCS7->MCS2, MCS8->MCS3 have been simulated and Integration tested in NuRAN 1.0 hardware thoroughly. Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 --- M src/gprs_coding_scheme.h M src/pcu_main.cpp M src/pcu_vty.c M src/rlc.cpp M src/rlc.h M src/tbf.h M src/tbf_dl.cpp M tests/edge/EdgeTest.cpp M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 11 files changed, 948 insertions(+), 77 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/55/655/10 diff --git a/src/gprs_coding_scheme.h b/src/gprs_coding_scheme.h index 60a8e79..3b15372 100644 --- a/src/gprs_coding_scheme.h +++ b/src/gprs_coding_scheme.h @@ -113,7 +113,8 @@ static const char *modeName(Mode mode); static Scheme get_retx_mcs(const GprsCodingScheme mcs, - const GprsCodingScheme retx_mcs); + const GprsCodingScheme retx_mcs, + const unsigned arq_type); static enum Scheme egprs_mcs_retx_tbl[MAX_NUM_ARQ] [MAX_NUM_MCS][MAX_NUM_MCS]; @@ -232,8 +233,9 @@ } inline GprsCodingScheme::Scheme GprsCodingScheme::get_retx_mcs( const GprsCodingScheme mcs, - const GprsCodingScheme demanded_mcs) + const GprsCodingScheme demanded_mcs, + const unsigned arq_type) { - return egprs_mcs_retx_tbl[EGPRS_ARQ2][mcs.to_num() - 1] + return egprs_mcs_retx_tbl[arq_type][mcs.to_num() - 1] [demanded_mcs.to_num() - 1]; } diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2d86cda..e34d534 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -210,6 +210,12 @@ bts->dl_tbf_idle_msec = 2000; bts->llc_idle_ack_csec = 10; + /* + * By default resegmentation is supported in DL + * can also be configured through VTY + */ + bts->dl_arq_type = EGPRS_ARQ1; + msgb_set_talloc_ctx(tall_pcu_ctx); osmo_init_logging(&gprs_log_info); diff --git a/src/pcu_vty.c b/src/pcu_vty.c index 58fea99..1eb29fe 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -129,6 +129,9 @@ vty_out(vty, " window-size %d %d%s", bts->ws_base, bts->ws_pdch, VTY_NEWLINE); + if (bts->dl_arq_type) + vty_out(vty, " dl arq-type %d %s", bts->dl_arq_type, VTY_NEWLINE); + if (bts->force_llc_lifetime == 0xffff) vty_out(vty, " queue lifetime infinite%s", VTY_NEWLINE); else if (bts->force_llc_lifetime) @@ -477,6 +480,20 @@ bts->max_mcs_dl = 0; bts->max_mcs_ul = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_pcu_dl_arq_type, + cfg_pcu_dl_arq_cmd, + "dl arq-type (0|1)", + EGPRS_STR "DL ARQ options\n" + "enable DL SPB support\n" + "enable DL ARQ2 support") +{ + struct gprs_rlcmac_bts *bts = bts_main_data(); + uint8_t dl_arq_type = atoi(argv[0]); + + bts->dl_arq_type = dl_arq_type; return CMD_SUCCESS; } @@ -954,6 +971,7 @@ install_element(PCU_NODE, &cfg_pcu_no_cs_downgrade_thrsh_cmd); install_element(PCU_NODE, &cfg_pcu_cs_lqual_ranges_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_cmd); + install_element(PCU_NODE, &cfg_pcu_dl_arq_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_max_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_max_cmd); diff --git a/src/rlc.cpp b/src/rlc.cpp index 6770043..8da96f7 100644 --- a/src/rlc.cpp +++ b/src/rlc.cpp @@ -285,7 +285,8 @@ } static void gprs_rlc_data_header_init(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding, unsigned int header_bits) + GprsCodingScheme cs, bool with_padding, unsigned int header_bits, + const unsigned int spb) { unsigned int i; unsigned int padding_bits = with_padding ? cs.optionalPaddingBits() : 0; @@ -300,7 +301,7 @@ for (i = 0; i < rlc->num_data_blocks; i++) { gprs_rlc_data_block_info_init(&rlc->block_info[i], cs, - with_padding); + with_padding, spb); rlc->data_offs_bits[i] = header_bits + padding_bits + @@ -310,21 +311,25 @@ } void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsDL()); + cs.numDataHeaderBitsDL(), spb); } void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding) { + /* + * last parameter is sent as 0 since common function used + * for both DL and UL + */ return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsUL()); + cs.numDataHeaderBitsUL(), 0); } void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { unsigned int data_len = cs.maxDataBlockBytes(); if (with_padding) @@ -336,7 +341,7 @@ rdbi->e = 1; rdbi->cv = 15; rdbi->pi = 0; - rdbi->spb = 0; + rdbi->spb = spb; } unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, @@ -411,8 +416,17 @@ enum egprs_puncturing_values gprs_get_punct_scheme( enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current) + const GprsCodingScheme &cs_current, + const unsigned int spb) { + + /* + * If it is second segment of the block + * dont change the puncturing scheme + */ + if (spb == 3) + return punct; + /* TS 44.060 9.3.2.1.1 */ if ((GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS9) && (GprsCodingScheme::Scheme(cs_current) == GprsCodingScheme::MCS6)) { diff --git a/src/rlc.h b/src/rlc.h index 539b30b..66faf6f 100644 --- a/src/rlc.h +++ b/src/rlc.h @@ -206,18 +206,19 @@ }; void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding); void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, enum egprs_puncturing_values punct, enum egprs_puncturing_values punct2, int with_padding); void gprs_rlc_mcs_cps_decode(unsigned int cps, GprsCodingScheme cs, int *punct, int *punct2, int *with_padding); enum egprs_puncturing_values gprs_get_punct_scheme(enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current_trans); + const GprsCodingScheme &cs_current_trans, + const unsigned int spb); void gprs_update_punct_scheme(enum egprs_puncturing_values *punct, const GprsCodingScheme &cs); /* diff --git a/src/tbf.h b/src/tbf.h index 1bd7878..969836b 100644 --- a/src/tbf.h +++ b/src/tbf.h @@ -421,6 +421,11 @@ int analyse_errors(char *show_rbb, uint8_t ssn, ana_result *res); void schedule_next_frame(); + enum egprs_rlc_dl_reseg_bsn_state egprs_dl_get_data_buffer + (int bsn, uint8_t **block_data); + unsigned int get_egprs_dl_spb_status(int bsn); + unsigned int get_egprs_dl_spb_value(int bsn); + struct osmo_timer_list m_llc_timer; }; diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp index 07a747a..0395ed0 100644 --- a/src/tbf_dl.cpp +++ b/src/tbf_dl.cpp @@ -375,21 +375,27 @@ return -1; if (is_egprs_enabled()) { + /* Table 8.1.1.2 and Table 8.1.1.1 of 44.060 */ m_rlc.block(bsn)->cs_current_trans = - GprsCodingScheme::get_retx_mcs( - m_rlc.block(bsn)->cs_last, ms()->current_cs_dl()); + GprsCodingScheme::get_retx_mcs( + m_rlc.block(bsn)->cs_init, + ms()->current_cs_dl(), + bts->bts_data()->dl_arq_type); LOGP(DRLCMACDL, LOGL_DEBUG, - "- current_cs_dl(%d) demanded_mcs(%d) cs_trans(%d)\n", + "- initial_cs_dl(%d) last_mcs(%d) demanded_mcs(%d)" + "cs_trans(%d) arq_type(%d) bsn(%d)\n", + m_rlc.block(bsn)->cs_init.to_num(), m_rlc.block(bsn)->cs_last.to_num(), ms()->current_cs_dl().to_num(), - m_rlc.block(bsn)->cs_current_trans.to_num()); + m_rlc.block(bsn)->cs_current_trans.to_num(), + bts->bts_data()->dl_arq_type, bsn); /* TODO: Need to remove this check when MCS-8 -> MCS-6 * transistion is handled. * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 */ - if (m_rlc.block(bsn)->cs_last == GprsCodingScheme::MCS8) + if (m_rlc.block(bsn)->cs_init == GprsCodingScheme::MCS8) m_rlc.block(bsn)->cs_current_trans = GprsCodingScheme::MCS8; } else @@ -523,6 +529,11 @@ data = rlc_data->prepare(block_data_len); rlc_data->cs_last = cs; rlc_data->cs_current_trans = cs; + + /* Initialise the variable related to DL SPB */ + rlc_data->spb_status.block_status_dl = EGPRS_RESEG_DL_DEFAULT; + rlc_data->cs_init = cs; + rlc_data->len = block_data_len; rdbi = &(rlc_data->block_info); @@ -616,6 +627,7 @@ unsigned num_bsns; enum egprs_puncturing_values punct[ARRAY_SIZE(rlc.block_info)]; bool need_padding = false; + unsigned int spb = 0; /* * TODO: This is an experimental work-around to put 2 BSN into @@ -626,6 +638,7 @@ * the current limit. */ cs = m_rlc.block(index)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(index)->cs_init; bsns[0] = index; num_bsns = 1; @@ -634,7 +647,19 @@ num_bsns += 1; } - if (num_bsns == 1) { + /* + * if the intial mcs is 8 and retransmission mcs is either 6 or 3 + * we have to include the padding of 6 octets in first segment + */ + if ((GprsCodingScheme::Scheme(cs_init) == GprsCodingScheme::MCS8) && + (GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS6 || + GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS3)) { + if ((get_egprs_dl_spb_status(index) == + EGPRS_RESEG_DL_DEFAULT) || + (get_egprs_dl_spb_status(index) == + EGPRS_RESEG_SECOND_SEG_SENT)) + need_padding = true; + } else if (num_bsns == 1) { /* TODO: remove the conditional when MCS-6 padding isn't * failing to be decoded by MEs anymore */ /* TODO: support of MCS-8 -> MCS-6 transition should be @@ -646,7 +671,14 @@ cs.decToSingleBlock(&need_padding); } - gprs_rlc_data_info_init_dl(&rlc, cs, need_padding); + spb = get_egprs_dl_spb_value(index); + + LOGP(DRLCMACDL, LOGL_DEBUG, "- need_padding %d spb_status %d spb %d" + "(BSN1 %d BSN2 %d)\n", + need_padding, + get_egprs_dl_spb_status(index), spb, index, index2); + + gprs_rlc_data_info_init_dl(&rlc, cs, need_padding, spb); rlc.usf = 7; /* will be set at scheduler */ rlc.pr = 0; /* FIXME: power reduction */ @@ -665,10 +697,9 @@ data_block_idx++) { int bsn; - GprsCodingScheme cs_enc; uint8_t *block_data; gprs_rlc_data_block_info *rdbi, *block_info; - enum egprs_puncturing_values punct_scheme; + enum egprs_rlc_dl_reseg_bsn_state reseg_status; /* Check if there are more blocks than BSNs */ if (data_block_idx < num_bsns) @@ -676,38 +707,43 @@ else bsn = bsns[0]; - cs_enc = m_rlc.block(bsn)->cs_current_trans; - /* get data and header from current block */ - block_data = m_rlc.block(bsn)->block; - /* Get current puncturing scheme from block */ - punct_scheme = gprs_get_punct_scheme( + + m_rlc.block(bsn)->next_ps = gprs_get_punct_scheme( m_rlc.block(bsn)->next_ps, - m_rlc.block(bsn)->cs_last, cs); + m_rlc.block(bsn)->cs_last, cs, spb); if (cs.isEgprs()) { - OSMO_ASSERT(punct_scheme >= EGPRS_PS_1); - OSMO_ASSERT(punct_scheme <= EGPRS_PS_3); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps >= EGPRS_PS_1); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps <= EGPRS_PS_3); } - punct[data_block_idx] = punct_scheme; + punct[data_block_idx] = m_rlc.block(bsn)->next_ps; rdbi = &rlc.block_info[data_block_idx]; block_info = &m_rlc.block(bsn)->block_info; - if(rdbi->data_len != m_rlc.block(bsn)->len) { - LOGP(DRLCMACDL, LOGL_ERROR, - "ERROR: Expected len = %d for %s instead of " - "%d in data unit %d (BSN %d, %s)\n", - rdbi->data_len, cs.name(), m_rlc.block(bsn)->len, - data_block_idx, bsn, cs_enc.name()); - OSMO_ASSERT(rdbi->data_len == m_rlc.block(bsn)->len); - } - - /* TODO: Need to handle 2 same bsns - * in header type 1 + /* + * get data and header from current block + * function returns the reseg status */ - gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, - cs); + reseg_status = egprs_dl_get_data_buffer(bsn, &block_data); + m_rlc.block(bsn)->spb_status.block_status_dl = reseg_status; + + /* + * If it is first segment of the split block set the state of + * bsn to nacked. If it is the first segment dont update the + * next ps value of bsn. since next segment also needs same cps + */ + if (spb == 2) + m_window.m_v_b.mark_nacked(bsn); + else { + /* + * TODO: Need to handle 2 same bsns + * in header type 1 + */ + gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, + cs); + } m_rlc.block(bsn)->cs_last = cs; rdbi->e = block_info->e; @@ -1169,3 +1205,119 @@ keep_time_frames = msecs_to_frames(bts_data()->dl_tbf_idle_msec); return frames_since_last_drain(fn) <= keep_time_frames; } + +/* + * This function returns the pointer to data which needs + * to be copied. Also updates the status of the block related to + * Split block handling in the RLC/MAC block. + */ +enum egprs_rlc_dl_reseg_bsn_state + gprs_rlcmac_dl_tbf::egprs_dl_get_data_buffer(int bsn, + uint8_t **block_data) +{ + gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state *block_status_dl = + &rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + *block_data = &rlc_data->block[0]; + + /* + * Table 10.3a.0.1 of 44.060 + * MCS6,9: second segment starts at 74/2 = 37 + * MCS5,7: second segment starts at 56/2 = 28 + * MCS8: second segment starts at 31 + * MCS4: second segment starts at 44/2 = 22 + */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + if (*block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + switch (GprsCodingScheme::Scheme(cs_init)) { + case GprsCodingScheme::MCS6 : + case GprsCodingScheme::MCS9 : + *block_data = &rlc_data->block[37]; + break; + case GprsCodingScheme::MCS7 : + case GprsCodingScheme::MCS5 : + *block_data = &rlc_data->block[28]; + break; + case GprsCodingScheme::MCS8 : + *block_data = &rlc_data->block[31]; + break; + case GprsCodingScheme::MCS4 : + *block_data = &rlc_data->block[22]; + break; + default: + LOGP(DRLCMACDL, LOGL_ERROR, "Software error: " + "--%s hit invalid condition. headerType(%d) " + " blockstatus(%d) cs(%s) PLEASE FIX!\n", name(), + cs_current_trans.headerTypeData(), + *block_status_dl, cs_init.name()); + break; + + } + return EGPRS_RESEG_SECOND_SEG_SENT; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } + } + return EGPRS_RESEG_DL_DEFAULT; +} + +/* + * This function returns the status of split block + * for RLC/MAC block. + */ +unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_status(const int bsn) +{ + const gprs_rlc_data *rlc_data = m_rlc.block(bsn); + + return rlc_data->spb_status.block_status_dl; +} + +/* + * This function returns the spb value to be sent OTA + * for RLC/MAC block. + */ +unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_value(const int bsn) +{ + struct gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state block_status_dl = + rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + + /* Table 10.4.8b.1 of 44.060 */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + /* + * if we are sending the second segment the spb should be 3 + * other wise it should be 2 + */ + if (block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + return 3; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return 2; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return 2; + } + } + /* Non SPB cases 0 is reurned */ + return 0; +} diff --git a/tests/edge/EdgeTest.cpp b/tests/edge/EdgeTest.cpp index 807102c..9081d4d 100644 --- a/tests/edge/EdgeTest.cpp +++ b/tests/edge/EdgeTest.cpp @@ -517,7 +517,7 @@ /* TS 44.060, B.1 */ cs = GprsCodingScheme::CS4; - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -570,7 +570,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -592,7 +592,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -630,7 +630,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -669,7 +669,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -694,7 +694,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -719,7 +719,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -740,7 +740,7 @@ OSMO_ASSERT(data[0] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -777,7 +777,7 @@ cs = GprsCodingScheme::MCS4; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -835,7 +835,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -872,7 +872,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -923,7 +923,7 @@ OSMO_ASSERT(data[3] == 0); /* Block 3 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -967,7 +967,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -993,7 +993,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1020,7 +1020,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1074,7 +1074,7 @@ block_idx++) { struct gprs_rlc_data_info rlc; - gprs_rlc_data_info_init_dl(&rlc, cs, false); + gprs_rlc_data_info_init_dl(&rlc, cs, false, 0); memset(bits, pattern, sizeof(bits)); Decoding::rlc_copy_to_aligned_buffer( @@ -1118,12 +1118,14 @@ struct gprs_rlc_data_info rlc; printf("=== start %s ===\n", __func__); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::CS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::CS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 24); OSMO_ASSERT(rlc.block_info[0].data_len == 20); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::MCS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::MCS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 33); OSMO_ASSERT(rlc.block_info[0].data_len == 22); diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..18cc5cb 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -1814,6 +1814,201 @@ } +static void egprs_spb_to_normal_validation(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + uint16_t bsn1, bsn2, bsn3; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + struct gprs_rlc_dl_header_egprs_2 *egprs2; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + if ((mcs == 6) && (demanded_mcs == 3)) { + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + bsn1 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) + || (egprs2->bsn1_lo); + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(bsn1 == 0); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + bsn2 = (egprs3->bsn1_hi << 9) || (egprs3->bsn1_mid << 1) || + (egprs3->bsn1_lo); + OSMO_ASSERT(bsn2 == bsn1); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Handle (MCS3, MCS3) -> MCS6 case */ + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + mcs)); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs2->cps == 0); + bsn3 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) || + (egprs2->bsn1_lo); + OSMO_ASSERT(bsn3 == bsn2); + + tbf_cleanup(dl_tbf); + } +} +static void establish_and_use_egprs_dl_tbf_for_spb(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + /* TODO: Need to support of MCS8 -> MCS6 ->MCS3 transistion + * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 + * dated 2016-02-07 23:45:40 (UTC) + */ + if (((mcs == 5) && (demanded_mcs == 2)) || + ((mcs == 6) && (demanded_mcs == 3)) || + ((mcs == 4) && (demanded_mcs == 1))) { + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + tbf_cleanup(dl_tbf); + } +} + static void establish_and_use_egprs_dl_tbf_for_retx(BTS *the_bts, int mcs, int demanded_mcs) { @@ -1972,6 +2167,9 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; + /* First parameter is current MCS, second one is demanded_mcs */ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 6); @@ -1981,6 +2179,38 @@ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 9); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 7, 5); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 9, 6); + + printf("=== end %s ===\n", __func__); +} + +static void test_tbf_egprs_spb_dl(void) +{ + BTS the_bts; + gprs_rlcmac_bts *bts; + uint8_t ts_no = 4; + int i, j; + + printf("=== start %s ===\n", __func__); + + bts = the_bts.bts_data(); + bts->cs_downgrade_threshold = 0; + setup_bts(&the_bts, ts_no); + bts->dl_tbf_idle_msec = 200; + bts->egprs_enabled = 1; + + /* ARQ I resegmentation support */ + bts->dl_arq_type = EGPRS_ARQ1; + + /* + * First parameter is current MCS, second one is demanded_mcs + * currently only MCS5->MCS2, MCS6->3, MCS4->MCS1 is tested in UT + * rest scenarios has been integration tested + */ + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 6, 3); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 5, 2); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 4, 1); + /* check MCS6->(MCS3+MCS3)->MCS6 case */ + egprs_spb_to_normal_validation(&the_bts, 6, 3); printf("=== end %s ===\n", __func__); } @@ -1999,6 +2229,8 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; for (i = 1; i <= 9; i++) establish_and_use_egprs_dl_tbf(&the_bts, i); @@ -2071,6 +2303,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_egprs_spb_dl(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..7b3f339 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -72,6 +72,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -81,6 +82,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -157,6 +159,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -166,6 +169,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -242,6 +246,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -251,6 +256,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -259,6 +265,7 @@ - Sending new block at BSN 2, CS=CS-1 -- Chunk with length 160 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=13 block=3 data=07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b @@ -267,6 +274,7 @@ - Sending new block at BSN 3, CS=CS-1 -- Chunk with length 140 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=17 block=4 data=07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @@ -275,6 +283,7 @@ - Sending new block at BSN 4, CS=CS-1 -- Chunk with length 120 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=21 block=5 data=07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 @@ -283,6 +292,7 @@ - Sending new block at BSN 5, CS=CS-1 -- Chunk with length 100 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=26 block=6 data=07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 @@ -291,6 +301,7 @@ - Sending new block at BSN 6, CS=CS-1 -- Chunk with length 80 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=30 block=7 data=07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b @@ -299,6 +310,7 @@ - Sending new block at BSN 7, CS=CS-1 -- Chunk with length 60 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=34 block=8 data=07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f @@ -307,6 +319,7 @@ - Sending new block at BSN 8, CS=CS-1 -- Chunk with length 40 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=39 block=9 data=07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 @@ -315,6 +328,7 @@ - Sending new block at BSN 9, CS=CS-1 -- Chunk with length 20 would exactly fit into space (20): add length header with LI=0, to make frame extend to next block, and we are done data block (BSN 9, CS-1): 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=43 block=10 data=07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 @@ -326,6 +340,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=47 block=11 data=07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 @@ -334,6 +349,7 @@ - Sending new block at BSN 11, CS=CS-1 -- Chunk with length 182 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=52 block=0 data=07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 @@ -342,6 +358,7 @@ - Sending new block at BSN 12, CS=CS-1 -- Chunk with length 162 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=56 block=1 data=07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 @@ -350,6 +367,7 @@ - Sending new block at BSN 13, CS=CS-1 -- Chunk with length 142 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 13, CS-1): 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=60 block=2 data=07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d @@ -358,6 +376,7 @@ - Sending new block at BSN 14, CS=CS-1 -- Chunk with length 122 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=65 block=3 data=07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 @@ -366,6 +385,7 @@ - Sending new block at BSN 15, CS=CS-1 -- Chunk with length 102 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=69 block=4 data=07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 @@ -374,6 +394,7 @@ - Sending new block at BSN 16, CS=CS-1 -- Chunk with length 82 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=73 block=5 data=07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 @@ -382,6 +403,7 @@ - Sending new block at BSN 17, CS=CS-1 -- Chunk with length 62 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=78 block=6 data=07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d @@ -390,6 +412,7 @@ - Sending new block at BSN 18, CS=CS-1 -- Chunk with length 42 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=82 block=7 data=07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 @@ -398,6 +421,7 @@ - Sending new block at BSN 19, CS=CS-1 -- Chunk with length 22 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=86 block=8 data=07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 @@ -411,6 +435,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=16 data block (BSN 20, CS-1): 0a 41 c6 c7 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -449,6 +474,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 data block (BSN 21, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -468,6 +494,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 22, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FINISHED) @@ -1481,6 +1508,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 0, CS-1): 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 MSG = 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 @@ -1491,6 +1519,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 1, CS-1): 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 MSG = 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 @@ -1501,6 +1530,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FINISHED data block (BSN 2, CS-1): 4d 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling cannot be scheduled in this TS 7 (first control TS 4) @@ -1784,6 +1814,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=10 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 0, CS-4): 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654292 TS 7 @@ -1797,6 +1828,7 @@ TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) downlink (V(A)==0 .. V(S)==1) - Restarting at BSN 0, because all blocks have been transmitted. - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-4): 07 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 @@ -2365,6 +2397,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654279 block=10 data=00 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 @@ -2384,6 +2417,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -2406,6 +2440,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654288 block=0 data=00 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 @@ -2425,6 +2460,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654292 block=1 data=00 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2447,6 +2483,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654296 block=2 data=00 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c @@ -2466,6 +2503,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654301 block=3 data=00 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b @@ -2488,6 +2526,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 6, CS-1): 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654305 block=4 data=00 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 @@ -2507,6 +2546,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654309 block=5 data=00 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 @@ -2526,6 +2566,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654314 block=6 data=00 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 @@ -2548,6 +2589,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654318 block=7 data=00 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 @@ -2567,6 +2609,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654322 block=8 data=00 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2589,6 +2632,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654327 block=9 data=00 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c @@ -2608,6 +2652,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654331 block=10 data=00 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b @@ -2630,6 +2675,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 13, CS-1): 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654335 block=11 data=00 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 @@ -2649,6 +2695,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654340 block=0 data=00 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 @@ -2668,6 +2715,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654344 block=1 data=00 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 @@ -2690,6 +2738,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654348 block=2 data=00 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 @@ -2709,6 +2758,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654353 block=3 data=00 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2731,6 +2781,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654357 block=4 data=00 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c @@ -2750,6 +2801,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654361 block=5 data=00 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b @@ -2772,6 +2824,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 20, CS-1): 16 35 45 54 20 32 38 4c 4c 43 20 50 41 43 4b 45 54 20 32 39 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because 20 blocks sent. TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW): Scheduling polling at FN 2654379 TS 7 @@ -2795,6 +2848,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 21, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) msg block (BSN 21, CS-1): 07 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654370 block=7 data=00 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 @@ -2814,6 +2868,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 22, CS-1): 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) msg block (BSN 22, CS-1): 07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654374 block=8 data=07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 @@ -2836,6 +2891,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 23, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) msg block (BSN 23, CS-1): 07 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654379 block=9 data=00 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 @@ -2855,6 +2911,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 24, CS-1): 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) msg block (BSN 24, CS-1): 07 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654383 block=10 data=00 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2877,6 +2934,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 25, CS-1): 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 25 BSN2 -1) - Copying data unit 0 (BSN 25) msg block (BSN 25, CS-1): 07 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654387 block=11 data=00 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c @@ -2896,6 +2954,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 26, CS-1): 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 26 BSN2 -1) - Copying data unit 0 (BSN 26) msg block (BSN 26, CS-1): 07 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654392 block=0 data=00 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b @@ -2918,6 +2977,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 27, CS-1): 16 35 45 54 20 33 38 4c 4c 43 20 50 41 43 4b 45 54 20 33 39 +- need_padding 0 spb_status 0 spb 0(BSN1 27 BSN2 -1) - Copying data unit 0 (BSN 27) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) @@ -3028,6 +3088,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654405 block=3 data=00 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 @@ -3047,6 +3108,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654409 block=4 data=00 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 @@ -3066,6 +3128,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (16) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654413 block=5 data=00 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 @@ -3085,6 +3148,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (14) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654418 block=6 data=00 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 @@ -3104,6 +3168,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654422 block=7 data=00 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -3123,6 +3188,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654426 block=8 data=00 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 @@ -3142,6 +3208,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654431 block=9 data=00 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b @@ -3161,6 +3228,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654435 block=10 data=00 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 @@ -3180,6 +3248,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654439 block=11 data=00 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 @@ -3199,6 +3268,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654444 block=0 data=00 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c @@ -3218,6 +3288,7 @@ Complete DL frame for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=21 TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 10, CS-1): 4d 43 20 50 41 43 4b 45 54 20 30 39 20 28 54 42 46 20 32 29 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654461 TS 7 @@ -3698,6 +3769,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 0, MCS-1): 14 15 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3711,6 +3783,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3721,6 +3794,7 @@ - Sending new block at BSN 2, CS=MCS-1 -- Chunk with length 490 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3731,6 +3805,7 @@ - Sending new block at BSN 3, CS=MCS-1 -- Chunk with length 468 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3741,6 +3816,7 @@ - Sending new block at BSN 4, CS=MCS-1 -- Chunk with length 446 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3751,6 +3827,7 @@ - Sending new block at BSN 5, CS=MCS-1 -- Chunk with length 424 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3761,6 +3838,7 @@ - Sending new block at BSN 6, CS=MCS-1 -- Chunk with length 402 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3771,6 +3849,7 @@ - Sending new block at BSN 7, CS=MCS-1 -- Chunk with length 380 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3781,6 +3860,7 @@ - Sending new block at BSN 8, CS=MCS-1 -- Chunk with length 358 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3791,6 +3871,7 @@ - Sending new block at BSN 9, CS=MCS-1 -- Chunk with length 336 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3801,6 +3882,7 @@ - Sending new block at BSN 10, CS=MCS-1 -- Chunk with length 314 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3811,6 +3893,7 @@ - Sending new block at BSN 11, CS=MCS-1 -- Chunk with length 292 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3821,6 +3904,7 @@ - Sending new block at BSN 12, CS=MCS-1 -- Chunk with length 270 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3831,6 +3915,7 @@ - Sending new block at BSN 13, CS=MCS-1 -- Chunk with length 248 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3841,6 +3926,7 @@ - Sending new block at BSN 14, CS=MCS-1 -- Chunk with length 226 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3851,6 +3937,7 @@ - Sending new block at BSN 15, CS=MCS-1 -- Chunk with length 204 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3861,6 +3948,7 @@ - Sending new block at BSN 16, CS=MCS-1 -- Chunk with length 182 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3871,6 +3959,7 @@ - Sending new block at BSN 17, CS=MCS-1 -- Chunk with length 160 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3881,6 +3970,7 @@ - Sending new block at BSN 18, CS=MCS-1 -- Chunk with length 138 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3891,6 +3981,7 @@ - Sending new block at BSN 19, CS=MCS-1 -- Chunk with length 116 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 19, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3901,6 +3992,7 @@ - Sending new block at BSN 20, CS=MCS-1 -- Chunk with length 94 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 20, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3911,6 +4003,7 @@ - Sending new block at BSN 21, CS=MCS-1 -- Chunk with length 72 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 21, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3921,6 +4014,7 @@ - Sending new block at BSN 22, CS=MCS-1 -- Chunk with length 50 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 22, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3931,6 +4025,7 @@ - Sending new block at BSN 23, CS=MCS-1 -- Chunk with length 28 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 23, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3946,6 +4041,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 24, MCS-1): 0c 1d 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4006,6 +4102,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=16 data block (BSN 0, MCS-2): 14 21 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4019,6 +4116,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4029,6 +4127,7 @@ - Sending new block at BSN 2, CS=MCS-2 -- Chunk with length 484 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4039,6 +4138,7 @@ - Sending new block at BSN 3, CS=MCS-2 -- Chunk with length 456 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4049,6 +4149,7 @@ - Sending new block at BSN 4, CS=MCS-2 -- Chunk with length 428 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4059,6 +4160,7 @@ - Sending new block at BSN 5, CS=MCS-2 -- Chunk with length 400 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4069,6 +4171,7 @@ - Sending new block at BSN 6, CS=MCS-2 -- Chunk with length 372 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4079,6 +4182,7 @@ - Sending new block at BSN 7, CS=MCS-2 -- Chunk with length 344 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4089,6 +4193,7 @@ - Sending new block at BSN 8, CS=MCS-2 -- Chunk with length 316 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4099,6 +4204,7 @@ - Sending new block at BSN 9, CS=MCS-2 -- Chunk with length 288 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4109,6 +4215,7 @@ - Sending new block at BSN 10, CS=MCS-2 -- Chunk with length 260 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4119,6 +4226,7 @@ - Sending new block at BSN 11, CS=MCS-2 -- Chunk with length 232 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4129,6 +4237,7 @@ - Sending new block at BSN 12, CS=MCS-2 -- Chunk with length 204 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4139,6 +4248,7 @@ - Sending new block at BSN 13, CS=MCS-2 -- Chunk with length 176 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4149,6 +4259,7 @@ - Sending new block at BSN 14, CS=MCS-2 -- Chunk with length 148 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4159,6 +4270,7 @@ - Sending new block at BSN 15, CS=MCS-2 -- Chunk with length 120 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4169,6 +4281,7 @@ - Sending new block at BSN 16, CS=MCS-2 -- Chunk with length 92 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4179,6 +4292,7 @@ - Sending new block at BSN 17, CS=MCS-2 -- Chunk with length 64 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4189,6 +4303,7 @@ - Sending new block at BSN 18, CS=MCS-2 -- Chunk with length 36 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4204,6 +4319,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=18 data block (BSN 19, MCS-2): 10 25 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4264,6 +4380,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=25 data block (BSN 0, MCS-3): 14 33 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4277,6 +4394,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4287,6 +4405,7 @@ - Sending new block at BSN 2, CS=MCS-3 -- Chunk with length 475 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4297,6 +4416,7 @@ - Sending new block at BSN 3, CS=MCS-3 -- Chunk with length 438 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4307,6 +4427,7 @@ - Sending new block at BSN 4, CS=MCS-3 -- Chunk with length 401 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4317,6 +4438,7 @@ - Sending new block at BSN 5, CS=MCS-3 -- Chunk with length 364 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4327,6 +4449,7 @@ - Sending new block at BSN 6, CS=MCS-3 -- Chunk with length 327 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4337,6 +4460,7 @@ - Sending new block at BSN 7, CS=MCS-3 -- Chunk with length 290 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4347,6 +4471,7 @@ - Sending new block at BSN 8, CS=MCS-3 -- Chunk with length 253 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4357,6 +4482,7 @@ - Sending new block at BSN 9, CS=MCS-3 -- Chunk with length 216 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4367,6 +4493,7 @@ - Sending new block at BSN 10, CS=MCS-3 -- Chunk with length 179 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4377,6 +4504,7 @@ - Sending new block at BSN 11, CS=MCS-3 -- Chunk with length 142 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4387,6 +4515,7 @@ - Sending new block at BSN 12, CS=MCS-3 -- Chunk with length 105 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4397,6 +4526,7 @@ - Sending new block at BSN 13, CS=MCS-3 -- Chunk with length 68 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4410,6 +4540,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-3): 3f 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4425,6 +4556,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=34 data block (BSN 15, MCS-3): 02 45 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4485,6 +4617,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=32 data block (BSN 0, MCS-4): 14 41 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4498,6 +4631,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4508,6 +4642,7 @@ - Sending new block at BSN 2, CS=MCS-4 -- Chunk with length 468 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4518,6 +4653,7 @@ - Sending new block at BSN 3, CS=MCS-4 -- Chunk with length 424 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4528,6 +4664,7 @@ - Sending new block at BSN 4, CS=MCS-4 -- Chunk with length 380 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4538,6 +4675,7 @@ - Sending new block at BSN 5, CS=MCS-4 -- Chunk with length 336 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4548,6 +4686,7 @@ - Sending new block at BSN 6, CS=MCS-4 -- Chunk with length 292 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4558,6 +4697,7 @@ - Sending new block at BSN 7, CS=MCS-4 -- Chunk with length 248 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4568,6 +4708,7 @@ - Sending new block at BSN 8, CS=MCS-4 -- Chunk with length 204 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4578,6 +4719,7 @@ - Sending new block at BSN 9, CS=MCS-4 -- Chunk with length 160 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4588,6 +4730,7 @@ - Sending new block at BSN 10, CS=MCS-4 -- Chunk with length 116 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4598,6 +4741,7 @@ - Sending new block at BSN 11, CS=MCS-4 -- Chunk with length 72 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4613,6 +4757,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 12, MCS-4): 38 1d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4673,6 +4818,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-5): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4686,6 +4832,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4696,6 +4843,7 @@ - Sending new block at BSN 2, CS=MCS-5 -- Chunk with length 456 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4706,6 +4854,7 @@ - Sending new block at BSN 3, CS=MCS-5 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4716,6 +4865,7 @@ - Sending new block at BSN 4, CS=MCS-5 -- Chunk with length 344 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4726,6 +4876,7 @@ - Sending new block at BSN 5, CS=MCS-5 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4736,6 +4887,7 @@ - Sending new block at BSN 6, CS=MCS-5 -- Chunk with length 232 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4746,6 +4898,7 @@ - Sending new block at BSN 7, CS=MCS-5 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4756,6 +4909,7 @@ - Sending new block at BSN 8, CS=MCS-5 -- Chunk with length 120 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4766,6 +4920,7 @@ - Sending new block at BSN 9, CS=MCS-5 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4781,6 +4936,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-5): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4841,6 +4997,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-6): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4854,6 +5011,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4864,6 +5022,7 @@ - Sending new block at BSN 2, CS=MCS-6 -- Chunk with length 438 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4874,6 +5033,7 @@ - Sending new block at BSN 3, CS=MCS-6 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4884,6 +5044,7 @@ - Sending new block at BSN 4, CS=MCS-6 -- Chunk with length 290 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4894,6 +5055,7 @@ - Sending new block at BSN 5, CS=MCS-6 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4904,6 +5066,7 @@ - Sending new block at BSN 6, CS=MCS-6 -- Chunk with length 142 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4917,6 +5080,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-6): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4932,6 +5096,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-6): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4993,6 +5158,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-7): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5002,12 +5168,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(7) last_mcs(5) demanded_mcs(7)cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-7 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5022,6 +5189,7 @@ - Sending new block at BSN 3, CS=MCS-7 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5036,6 +5204,7 @@ - Sending new block at BSN 5, CS=MCS-7 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5050,6 +5219,7 @@ - Sending new block at BSN 7, CS=MCS-7 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5064,6 +5234,7 @@ - Sending new block at BSN 9, CS=MCS-7 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 9) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5081,6 +5252,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-7): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5142,6 +5314,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=56 data block (BSN 0, MCS-8): 14 71 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5152,12 +5325,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(8) demanded_mcs(8) cs_trans(8) +- initial_cs_dl(8) last_mcs(8) demanded_mcs(8)cs_trans(8) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-8 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5172,6 +5346,7 @@ - Sending new block at BSN 3, CS=MCS-8 -- Chunk with length 376 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5186,6 +5361,7 @@ - Sending new block at BSN 5, CS=MCS-8 -- Chunk with length 240 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5200,6 +5376,7 @@ - Sending new block at BSN 7, CS=MCS-8 -- Chunk with length 104 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5217,6 +5394,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=30 data block (BSN 8, MCS-8): 48 3d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5279,6 +5457,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-9): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5288,12 +5467,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(9) last_mcs(6) demanded_mcs(9)cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-9 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5308,6 +5488,7 @@ - Sending new block at BSN 3, CS=MCS-9 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5322,6 +5503,7 @@ - Sending new block at BSN 5, CS=MCS-9 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5339,6 +5521,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-9): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5356,6 +5539,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-9): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5402,11 +5586,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(6)cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5450,11 +5636,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 96 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(1) demanded_mcs(1) cs_trans(1) +- initial_cs_dl(1) last_mcs(1) demanded_mcs(1)cs_trans(1) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 98 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5498,11 +5686,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-2): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 92 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(2) demanded_mcs(2) cs_trans(2) +- initial_cs_dl(2) last_mcs(2) demanded_mcs(2)cs_trans(2) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 94 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5546,6 +5736,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5557,6 +5748,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-5): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5564,10 +5756,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-5): 0f 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7)cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7)cs_trans(7) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-7): 07 00 00 02 c0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 @@ -5612,6 +5805,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5623,6 +5817,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-6): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5630,10 +5825,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-6): 0f 40 00 00 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9)cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9)cs_trans(9) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-9): 07 00 00 02 28 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 @@ -5686,6 +5882,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-7): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5694,13 +5891,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-7): 0f 00 00 02 a0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5)cs_trans(5) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5)cs_trans(5) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-5): 07 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5752,6 +5951,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-9): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5760,13 +5960,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-9): 0f 00 00 02 00 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6)cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6)cs_trans(6) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-6): 07 40 00 02 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5780,3 +5982,233 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-5 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(2)cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 d2 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(2) demanded_mcs(2)cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 f2 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-4 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (44) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-4): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-4): 07 00 00 80 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(4) demanded_mcs(1)cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 d6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(1) demanded_mcs(1)cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 f6 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(6)cs_trans(6) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 2 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..c38417d 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,9 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_egprs_spb_dl === +Testing retx for MCS 6 to reseg_mcs 3 +Testing retx for MCS 5 to reseg_mcs 2 +Testing retx for MCS 4 to reseg_mcs 1 +Testing retx for MCS 6 to reseg_mcs 3 +=== end test_tbf_egprs_spb_dl === -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 10 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Wed Aug 10 09:02:31 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Wed, 10 Aug 2016 09:02:31 +0000 Subject: osmo-bts[master]: sysmo: fix dyn TS: Revert "Activate PTCCH UL" [in sysmobts] In-Reply-To: References: Message-ID: Patch Set 1: PTCCH are necessary for OS#1545. What's the actual reason for incompatibility between dynamic TS and PTCCH? Is there anything in the spec about it? -- To view, visit https://gerrit.osmocom.org/671 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia59d95c75a8a5d3bd596f55cd1dc0906a6a95f7f Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 10 09:05:27 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Wed, 10 Aug 2016 09:05:27 +0000 Subject: osmo-bts[master]: Change interface in osmo-bts for 11 bit RACH In-Reply-To: References: Message-ID: Patch Set 4: The status is "merge conflict" - gerrit is unable to automatically rebase it for some reason so please resubmit it after manually rebasing on top of latest master. -- To view, visit https://gerrit.osmocom.org/433 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I4f4c501b2d86d77c78de32a84b1804172ffb6f4d Gerrit-PatchSet: 4 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: bhargava_abhyankar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 10 09:25:30 2016 From: gerrit-no-reply at lists.osmocom.org (pravin) Date: Wed, 10 Aug 2016 09:25:30 +0000 Subject: [PATCH] osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Hello Max, Neels Hofmeyr, Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/416 to look at the new patch set (#10). Add decoding of compressed bitmap in EPDAN Implemented tree based algorithm to decode compressed bitmap in EPDAN as described in section 9.1.10 of 3GPP 44.060. This algorithm intends to improve the performance over existing method. New Regression test is added under bitcomp directory. Test case is added to validate decompressed result of the bitmap Present in EPDAN. Test is done for multiple bitmaps of varying length. Invalid inputs are also part of the test vector. Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce --- M src/Makefile.am M src/decoding.cpp A src/egprs_rlc_compression.cpp A src/egprs_rlc_compression.h M src/pcu_main.cpp M tests/Makefile.am A tests/bitcomp/BitcompTest A tests/bitcomp/BitcompTest.cpp A tests/bitcomp/BitcompTest.ok M tests/testsuite.at 10 files changed, 580 insertions(+), 20 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/16/416/10 diff --git a/src/Makefile.am b/src/Makefile.am index 9bdec2f..9b047e7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -62,7 +62,8 @@ rlc.cpp \ osmobts_sock.cpp \ gprs_codel.c \ - gprs_coding_scheme.cpp + gprs_coding_scheme.cpp \ + egprs_rlc_compression.cpp bin_PROGRAMS = \ osmo-pcu @@ -94,7 +95,8 @@ pcu_utils.h \ cxx_linuxlist.h \ gprs_codel.h \ - gprs_coding_scheme.h + gprs_coding_scheme.h \ + egprs_rlc_compression.h osmo_pcu_SOURCES = pcu_main.cpp diff --git a/src/decoding.cpp b/src/decoding.cpp index 7c00ff7..05603ef 100644 --- a/src/decoding.cpp +++ b/src/decoding.cpp @@ -20,6 +20,8 @@ #include #include #include +#include + extern "C" { #include @@ -652,10 +654,10 @@ int num_blocks = 0; struct bitvec urbb; int i; + int rc; bool have_bitmap; int implicitly_acked_blocks; int ssn = desc->STARTING_SEQUENCE_NUMBER; - int rc; if (desc->FINAL_ACK_INDICATION) return handle_final_ack(bits, bsn_begin, bsn_end, window); @@ -695,24 +697,20 @@ if (crbb_len > 0) { int old_len = bits->cur_bit; - struct bitvec crbb; - crbb.data = (uint8_t *)desc->CRBB; - crbb.data_len = sizeof(desc->CRBB); - crbb.cur_bit = desc->CRBB_LENGTH; - - rc = osmo_t4_decode(&crbb, desc->CRBB_STARTING_COLOR_CODE, - bits); - + LOGP(DRLCMACDL, LOGL_DEBUG, "Compress bitmap exist," + "CRBB LEN =%d and Starting color code =%d", + desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE); + rc = decompress_crbb(desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE, + desc->CRBB, bits); if (rc < 0) { LOGP(DRLCMACUL, LOGL_NOTICE, - "Failed to decode CRBB: " - "length %d, data '%s'\n", - desc->CRBB_LENGTH, - osmo_hexdump(crbb.data, crbb.data_len)); + "Failed to decode CRBB: length %d, data '%s'\n", + desc->CRBB_LENGTH, osmo_hexdump( + desc->CRBB, (desc->CRBB_LENGTH + 7)/8)); /* We don't know the SSN offset for the URBB, - * return what we have so far and assume the - * bitmap has stopped here */ + * return what we have so far and assume the + * bitmap has stopped here */ goto aborted; } diff --git a/src/egprs_rlc_compression.cpp b/src/egprs_rlc_compression.cpp new file mode 100644 index 0000000..91021ae --- /dev/null +++ b/src/egprs_rlc_compression.cpp @@ -0,0 +1,308 @@ +/* egprs_rlc_compression.h +* Routines for EGPRS RLC bitmap compression handling +*/ +#include +#include +#include + +extern "C" { +#include +#include +#include +} + +egprs_compress *egprs_compress::s_instance = 0; +Node *egprs_compress::ones_list = NULL; +Node *egprs_compress::zeros_list = NULL; + +Node *egprs_compress::create_tree_node() +{ + Node *new_node; + + new_node = talloc_zero(tall_tree_ctx, Node); + new_node->left = NULL; + new_node->right = NULL; + new_node->run_length = -1; + return new_node; +} + +void egprs_compress::build_codeword(Node *root, const char *cdwd[]) +{ + Node *iter; + int len; + int i; + int idx; + + root->left = NULL; + root->right = NULL; + root->run_length = -1; + + for (idx = 0; idx < MAX_CDWDTBL_LEN; idx++) { + len = strlen((const char *)cdwd[idx]); + iter = root; + for (i = 0; i < len; i++) { + if (cdwd[idx][i] == '0') { + if (iter->left == NULL) + iter->left = create_tree_node(); + iter = iter->left; + } else if (cdwd[idx][i] == '1') { + if (iter->right == NULL) + iter->right = create_tree_node(); + iter = iter->right; + } + } + if (iter != NULL) { + if (idx < 64) + (iter->run_length) = idx; + else + (iter->run_length) = (idx - 63) * 64; + } + } +} + +const char *one_run_len_code_list[MAX_CDWDTBL_LEN] = { + "00110101", + "000111", + "0111", + "1000", + "1011", + "1100", + "1110", + "1111", + "10011", + "10100", + "00111", + "01000", + "001000", + "000011", + "110100", + "110101", + "101010", + "101011", + "0100111", + "0001100", + "0001000", + "0010111", + "0000011", + "0000100", + "0101000", + "0101011", + "0010011", + "0100100", + "0011000", + "00000010", + "00000011", + "00011010", + "00011011", + "00010010", + "00010011", + "00010100", + "00010101", + "00010110", + "00010111", + "00101000", + "00101001", + "00101010", + "00101011", + "00101100", + "00101101", + "00000100", + "00000101", + "00001010", + "00001011", + "01010010", + "01010011", + "01010100", + "01010101", + "00100100", + "00100101", + "01011000", + "01011001", + "01011010", + "01011011", + "01001010", + "01001011", + "00110010", + "00110011", + "00110100", + "11011", + "10010", + "010111", + "0110111", + "00110110", + "00110111", + "01100100", + "01100101", + "01101000", + "01100111", + "011001100", + "011001101", + "011010010", + "011010011", + "011010100" +}; + +const char *zero_run_len_code_list[MAX_CDWDTBL_LEN] = { + "0000110111", + "10", + "11", + "010", + "011", + "0011", + "0010", + "00011", + "000101", + "000100", + "0000100", + "0000101", + "0000111", + "00000100", + "00000111", + "000011000", + "0000010111", + "0000011000", + "0000001000", + "00001100111", + "00001101000", + "00001101100", + "00000110111", + "00000101000", + "00000010111", + "00000011000", + "000011001010", + "000011001011", + "000011001100", + "000011001101", + "000001101000", + "000001101001", + "000001101010", + "000001101011", + "000011010010", + "000011010011", + "000011010100", + "000011010101", + "000011010110", + "000011010111", + "000001101100", + "000001101101", + "000011011010", + "000011011011", + "000001010100", + "000001010101", + "000001010110", + "000001010111", + "000001100100", + "000001100101", + "000001010010", + "000001010011", + "000000100100", + "000000110111", + "000000111000", + "000000100111", + "000000101000", + "000001011000", + "000001011001", + "000000101011", + "000000101100", + "000001011010", + "000001100110", + "000001100111", + "0000001111", + "000011001000", + "000011001001", + "000001011011", + "000000110011", + "000000110100", + "000000110101", + "0000001101100", + "0000001101101", + "0000001001010", + "0000001001011", + "0000001001100", + "0000001001101", + "0000001110010", + "0000001110011" +}; + +/* search_runlen function will return the runlength for the codeword */ +static int search_runlen( + Node *root, /* root of Ones or Zeros tree */ + const uint8_t *bmbuf, /* Received compressed bitmap buf */ + uint8_t bit_pos, /* the start bit pos to read codeword */ + uint8_t *len_codewd, /* length of code word */ + uint16_t *rlen) /* run length value */ +{ + Node *iter; + uint8_t dir; + + iter = root; + *len_codewd = 0; + + while (iter->run_length == -1) { + if ((iter->left == NULL) && (iter->right == NULL)) + return -1; + /* get the bit value at the bitpos and put it in right most of dir */ + dir = ((bmbuf[BITS_TO_BYTES(bit_pos)-1] + >>(7-(MOD8(bit_pos)))) & 0x01); + (bit_pos)++; + (*len_codewd)++; + if (((dir&0x01) == 0) && (iter->left != NULL)) + iter = iter->left; + else if (((dir&0x01) == 1) && (iter->right != NULL)) + iter = iter->right; + else + return -1; + } + (*rlen) = (iter->run_length); + return 1; +} + +/*Function to decompress crbb*/ +int decompress_crbb( + int8_t compress_bmap_len, /* compressed bitmap length */ + uint8_t clr_code_bit, /* run length of Ones or Zeros */ + const uint8_t *orig_crbb_buf, /* received block crbb bitmap */ + bitvec * dest) /*uncompressed bitvector */ +{ + + uint8_t bit_pos = 0; + uint8_t data = 0x0; + node *list = NULL; + uint8_t nbits = 0; /* number of bits of codeword */ + uint16_t run_length = 0; + uint16_t cbmaplen = 0; /* compressed bitmap part after decompression */ + unsigned wp = dest->cur_bit; + int rc = 0; + egprs_compress *compress = egprs_compress::instance(); + + while (compress_bmap_len > 0) { + if (clr_code_bit == 1) { + data = 0xff; + list = compress->ones_list; + } else { + data = 0x00; + list = compress->zeros_list; + } + rc = search_runlen(list, orig_crbb_buf, + bit_pos, &nbits, &run_length); + if (rc == -1) + return -1; + /*If run length > 64, need makeup and terminating code*/ + if (run_length < 64) + clr_code_bit ? clr_code_bit = 0 : clr_code_bit = 1; + cbmaplen = cbmaplen + run_length; + /* put run length of Ones in uncompressed bitmap */ + while (run_length != 0) { + if (run_length > 8) { + bitvec_write_field(dest, wp, data, 8); + run_length = run_length - 8; + } else { + bitvec_write_field(dest, wp, data, run_length); + run_length = 0; + } + } + bit_pos = bit_pos + nbits; + compress_bmap_len = compress_bmap_len - nbits; + } + return 0; +} diff --git a/src/egprs_rlc_compression.h b/src/egprs_rlc_compression.h new file mode 100644 index 0000000..e37fe66 --- /dev/null +++ b/src/egprs_rlc_compression.h @@ -0,0 +1,73 @@ +/* egprs_rlc_compression.h + * Routines for EGPRS RLC bitmap compression handling + */ +#include +#include + +extern "C" { +#include +} + +#include +#include +#include + +#define MAX_CDWDTBL_LEN 79 /* total number of codewords */ +#define BITS_TO_BYTES(X) ((X ? (X/8):0)+1) +#define MOD8(X) (((X)+8) & (0x07)) + +typedef struct node { + struct node *left; + struct node *right; + int run_length; +} Node; + +extern const char *one_run_len_code_list[MAX_CDWDTBL_LEN]; +extern const char *zero_run_len_code_list[MAX_CDWDTBL_LEN]; + +int decompress_crbb(int8_t compress_bmap_len, uint8_t clr_code_bit, + const uint8_t *orig_buf, bitvec *dest); + +/* Creating singleton class + */ +class egprs_compress +{ + static egprs_compress *s_instance; + void *tall_tree_ctx; + + egprs_compress() + { + } + Node *create_tree_node(); + void build_codeword(Node *root, const char *cdwd[]); + void free_codeword(Node *root); + ~egprs_compress() + { + s_instance = NULL; + } +public: + static Node *ones_list; + static Node *zeros_list; + + int decode_tree_init(void *tall_pcu_ctx) + { + tall_tree_ctx = talloc_named_const(tall_pcu_ctx, 0, + "decode-tree context"); + if (!tall_tree_ctx) + return -ENOMEM; + ones_list = talloc(tall_tree_ctx, Node); + zeros_list = talloc(tall_tree_ctx, Node); + instance()->build_codeword( + ones_list, one_run_len_code_list); + instance()->build_codeword( + zeros_list, zero_run_len_code_list); + return 0; + } + static egprs_compress *instance() + { + if (!s_instance) + s_instance = new egprs_compress; + + return s_instance; + } +}; diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2d86cda..4f2853a 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -28,6 +28,7 @@ #include #include #include +#include extern "C" { #include "pcu_vty.h" #include @@ -168,7 +169,6 @@ if (!tall_pcu_ctx) return -ENOMEM; bv_tall_ctx = tall_pcu_ctx; - bts = bts_main_data(); bts->fc_interval = 1; bts->initial_cs_dl = bts->initial_cs_ul = 1; @@ -253,6 +253,11 @@ if (!bts->alloc_algorithm) bts->alloc_algorithm = alloc_algorithm_dynamic; + if (egprs_compress::instance()->decode_tree_init(tall_pcu_ctx) < 0 ){ + fprintf(stderr, "Error initializing tree\n"); + exit(1); + } + rc = pcu_l1if_open(); if (rc < 0) @@ -292,6 +297,5 @@ talloc_report_full(tall_pcu_ctx, stderr); talloc_free(tall_pcu_ctx); - return 0; } diff --git a/tests/Makefile.am b/tests/Makefile.am index 2a3415e..1487431 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,7 +1,7 @@ AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGB_CFLAGS) $(LIBOSMOGSM_CFLAGS) -I$(top_srcdir)/src/ AM_LDFLAGS = -lrt -check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest llc/LlcTest codel/codel_test edge/EdgeTest +check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest llc/LlcTest codel/codel_test edge/EdgeTest bitcomp/BitcompTest noinst_PROGRAMS = emu/pcu_emu rlcmac_RLCMACTest_SOURCES = rlcmac/RLCMACTest.cpp @@ -20,6 +20,14 @@ tbf_TbfTest_SOURCES = tbf/TbfTest.cpp tbf_TbfTest_LDADD = \ + $(top_builddir)/src/libgprs.la \ + $(LIBOSMOGB_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(COMMON_LA) + +bitcomp_BitcompTest_SOURCES = bitcomp/BitcompTest.cpp +bitcomp_BitcompTest_LDADD = \ $(top_builddir)/src/libgprs.la \ $(LIBOSMOGB_LIBS) \ $(LIBOSMOGSM_LIBS) \ @@ -108,6 +116,7 @@ rlcmac/RLCMACTest.ok rlcmac/RLCMACTest.err \ alloc/AllocTest.ok alloc/AllocTest.err \ tbf/TbfTest.ok tbf/TbfTest.err \ + bitcomp/Bitcomptest.ok bitcomp/Bitcomptest.err \ types/TypesTest.ok types/TypesTest.err \ ms/MsTest.ok ms/MsTest.err \ llc/LlcTest.ok llc/LlcTest.err \ diff --git a/tests/bitcomp/BitcompTest b/tests/bitcomp/BitcompTest new file mode 100755 index 0000000..8ac3936 --- /dev/null +++ b/tests/bitcomp/BitcompTest Binary files differ diff --git a/tests/bitcomp/BitcompTest.cpp b/tests/bitcomp/BitcompTest.cpp new file mode 100644 index 0000000..ccb4f6e --- /dev/null +++ b/tests/bitcomp/BitcompTest.cpp @@ -0,0 +1,156 @@ +#include "egprs_rlc_compression.h" +#include "decoding.h" + +extern "C" { +#include +} + +#define NEW 1 +#define MASK(n) (0xFF << (8-n)) +#define MAX_CRBB_LEN 23 +#define MAX_URBB_LEN 40 +void *tall_pcu_ctx; + +struct test_data { + int8_t crbb_len; + uint8_t cc; + uint8_t crbb_data[MAX_CRBB_LEN]; /* compressed data */ + uint8_t ucmp_data[MAX_URBB_LEN]; /* uncompressed data */ + int ucmp_len; + int verify; +} test[] = { + {67, 1, + {0x02, 0x0c, 0xa0, 0x30, 0xcb, 0x1a, 0x0c, 0xe3, 0x6c}, + {0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x01, 0xff, 0xff, + 0xff, 0xf8, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, + 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xdb + }, + 194, 1 + }, + { 40, 1, + {0x53, 0x06, 0xc5, 0x40, 0x6d}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x03 + }, + 182, 1 + }, + { 8, 1, + {0x02}, + {0xff, 0xff, 0xff, 0xf8 + }, + 29, 1 + }, + { 103, 1, + {0x02, 0x0c, 0xe0, 0x41, 0xa0, 0x0c, 0x36, 0x0d, 0x03, + 0x71, 0xb0, 0x6e, 0x24 + }, + {0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xf8, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, + 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff + }, + 288, 1 + }, + /* Test vector from libosmocore test */ + { 35, 0, + {0xde, 0x88, 0x75, 0x65, 0x80}, + {0x37, 0x47, 0x81, 0xf0}, + 28, 1 + }, + { 18, 1, + {0xdd, 0x41, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00 + }, + 90, 1 + }, + /*Invalid inputs*/ + { 18, 1, + {0x1E, 0x70, 0xc0}, + {0x0}, + 0, 0 + }, + { 14, 1, + {0x00, 0x1E, 0x7c}, + {0x0}, + 0, 0 + }, + { 24, 0, + {0x00, 0x00, 0x00}, + {0x0}, + 0, 0 + } + }; + + +/* To verify the result with expected result */ +int check_result(bitvec bits, uint8_t *exp_data, int exp_len) +{ + if (bits.cur_bit != exp_len) + return 0; + size_t n = (exp_len / 8); + int rem = (exp_len % 8); + + if (memcmp(exp_data, bits.data, n) == 0) { + if (rem == 0) + return 1; + if ((bits.data[n] & MASK(rem)) == ((*(exp_data + n)) & MASK(rem))) + return 1; + else + return 0; + } else { + return 0; + } +} + +/* To test decoding of compressed bitmap by Tree based method + * and to verify the result with expected result + * for invalid input verfication is suppressed + */ +static void test_EPDAN_decode_tree(void) +{ + bitvec dest; + int init_flag = 1; + int itr; + uint8_t bits_data[RLC_EGPRS_MAX_WS/8]; + + printf("=== start %s ===\n", __func__); + + for (itr = 0 ; itr < (sizeof(test) / sizeof(test_data)) ; itr++) { + dest.data = bits_data; + dest.data_len = sizeof(bits_data); + dest.cur_bit = 0; + memset(dest.data, 0, sizeof(bits_data)); + decompress_crbb(test[itr].crbb_len, test[itr].cc, + test[itr].crbb_data, &dest + ); + + if (init_flag) + init_flag = 0; + if (test[itr].verify) { + if (check_result(dest, test[itr].ucmp_data, + test[itr].ucmp_len) == 0) { + LOGP(DRLCMACDL, LOGL_DEBUG, "Tree based", + "decoding :Error\n"); + OSMO_ASSERT(0); + } + } + } + + printf("=== end %s ===\n", __func__); +} + +int main(int argc, char **argv) +{ + tall_pcu_ctx = talloc_named_const(NULL, 1, "moiji-mobile TbfTest context"); + if (!tall_pcu_ctx) + abort(); + /*initialization_of_tree*/ + egprs_compress::instance()->decode_tree_init(tall_pcu_ctx); + test_EPDAN_decode_tree(); + if (getenv("TALLOC_REPORT_FULL")) + talloc_report_full(tall_pcu_ctx, stderr); + talloc_free(tall_pcu_ctx); + return EXIT_SUCCESS; +} diff --git a/tests/bitcomp/BitcompTest.ok b/tests/bitcomp/BitcompTest.ok new file mode 100644 index 0000000..f7720fc --- /dev/null +++ b/tests/bitcomp/BitcompTest.ok @@ -0,0 +1,2 @@ +=== start test_EPDAN_decode_tree === +=== end test_EPDAN_decode_tree === diff --git a/tests/testsuite.at b/tests/testsuite.at index 1049b31..3ab39cc 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -23,6 +23,14 @@ AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/tbf/TbfTest], [0], [expout], [experr]) AT_CLEANUP + +AT_SETUP([bitcomp]) +AT_KEYWORDS([bitcomp]) +cat $abs_srcdir/bitcomp/BitcompTest.ok > expout +cat $abs_srcdir/bitcomp/BitcompTest.err > experr +AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/bitcomp/BitcompTest], [0], [expout], [experr]) +AT_CLEANUP + AT_SETUP([edge]) AT_KEYWORDS([edge]) cat $abs_srcdir/edge/EdgeTest.ok > expout -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 10 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: pravin From gerrit-no-reply at lists.osmocom.org Wed Aug 10 10:29:10 2016 From: gerrit-no-reply at lists.osmocom.org (pravin) Date: Wed, 10 Aug 2016 10:29:10 +0000 Subject: [PATCH] osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Hello Max, Neels Hofmeyr, Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/416 to look at the new patch set (#11). Add decoding of compressed bitmap in EPDAN Implemented tree based algorithm to decode compressed bitmap in EPDAN as described in section 9.1.10 of 3GPP 44.060. This algorithm intends to improve the performance over existing method. New Regression test is added under bitcomp directory. Test case is added to validate decompressed result of the bitmap Present in EPDAN. Test is done for multiple bitmaps of varying length. Invalid inputs are also part of the test vector. Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce --- M src/Makefile.am M src/decoding.cpp A src/egprs_rlc_compression.cpp A src/egprs_rlc_compression.h M src/pcu_main.cpp M tests/Makefile.am A tests/bitcomp/BitcompTest A tests/bitcomp/BitcompTest.cpp A tests/bitcomp/BitcompTest.ok M tests/testsuite.at 10 files changed, 579 insertions(+), 20 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/16/416/11 diff --git a/src/Makefile.am b/src/Makefile.am index 9bdec2f..9b047e7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -62,7 +62,8 @@ rlc.cpp \ osmobts_sock.cpp \ gprs_codel.c \ - gprs_coding_scheme.cpp + gprs_coding_scheme.cpp \ + egprs_rlc_compression.cpp bin_PROGRAMS = \ osmo-pcu @@ -94,7 +95,8 @@ pcu_utils.h \ cxx_linuxlist.h \ gprs_codel.h \ - gprs_coding_scheme.h + gprs_coding_scheme.h \ + egprs_rlc_compression.h osmo_pcu_SOURCES = pcu_main.cpp diff --git a/src/decoding.cpp b/src/decoding.cpp index 7c00ff7..2b00a07 100644 --- a/src/decoding.cpp +++ b/src/decoding.cpp @@ -20,6 +20,7 @@ #include #include #include +#include extern "C" { #include @@ -652,10 +653,10 @@ int num_blocks = 0; struct bitvec urbb; int i; + int rc; bool have_bitmap; int implicitly_acked_blocks; int ssn = desc->STARTING_SEQUENCE_NUMBER; - int rc; if (desc->FINAL_ACK_INDICATION) return handle_final_ack(bits, bsn_begin, bsn_end, window); @@ -695,24 +696,20 @@ if (crbb_len > 0) { int old_len = bits->cur_bit; - struct bitvec crbb; - crbb.data = (uint8_t *)desc->CRBB; - crbb.data_len = sizeof(desc->CRBB); - crbb.cur_bit = desc->CRBB_LENGTH; - - rc = osmo_t4_decode(&crbb, desc->CRBB_STARTING_COLOR_CODE, - bits); - + LOGP(DRLCMACDL, LOGL_DEBUG, "Compress bitmap exist," + "CRBB LEN =%d and Starting color code =%d", + desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE); + rc = decompress_crbb(desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE, + desc->CRBB, bits); if (rc < 0) { LOGP(DRLCMACUL, LOGL_NOTICE, - "Failed to decode CRBB: " - "length %d, data '%s'\n", - desc->CRBB_LENGTH, - osmo_hexdump(crbb.data, crbb.data_len)); + "Failed to decode CRBB: length %d, data '%s'\n", + desc->CRBB_LENGTH, osmo_hexdump( + desc->CRBB, (desc->CRBB_LENGTH + 7)/8)); /* We don't know the SSN offset for the URBB, - * return what we have so far and assume the - * bitmap has stopped here */ + * return what we have so far and assume the + * bitmap has stopped here */ goto aborted; } diff --git a/src/egprs_rlc_compression.cpp b/src/egprs_rlc_compression.cpp new file mode 100644 index 0000000..91021ae --- /dev/null +++ b/src/egprs_rlc_compression.cpp @@ -0,0 +1,308 @@ +/* egprs_rlc_compression.h +* Routines for EGPRS RLC bitmap compression handling +*/ +#include +#include +#include + +extern "C" { +#include +#include +#include +} + +egprs_compress *egprs_compress::s_instance = 0; +Node *egprs_compress::ones_list = NULL; +Node *egprs_compress::zeros_list = NULL; + +Node *egprs_compress::create_tree_node() +{ + Node *new_node; + + new_node = talloc_zero(tall_tree_ctx, Node); + new_node->left = NULL; + new_node->right = NULL; + new_node->run_length = -1; + return new_node; +} + +void egprs_compress::build_codeword(Node *root, const char *cdwd[]) +{ + Node *iter; + int len; + int i; + int idx; + + root->left = NULL; + root->right = NULL; + root->run_length = -1; + + for (idx = 0; idx < MAX_CDWDTBL_LEN; idx++) { + len = strlen((const char *)cdwd[idx]); + iter = root; + for (i = 0; i < len; i++) { + if (cdwd[idx][i] == '0') { + if (iter->left == NULL) + iter->left = create_tree_node(); + iter = iter->left; + } else if (cdwd[idx][i] == '1') { + if (iter->right == NULL) + iter->right = create_tree_node(); + iter = iter->right; + } + } + if (iter != NULL) { + if (idx < 64) + (iter->run_length) = idx; + else + (iter->run_length) = (idx - 63) * 64; + } + } +} + +const char *one_run_len_code_list[MAX_CDWDTBL_LEN] = { + "00110101", + "000111", + "0111", + "1000", + "1011", + "1100", + "1110", + "1111", + "10011", + "10100", + "00111", + "01000", + "001000", + "000011", + "110100", + "110101", + "101010", + "101011", + "0100111", + "0001100", + "0001000", + "0010111", + "0000011", + "0000100", + "0101000", + "0101011", + "0010011", + "0100100", + "0011000", + "00000010", + "00000011", + "00011010", + "00011011", + "00010010", + "00010011", + "00010100", + "00010101", + "00010110", + "00010111", + "00101000", + "00101001", + "00101010", + "00101011", + "00101100", + "00101101", + "00000100", + "00000101", + "00001010", + "00001011", + "01010010", + "01010011", + "01010100", + "01010101", + "00100100", + "00100101", + "01011000", + "01011001", + "01011010", + "01011011", + "01001010", + "01001011", + "00110010", + "00110011", + "00110100", + "11011", + "10010", + "010111", + "0110111", + "00110110", + "00110111", + "01100100", + "01100101", + "01101000", + "01100111", + "011001100", + "011001101", + "011010010", + "011010011", + "011010100" +}; + +const char *zero_run_len_code_list[MAX_CDWDTBL_LEN] = { + "0000110111", + "10", + "11", + "010", + "011", + "0011", + "0010", + "00011", + "000101", + "000100", + "0000100", + "0000101", + "0000111", + "00000100", + "00000111", + "000011000", + "0000010111", + "0000011000", + "0000001000", + "00001100111", + "00001101000", + "00001101100", + "00000110111", + "00000101000", + "00000010111", + "00000011000", + "000011001010", + "000011001011", + "000011001100", + "000011001101", + "000001101000", + "000001101001", + "000001101010", + "000001101011", + "000011010010", + "000011010011", + "000011010100", + "000011010101", + "000011010110", + "000011010111", + "000001101100", + "000001101101", + "000011011010", + "000011011011", + "000001010100", + "000001010101", + "000001010110", + "000001010111", + "000001100100", + "000001100101", + "000001010010", + "000001010011", + "000000100100", + "000000110111", + "000000111000", + "000000100111", + "000000101000", + "000001011000", + "000001011001", + "000000101011", + "000000101100", + "000001011010", + "000001100110", + "000001100111", + "0000001111", + "000011001000", + "000011001001", + "000001011011", + "000000110011", + "000000110100", + "000000110101", + "0000001101100", + "0000001101101", + "0000001001010", + "0000001001011", + "0000001001100", + "0000001001101", + "0000001110010", + "0000001110011" +}; + +/* search_runlen function will return the runlength for the codeword */ +static int search_runlen( + Node *root, /* root of Ones or Zeros tree */ + const uint8_t *bmbuf, /* Received compressed bitmap buf */ + uint8_t bit_pos, /* the start bit pos to read codeword */ + uint8_t *len_codewd, /* length of code word */ + uint16_t *rlen) /* run length value */ +{ + Node *iter; + uint8_t dir; + + iter = root; + *len_codewd = 0; + + while (iter->run_length == -1) { + if ((iter->left == NULL) && (iter->right == NULL)) + return -1; + /* get the bit value at the bitpos and put it in right most of dir */ + dir = ((bmbuf[BITS_TO_BYTES(bit_pos)-1] + >>(7-(MOD8(bit_pos)))) & 0x01); + (bit_pos)++; + (*len_codewd)++; + if (((dir&0x01) == 0) && (iter->left != NULL)) + iter = iter->left; + else if (((dir&0x01) == 1) && (iter->right != NULL)) + iter = iter->right; + else + return -1; + } + (*rlen) = (iter->run_length); + return 1; +} + +/*Function to decompress crbb*/ +int decompress_crbb( + int8_t compress_bmap_len, /* compressed bitmap length */ + uint8_t clr_code_bit, /* run length of Ones or Zeros */ + const uint8_t *orig_crbb_buf, /* received block crbb bitmap */ + bitvec * dest) /*uncompressed bitvector */ +{ + + uint8_t bit_pos = 0; + uint8_t data = 0x0; + node *list = NULL; + uint8_t nbits = 0; /* number of bits of codeword */ + uint16_t run_length = 0; + uint16_t cbmaplen = 0; /* compressed bitmap part after decompression */ + unsigned wp = dest->cur_bit; + int rc = 0; + egprs_compress *compress = egprs_compress::instance(); + + while (compress_bmap_len > 0) { + if (clr_code_bit == 1) { + data = 0xff; + list = compress->ones_list; + } else { + data = 0x00; + list = compress->zeros_list; + } + rc = search_runlen(list, orig_crbb_buf, + bit_pos, &nbits, &run_length); + if (rc == -1) + return -1; + /*If run length > 64, need makeup and terminating code*/ + if (run_length < 64) + clr_code_bit ? clr_code_bit = 0 : clr_code_bit = 1; + cbmaplen = cbmaplen + run_length; + /* put run length of Ones in uncompressed bitmap */ + while (run_length != 0) { + if (run_length > 8) { + bitvec_write_field(dest, wp, data, 8); + run_length = run_length - 8; + } else { + bitvec_write_field(dest, wp, data, run_length); + run_length = 0; + } + } + bit_pos = bit_pos + nbits; + compress_bmap_len = compress_bmap_len - nbits; + } + return 0; +} diff --git a/src/egprs_rlc_compression.h b/src/egprs_rlc_compression.h new file mode 100644 index 0000000..e37fe66 --- /dev/null +++ b/src/egprs_rlc_compression.h @@ -0,0 +1,73 @@ +/* egprs_rlc_compression.h + * Routines for EGPRS RLC bitmap compression handling + */ +#include +#include + +extern "C" { +#include +} + +#include +#include +#include + +#define MAX_CDWDTBL_LEN 79 /* total number of codewords */ +#define BITS_TO_BYTES(X) ((X ? (X/8):0)+1) +#define MOD8(X) (((X)+8) & (0x07)) + +typedef struct node { + struct node *left; + struct node *right; + int run_length; +} Node; + +extern const char *one_run_len_code_list[MAX_CDWDTBL_LEN]; +extern const char *zero_run_len_code_list[MAX_CDWDTBL_LEN]; + +int decompress_crbb(int8_t compress_bmap_len, uint8_t clr_code_bit, + const uint8_t *orig_buf, bitvec *dest); + +/* Creating singleton class + */ +class egprs_compress +{ + static egprs_compress *s_instance; + void *tall_tree_ctx; + + egprs_compress() + { + } + Node *create_tree_node(); + void build_codeword(Node *root, const char *cdwd[]); + void free_codeword(Node *root); + ~egprs_compress() + { + s_instance = NULL; + } +public: + static Node *ones_list; + static Node *zeros_list; + + int decode_tree_init(void *tall_pcu_ctx) + { + tall_tree_ctx = talloc_named_const(tall_pcu_ctx, 0, + "decode-tree context"); + if (!tall_tree_ctx) + return -ENOMEM; + ones_list = talloc(tall_tree_ctx, Node); + zeros_list = talloc(tall_tree_ctx, Node); + instance()->build_codeword( + ones_list, one_run_len_code_list); + instance()->build_codeword( + zeros_list, zero_run_len_code_list); + return 0; + } + static egprs_compress *instance() + { + if (!s_instance) + s_instance = new egprs_compress; + + return s_instance; + } +}; diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2d86cda..4f2853a 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -28,6 +28,7 @@ #include #include #include +#include extern "C" { #include "pcu_vty.h" #include @@ -168,7 +169,6 @@ if (!tall_pcu_ctx) return -ENOMEM; bv_tall_ctx = tall_pcu_ctx; - bts = bts_main_data(); bts->fc_interval = 1; bts->initial_cs_dl = bts->initial_cs_ul = 1; @@ -253,6 +253,11 @@ if (!bts->alloc_algorithm) bts->alloc_algorithm = alloc_algorithm_dynamic; + if (egprs_compress::instance()->decode_tree_init(tall_pcu_ctx) < 0 ){ + fprintf(stderr, "Error initializing tree\n"); + exit(1); + } + rc = pcu_l1if_open(); if (rc < 0) @@ -292,6 +297,5 @@ talloc_report_full(tall_pcu_ctx, stderr); talloc_free(tall_pcu_ctx); - return 0; } diff --git a/tests/Makefile.am b/tests/Makefile.am index 2a3415e..0f4feb1 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,7 +1,7 @@ AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGB_CFLAGS) $(LIBOSMOGSM_CFLAGS) -I$(top_srcdir)/src/ AM_LDFLAGS = -lrt -check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest llc/LlcTest codel/codel_test edge/EdgeTest +check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest llc/LlcTest codel/codel_test edge/EdgeTest bitcomp/BitcompTest noinst_PROGRAMS = emu/pcu_emu rlcmac_RLCMACTest_SOURCES = rlcmac/RLCMACTest.cpp @@ -20,6 +20,14 @@ tbf_TbfTest_SOURCES = tbf/TbfTest.cpp tbf_TbfTest_LDADD = \ + $(top_builddir)/src/libgprs.la \ + $(LIBOSMOGB_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(COMMON_LA) + +bitcomp_BitcompTest_SOURCES = bitcomp/BitcompTest.cpp +bitcomp_BitcompTest_LDADD = \ $(top_builddir)/src/libgprs.la \ $(LIBOSMOGB_LIBS) \ $(LIBOSMOGSM_LIBS) \ @@ -108,6 +116,7 @@ rlcmac/RLCMACTest.ok rlcmac/RLCMACTest.err \ alloc/AllocTest.ok alloc/AllocTest.err \ tbf/TbfTest.ok tbf/TbfTest.err \ + bitcomp/BitcompTest.ok \ types/TypesTest.ok types/TypesTest.err \ ms/MsTest.ok ms/MsTest.err \ llc/LlcTest.ok llc/LlcTest.err \ diff --git a/tests/bitcomp/BitcompTest b/tests/bitcomp/BitcompTest new file mode 100755 index 0000000..e1f3666 --- /dev/null +++ b/tests/bitcomp/BitcompTest Binary files differ diff --git a/tests/bitcomp/BitcompTest.cpp b/tests/bitcomp/BitcompTest.cpp new file mode 100644 index 0000000..ccb4f6e --- /dev/null +++ b/tests/bitcomp/BitcompTest.cpp @@ -0,0 +1,156 @@ +#include "egprs_rlc_compression.h" +#include "decoding.h" + +extern "C" { +#include +} + +#define NEW 1 +#define MASK(n) (0xFF << (8-n)) +#define MAX_CRBB_LEN 23 +#define MAX_URBB_LEN 40 +void *tall_pcu_ctx; + +struct test_data { + int8_t crbb_len; + uint8_t cc; + uint8_t crbb_data[MAX_CRBB_LEN]; /* compressed data */ + uint8_t ucmp_data[MAX_URBB_LEN]; /* uncompressed data */ + int ucmp_len; + int verify; +} test[] = { + {67, 1, + {0x02, 0x0c, 0xa0, 0x30, 0xcb, 0x1a, 0x0c, 0xe3, 0x6c}, + {0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x01, 0xff, 0xff, + 0xff, 0xf8, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, + 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xdb + }, + 194, 1 + }, + { 40, 1, + {0x53, 0x06, 0xc5, 0x40, 0x6d}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x03 + }, + 182, 1 + }, + { 8, 1, + {0x02}, + {0xff, 0xff, 0xff, 0xf8 + }, + 29, 1 + }, + { 103, 1, + {0x02, 0x0c, 0xe0, 0x41, 0xa0, 0x0c, 0x36, 0x0d, 0x03, + 0x71, 0xb0, 0x6e, 0x24 + }, + {0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xf8, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, + 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff + }, + 288, 1 + }, + /* Test vector from libosmocore test */ + { 35, 0, + {0xde, 0x88, 0x75, 0x65, 0x80}, + {0x37, 0x47, 0x81, 0xf0}, + 28, 1 + }, + { 18, 1, + {0xdd, 0x41, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00 + }, + 90, 1 + }, + /*Invalid inputs*/ + { 18, 1, + {0x1E, 0x70, 0xc0}, + {0x0}, + 0, 0 + }, + { 14, 1, + {0x00, 0x1E, 0x7c}, + {0x0}, + 0, 0 + }, + { 24, 0, + {0x00, 0x00, 0x00}, + {0x0}, + 0, 0 + } + }; + + +/* To verify the result with expected result */ +int check_result(bitvec bits, uint8_t *exp_data, int exp_len) +{ + if (bits.cur_bit != exp_len) + return 0; + size_t n = (exp_len / 8); + int rem = (exp_len % 8); + + if (memcmp(exp_data, bits.data, n) == 0) { + if (rem == 0) + return 1; + if ((bits.data[n] & MASK(rem)) == ((*(exp_data + n)) & MASK(rem))) + return 1; + else + return 0; + } else { + return 0; + } +} + +/* To test decoding of compressed bitmap by Tree based method + * and to verify the result with expected result + * for invalid input verfication is suppressed + */ +static void test_EPDAN_decode_tree(void) +{ + bitvec dest; + int init_flag = 1; + int itr; + uint8_t bits_data[RLC_EGPRS_MAX_WS/8]; + + printf("=== start %s ===\n", __func__); + + for (itr = 0 ; itr < (sizeof(test) / sizeof(test_data)) ; itr++) { + dest.data = bits_data; + dest.data_len = sizeof(bits_data); + dest.cur_bit = 0; + memset(dest.data, 0, sizeof(bits_data)); + decompress_crbb(test[itr].crbb_len, test[itr].cc, + test[itr].crbb_data, &dest + ); + + if (init_flag) + init_flag = 0; + if (test[itr].verify) { + if (check_result(dest, test[itr].ucmp_data, + test[itr].ucmp_len) == 0) { + LOGP(DRLCMACDL, LOGL_DEBUG, "Tree based", + "decoding :Error\n"); + OSMO_ASSERT(0); + } + } + } + + printf("=== end %s ===\n", __func__); +} + +int main(int argc, char **argv) +{ + tall_pcu_ctx = talloc_named_const(NULL, 1, "moiji-mobile TbfTest context"); + if (!tall_pcu_ctx) + abort(); + /*initialization_of_tree*/ + egprs_compress::instance()->decode_tree_init(tall_pcu_ctx); + test_EPDAN_decode_tree(); + if (getenv("TALLOC_REPORT_FULL")) + talloc_report_full(tall_pcu_ctx, stderr); + talloc_free(tall_pcu_ctx); + return EXIT_SUCCESS; +} diff --git a/tests/bitcomp/BitcompTest.ok b/tests/bitcomp/BitcompTest.ok new file mode 100644 index 0000000..f7720fc --- /dev/null +++ b/tests/bitcomp/BitcompTest.ok @@ -0,0 +1,2 @@ +=== start test_EPDAN_decode_tree === +=== end test_EPDAN_decode_tree === diff --git a/tests/testsuite.at b/tests/testsuite.at index 1049b31..3ab39cc 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -23,6 +23,14 @@ AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/tbf/TbfTest], [0], [expout], [experr]) AT_CLEANUP + +AT_SETUP([bitcomp]) +AT_KEYWORDS([bitcomp]) +cat $abs_srcdir/bitcomp/BitcompTest.ok > expout +cat $abs_srcdir/bitcomp/BitcompTest.err > experr +AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/bitcomp/BitcompTest], [0], [expout], [experr]) +AT_CLEANUP + AT_SETUP([edge]) AT_KEYWORDS([edge]) cat $abs_srcdir/edge/EdgeTest.ok > expout -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 11 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: pravin From gerrit-no-reply at lists.osmocom.org Wed Aug 10 10:46:26 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Wed, 10 Aug 2016 10:46:26 +0000 Subject: [PATCH] openbsc[master]: Add python functions to get/set ctrl variables In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/658 to look at the new patch set (#2). Add python functions to get/set ctrl variables Add get_var and set_var functions which handle requested variable while checking for proper response and id. Split header handling into separate function. Change-Id: I08705963c277bd93a011193dd7451a626d606c21 Related: OS#1646 --- M openbsc/contrib/bsc_control.py 1 file changed, 27 insertions(+), 4 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/58/658/2 diff --git a/openbsc/contrib/bsc_control.py b/openbsc/contrib/bsc_control.py index 4fc8b4d..de0c2a9 100755 --- a/openbsc/contrib/bsc_control.py +++ b/openbsc/contrib/bsc_control.py @@ -10,15 +10,18 @@ def prefix_ipa_ctrl_header(data): return struct.pack(">HBB", len(data)+1, 0xee, 0) + data +def ipa_ctrl_header(header): + (plen, ipa_proto, osmo_proto) = struct.unpack(">HBB", header) + return None if (ipa_proto != 0xee or osmo_proto != 0) else plen + def remove_ipa_ctrl_header(data): if (len(data) < 4): raise BaseException("Answer too short!") - (plen, ipa_proto, osmo_proto) = struct.unpack(">HBB", data[:4]) + plen = ipa_ctrl_header(data[:4]) + if (None == plen): + raise BaseException("Wrong protocol in answer!") if (plen + 3 > len(data)): print "Warning: Wrong payload length (expected %i, got %i)" % (plen, len(data) - 3) - if (ipa_proto != 0xee or osmo_proto != 0): - raise BaseException("Wrong protocol in answer!") - return data[4:plen+3], data[plen+3:] def connect(host, port): @@ -44,6 +47,26 @@ getmsg = "GET %s %s" %(op_id, var) send(sck, getmsg) +def do_set_get(sck, var, value = None): + r = random.randint(1, sys.maxint) + if (value != None): + s = 'SET_REPLY' + do_set(var, value, r, sck) + else: + s = 'GET_REPLY' + do_get(var, r, sck) + (answer, data) = remove_ipa_ctrl_header(sck.recv(4096)) + x = answer.split() + if (s == x[0] and str(r) == x[1] and var == x[2]): + return None if ('SET_REPLY' == s and value != x[3]) else x[3] + return None + +def set_var(sck, var, val): + return do_set_get(sck, var, val) + +def get_var(sck, var): + return do_set_get(sck, var) + if __name__ == '__main__': random.seed() -- To view, visit https://gerrit.osmocom.org/658 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I08705963c277bd93a011193dd7451a626d606c21 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Wed Aug 10 10:46:26 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Wed, 10 Aug 2016 10:46:26 +0000 Subject: [PATCH] openbsc[master]: Add web proxy for control interface In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/659 to look at the new patch set (#4). Add web proxy for control interface Add web application exposing Control Interface over web. All of SET, GET and TRAP are fully supported. Notice: TRAP is converted into 'Server-sent events' according to RFC 6202, see also https://www.w3.org/TR/eventsource/ - this requires corresponding client. Due to use of special prefix modified version of python eventsource-client is necessary ATM. Change-Id: I87d40c80061f8b3d02d656ab8cadabbfb871b461 Related: OS#1646 --- A openbsc/contrib/ctrl2sse.py 1 file changed, 147 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/59/659/4 diff --git a/openbsc/contrib/ctrl2sse.py b/openbsc/contrib/ctrl2sse.py new file mode 100755 index 0000000..8b630ec --- /dev/null +++ b/openbsc/contrib/ctrl2sse.py @@ -0,0 +1,147 @@ +#!/usr/bin/python2 + +mod_license = ''' +/* + * Copyright (C) 2016 sysmocom s.f.m.c. GmbH + * + * All Rights Reserved + * + * 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +''' + +import sys, argparse, random, logging, tornado.ioloop, tornado.web, tornado.tcpclient, tornado.httpclient, eventsource, bsc_control +from eventsource import listener, request + +''' +N. B: this is not an example of building proper REST API or building secure web application. +It's only purpose is to illustrate conversion of Osmocom's Control Interface to web-friendly API. +Exposing this to Internet while connected to production network might lead to all sorts of mischief and mayhem +from NSA' TAO breaking into your network to zombie apocalypse. Do NOT do that. +''' + +token = None +stream = None +url = None + +''' +Returns json according to following schema - see http://json-schema.org/documentation.html for details: +{ + "title": "Ctrl Schema", + "type": "object", + "properties": { + "variable": { + "type": "string" + }, + "varlue": { + "type": "string" + } + }, + "required": ["interface", "variable", "value"] +} +Example validation from command-line: +json validate --schema-file=schema.json --document-file=data.json +The interface is represented as string because it might look different for IPv4 vs v6. +''' + +def read_header(data): + t_length = bsc_control.ipa_ctrl_header(data) + if (t_length): + stream.read_bytes(t_length - 1, callback = read_trap) + else: + print >> sys.stderr, "protocol error: length missing in %s!" % data + + at tornado.gen.coroutine +def read_trap(data): + (t, z, v, p) = data.split() + if (t != 'TRAP' or int(z) != 0): + print >> sys.stderr, "protocol error: TRAP != %s or 0! = %d" % (t, int(z)) + else: + yield tornado.httpclient.AsyncHTTPClient().fetch(tornado.httpclient.HTTPRequest(url = "%s/%s/%s" % (url, "ping", token), + method = 'POST', + headers = {'Content-Type': 'application/json'}, + body = tornado.escape.json_encode({ 'variable' : v, 'value' : p }))) + stream.read_bytes(4, callback = read_header) + + at tornado.gen.coroutine +def trap_setup(host, port, target_host, target_port, tk): + global stream + global url + global token + token = tk + url = "http://%s:%s/sse" % (host, port) + stream = yield tornado.tcpclient.TCPClient().connect(target_host, target_port) + stream.read_bytes(4, callback = read_header) + +def get_v(s, v): + return { 'variable' : v, 'value' : bsc_control.get_var(s, tornado.escape.native_str(v)) } + +class CtrlHandler(tornado.web.RequestHandler): + def initialize(self): + self.skt = bsc_control.connect(self.settings['ctrl_host'], self.settings['ctrl_port']) + + def get(self, v): + self.write(get_v(self.skt, v)) + + def post(self): + self.write(get_v(self.skt, self.get_argument("variable"))) + +class SetCtrl(CtrlHandler): + def get(self, var, val): + bsc_control.set_var(self.skt, tornado.escape.native_str(var), tornado.escape.native_str(val)) + super(SetCtrl, self).get(tornado.escape.native_str(var)) + + def post(self): + bsc_control.set_var(self.skt, tornado.escape.native_str(self.get_argument("variable")), tornado.escape.native_str(self.get_argument("value"))) + super(SetCtrl, self).post() + +class Slash(tornado.web.RequestHandler): + def get(self): + self.write('%sUsing Tornado framework v%s' + '
' + '' + '' + '
' + '
' + '' + '' + '' + '
' + '' % ("Osmocom Control Interface Proxy", tornado.version)) + +if __name__ == '__main__': + p = argparse.ArgumentParser(description='Osmocom Control Interface proxy.') + p.add_argument('-c', '--control-port', type = int, default = 4252, help = "Target Control Interface port") + p.add_argument('-a', '--control-host', default = 'localhost', help = "Target Control Interface adress") + p.add_argument('-b', '--host', default = 'localhost', help = "Adress to bind proxy's web interface") + p.add_argument('-p', '--port', type = int, default = 6969, help = "Port to bind proxy's web interface") + p.add_argument('-d', '--debug', action='store_true', help = "Activate debugging (default off)") + p.add_argument('-t', '--token', default = 'osmocom', help = "Token to be used by SSE client in URL e. g. http://127.0.0.1:8888/poll/osmocom where 'osmocom' is default token value") + p.add_argument('-k', '--keepalive', type = int, default = 5000, help = "Timeout betwwen keepalive messages, in milliseconds, defaults to 5000") + args = p.parse_args() + random.seed() + tornado.netutil.Resolver.configure('tornado.netutil.ThreadedResolver') # Use non-blocking resolver + logging.basicConfig() + application = tornado.web.Application([ + (r"/", Slash), + (r"/get", CtrlHandler), + (r"/get/(.*)", CtrlHandler), + (r"/set", SetCtrl), + (r"/set/(.*)/(.*)", SetCtrl), + (r"/sse/(.*)/(.*)", listener.EventSourceHandler, dict(event_class = listener.JSONIdEvent, keepalive = args.keepalive)), + ], debug = args.debug, ctrl_host = args.control_host, ctrl_port = args.control_port) + application.listen(address = args.host, port = args.port) + trap_setup(args.host, args.port, application.settings['ctrl_host'], application.settings['ctrl_port'], args.token) + tornado.ioloop.IOLoop.instance().start() -- To view, visit https://gerrit.osmocom.org/659 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I87d40c80061f8b3d02d656ab8cadabbfb871b461 Gerrit-PatchSet: 4 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max From gerrit-no-reply at lists.osmocom.org Wed Aug 10 10:58:31 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Wed, 10 Aug 2016 10:58:31 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 10: (3 comments) https://gerrit.osmocom.org/#/c/655/6/src/pcu_vty.c File src/pcu_vty.c: PS6, Line 133: p > why are you putting a space before the end-of-line? Which part of the code Done PS6, Line 490: DL SPB suppor > * why is there a second optional argument that is not used in the code? Done Line 493: struct gprs_rlcmac_bts *bts = bts_main_data(); > have you seen this syntax/description for help used anywhere else in the co Done -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 10 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Wed Aug 10 11:03:25 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Wed, 10 Aug 2016 11:03:25 +0000 Subject: [PATCH] osmo-pcu[master]: Use qbit-TA to update Timing Advance In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/544 to look at the new patch set (#8). Use qbit-TA to update Timing Advance Separate qbit-TA to TA conversion into separate function and use it for computing and updating Timing Advance. Note: the code was tested with TA=0 only to make sure it does not introduce regressions. Change-Id: I96fdbb20b09fb85fdd9fb6dcf3c25f6bee7f80e4 Fixes: OS#1531 --- M src/bts.cpp M src/bts.h M src/osmo-bts-litecell15/lc15_l1_if.c M src/osmo-bts-sysmo/sysmo_l1_if.c M src/pcu_l1_if.h 5 files changed, 38 insertions(+), 49 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/44/544/8 diff --git a/src/bts.cpp b/src/bts.cpp index c53c92c..2e52137 100644 --- a/src/bts.cpp +++ b/src/bts.cpp @@ -477,7 +477,7 @@ int plen; uint8_t usf = 7; uint8_t tsc; - uint16_t ta; + uint8_t ta = qta2ta(qta); rach_frame(); @@ -492,12 +492,6 @@ "but we force two phase access\n"); sb = 1; } - if (qta < 0) - qta = 0; - if (qta > 252) - qta = 252; - - ta = qta >> 2; if (sb) { rc = sba()->alloc(&trx_no, &ts_no, &sb_fn, ta); @@ -1407,6 +1401,23 @@ return rc; } +void bts_update_tbf_ta(const char *p, uint32_t fn, uint8_t trx_no, uint8_t ts, + uint8_t ta) +{ + struct gprs_rlcmac_ul_tbf *tbf = + bts_main_data()->bts->ul_tbf_by_poll_fn(fn, trx_no, ts); + if (!tbf) + LOGP(DL1IF, LOGL_DEBUG, "[%s] update TA = %u ignored due to " + "unknown UL TBF on TRX = %d, TS = %d, FN = %d\n", + p, ta, trx_no, ts, fn); + else if (tbf->ta() != ta) { + LOGP(DL1IF, LOGL_INFO, "[%s] Updating TA %u -> %u on " + "TRX = %d, TS = %d, FN = %d\n", + p, tbf->ta(), ta, trx_no, ts, fn); + tbf->set_ta(ta); + } +} + gprs_rlcmac_tbf *gprs_rlcmac_pdch::tbf_from_list_by_tfi( LListHead *tbf_list, uint8_t tfi, enum gprs_rlcmac_tbf_direction dir) diff --git a/src/bts.h b/src/bts.h index 807ce08..2960203 100644 --- a/src/bts.h +++ b/src/bts.h @@ -142,6 +142,9 @@ #endif }; +void bts_update_tbf_ta(const char *p, uint32_t fn, uint8_t trx_no, uint8_t ts, + uint8_t ta); + /** * This is the data from C. As soon as our minimal compiler is gcc 4.7 * we can start to compile pcu_vty.c with c++ and remove the split. diff --git a/src/osmo-bts-litecell15/lc15_l1_if.c b/src/osmo-bts-litecell15/lc15_l1_if.c index a2189f0..eb680b2 100644 --- a/src/osmo-bts-litecell15/lc15_l1_if.c +++ b/src/osmo-bts-litecell15/lc15_l1_if.c @@ -204,6 +204,8 @@ data_ind->msgUnitParam.u8Size-1); get_meas(&meas, &data_ind->measParam); + bts_update_tbf_ta("PH-DATA", data_ind->u32Fn, fl1h->trx_no, + data_ind->u8Tn, qta2ta(meas.bto)); switch (data_ind->sapi) { case GsmL1_Sapi_Pdtch: @@ -235,31 +237,12 @@ static int handle_ph_ra_ind(struct lc15l1_hdl *fl1h, GsmL1_PhRaInd_t *ra_ind) { - uint8_t acc_delay; - if (ra_ind->measParam.fLinkQuality < MIN_QUAL_RACH) return 0; DEBUGP(DL1IF, "Rx PH-RA.ind"); - - /* check for under/overflow / sign */ - if (ra_ind->measParam.i16BurstTiming < 0) - acc_delay = 0; - else - acc_delay = ra_ind->measParam.i16BurstTiming >> 2; - - LOGP(DL1IF, LOGL_NOTICE, "got (P)RACH request, TA = %u (ignored)\n", - acc_delay); - -#warning "The (P)RACH request is just dropped here" - -#if 0 - if (acc_delay > bts->max_ta) { - LOGP(DL1C, LOGL_INFO, "ignoring RACH request %u > max_ta(%u)\n", - acc_delay, btsb->max_ta); - return 0; - } -#endif + bts_update_tbf_ta("PH-RA", ra_ind->u32Fn, fl1h->trx_no, ra_ind->u8Tn, + qta2ta(ra_ind->measParam.i16BurstTiming)); return 0; } diff --git a/src/osmo-bts-sysmo/sysmo_l1_if.c b/src/osmo-bts-sysmo/sysmo_l1_if.c index 75a2d5f..4ebabc5 100644 --- a/src/osmo-bts-sysmo/sysmo_l1_if.c +++ b/src/osmo-bts-sysmo/sysmo_l1_if.c @@ -189,6 +189,8 @@ data_ind->msgUnitParam.u8Size-1); get_meas(&meas, &data_ind->measParam); + bts_update_tbf_ta("PH-DATA", data_ind->u32Fn, fl1h->trx_no, + data_ind->u8Tn, qta2ta(meas.bto)); switch (data_ind->sapi) { case GsmL1_Sapi_Pdtch: @@ -220,33 +222,14 @@ static int handle_ph_ra_ind(struct femtol1_hdl *fl1h, GsmL1_PhRaInd_t *ra_ind) { - uint8_t acc_delay; - pcu_rx_ra_time(ra_ind->u16Arfcn, ra_ind->u32Fn, ra_ind->u8Tn); if (ra_ind->measParam.fLinkQuality < MIN_QUAL_RACH) return 0; DEBUGP(DL1IF, "Rx PH-RA.ind"); - - /* check for under/overflow / sign */ - if (ra_ind->measParam.i16BurstTiming < 0) - acc_delay = 0; - else - acc_delay = ra_ind->measParam.i16BurstTiming >> 2; - - LOGP(DL1IF, LOGL_NOTICE, "got (P)RACH request, TA = %u (ignored)\n", - acc_delay); - -#warning "The (P)RACH request is just dropped here" - -#if 0 - if (acc_delay > bts->max_ta) { - LOGP(DL1C, LOGL_INFO, "ignoring RACH request %u > max_ta(%u)\n", - acc_delay, btsb->max_ta); - return 0; - } -#endif + bts_update_tbf_ta("PH-RA", ra_ind->u32Fn, fl1h->trx_no, ra_ind->u8Tn, + qta2ta(ra_ind->measParam.i16BurstTiming)); return 0; } diff --git a/src/pcu_l1_if.h b/src/pcu_l1_if.h index b2a9832..d9d970d 100644 --- a/src/pcu_l1_if.h +++ b/src/pcu_l1_if.h @@ -33,6 +33,15 @@ } #endif +static inline uint8_t qta2ta(int16_t qta) +{ + if (qta < 0) + return 0; + if (qta > 252) + qta = 252; + return qta >> 2; +} + /* * L1 Measurement values */ -- To view, visit https://gerrit.osmocom.org/544 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I96fdbb20b09fb85fdd9fb6dcf3c25f6bee7f80e4 Gerrit-PatchSet: 8 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max From gerrit-no-reply at lists.osmocom.org Wed Aug 10 11:19:55 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Wed, 10 Aug 2016 11:19:55 +0000 Subject: [PATCH] osmo-pcu[master]: wip.. discard pcu patch to see build log Message-ID: Review at https://gerrit.osmocom.org/678 wip.. discard pcu patch to see build log Change-Id: I935f06ea0d428fd24b23c4581f8d42209cd5a73d --- M README 1 file changed, 2 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/78/678/1 diff --git a/README b/README index 77fad7a..8c58fb8 100644 --- a/README +++ b/README @@ -17,3 +17,5 @@ * No power loop * No CS loop * No EGPRS + +Dummy change so max sees that a build either fails or works -- To view, visit https://gerrit.osmocom.org/678 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I935f06ea0d428fd24b23c4581f8d42209cd5a73d Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Holger Freyther From gerrit-no-reply at lists.osmocom.org Wed Aug 10 11:50:29 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Wed, 10 Aug 2016 11:50:29 +0000 Subject: [PATCH] osmo-pcu[master]: Use qbit-TA to update Timing Advance In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/544 to look at the new patch set (#9). Use qbit-TA to update Timing Advance Separate qbit-TA to TA conversion into separate function and use it for computing and updating Timing Advance. Note: the code was tested with TA=0 only to make sure it does not introduce regressions. Change-Id: I96fdbb20b09fb85fdd9fb6dcf3c25f6bee7f80e4 Fixes: OS#1531 --- M src/bts.cpp M src/bts.h M src/osmo-bts-litecell15/lc15_l1_if.c M src/osmo-bts-sysmo/sysmo_l1_if.c M src/pcu_l1_if.h 5 files changed, 46 insertions(+), 49 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/44/544/9 diff --git a/src/bts.cpp b/src/bts.cpp index c53c92c..2e52137 100644 --- a/src/bts.cpp +++ b/src/bts.cpp @@ -477,7 +477,7 @@ int plen; uint8_t usf = 7; uint8_t tsc; - uint16_t ta; + uint8_t ta = qta2ta(qta); rach_frame(); @@ -492,12 +492,6 @@ "but we force two phase access\n"); sb = 1; } - if (qta < 0) - qta = 0; - if (qta > 252) - qta = 252; - - ta = qta >> 2; if (sb) { rc = sba()->alloc(&trx_no, &ts_no, &sb_fn, ta); @@ -1407,6 +1401,23 @@ return rc; } +void bts_update_tbf_ta(const char *p, uint32_t fn, uint8_t trx_no, uint8_t ts, + uint8_t ta) +{ + struct gprs_rlcmac_ul_tbf *tbf = + bts_main_data()->bts->ul_tbf_by_poll_fn(fn, trx_no, ts); + if (!tbf) + LOGP(DL1IF, LOGL_DEBUG, "[%s] update TA = %u ignored due to " + "unknown UL TBF on TRX = %d, TS = %d, FN = %d\n", + p, ta, trx_no, ts, fn); + else if (tbf->ta() != ta) { + LOGP(DL1IF, LOGL_INFO, "[%s] Updating TA %u -> %u on " + "TRX = %d, TS = %d, FN = %d\n", + p, tbf->ta(), ta, trx_no, ts, fn); + tbf->set_ta(ta); + } +} + gprs_rlcmac_tbf *gprs_rlcmac_pdch::tbf_from_list_by_tfi( LListHead *tbf_list, uint8_t tfi, enum gprs_rlcmac_tbf_direction dir) diff --git a/src/bts.h b/src/bts.h index 807ce08..db31ac0 100644 --- a/src/bts.h +++ b/src/bts.h @@ -142,6 +142,15 @@ #endif }; +#ifdef __cplusplus +extern "C" { +#endif +void bts_update_tbf_ta(const char *p, uint32_t fn, uint8_t trx_no, uint8_t ts, + uint8_t ta); +#ifdef __cplusplus +} +#endif + /** * This is the data from C. As soon as our minimal compiler is gcc 4.7 * we can start to compile pcu_vty.c with c++ and remove the split. diff --git a/src/osmo-bts-litecell15/lc15_l1_if.c b/src/osmo-bts-litecell15/lc15_l1_if.c index a2189f0..5629b17 100644 --- a/src/osmo-bts-litecell15/lc15_l1_if.c +++ b/src/osmo-bts-litecell15/lc15_l1_if.c @@ -32,6 +32,7 @@ #include #include #include +#include extern void *tall_pcu_ctx; @@ -204,6 +205,8 @@ data_ind->msgUnitParam.u8Size-1); get_meas(&meas, &data_ind->measParam); + bts_update_tbf_ta("PH-DATA", data_ind->u32Fn, fl1h->trx_no, + data_ind->u8Tn, qta2ta(meas.bto)); switch (data_ind->sapi) { case GsmL1_Sapi_Pdtch: @@ -235,31 +238,12 @@ static int handle_ph_ra_ind(struct lc15l1_hdl *fl1h, GsmL1_PhRaInd_t *ra_ind) { - uint8_t acc_delay; - if (ra_ind->measParam.fLinkQuality < MIN_QUAL_RACH) return 0; DEBUGP(DL1IF, "Rx PH-RA.ind"); - - /* check for under/overflow / sign */ - if (ra_ind->measParam.i16BurstTiming < 0) - acc_delay = 0; - else - acc_delay = ra_ind->measParam.i16BurstTiming >> 2; - - LOGP(DL1IF, LOGL_NOTICE, "got (P)RACH request, TA = %u (ignored)\n", - acc_delay); - -#warning "The (P)RACH request is just dropped here" - -#if 0 - if (acc_delay > bts->max_ta) { - LOGP(DL1C, LOGL_INFO, "ignoring RACH request %u > max_ta(%u)\n", - acc_delay, btsb->max_ta); - return 0; - } -#endif + bts_update_tbf_ta("PH-RA", ra_ind->u32Fn, fl1h->trx_no, ra_ind->u8Tn, + qta2ta(ra_ind->measParam.i16BurstTiming)); return 0; } diff --git a/src/osmo-bts-sysmo/sysmo_l1_if.c b/src/osmo-bts-sysmo/sysmo_l1_if.c index 75a2d5f..8994ac3 100644 --- a/src/osmo-bts-sysmo/sysmo_l1_if.c +++ b/src/osmo-bts-sysmo/sysmo_l1_if.c @@ -13,6 +13,7 @@ #include #include #include +#include extern void *tall_pcu_ctx; @@ -189,6 +190,8 @@ data_ind->msgUnitParam.u8Size-1); get_meas(&meas, &data_ind->measParam); + bts_update_tbf_ta("PH-DATA", data_ind->u32Fn, fl1h->trx_no, + data_ind->u8Tn, qta2ta(meas.bto)); switch (data_ind->sapi) { case GsmL1_Sapi_Pdtch: @@ -220,33 +223,14 @@ static int handle_ph_ra_ind(struct femtol1_hdl *fl1h, GsmL1_PhRaInd_t *ra_ind) { - uint8_t acc_delay; - pcu_rx_ra_time(ra_ind->u16Arfcn, ra_ind->u32Fn, ra_ind->u8Tn); if (ra_ind->measParam.fLinkQuality < MIN_QUAL_RACH) return 0; DEBUGP(DL1IF, "Rx PH-RA.ind"); - - /* check for under/overflow / sign */ - if (ra_ind->measParam.i16BurstTiming < 0) - acc_delay = 0; - else - acc_delay = ra_ind->measParam.i16BurstTiming >> 2; - - LOGP(DL1IF, LOGL_NOTICE, "got (P)RACH request, TA = %u (ignored)\n", - acc_delay); - -#warning "The (P)RACH request is just dropped here" - -#if 0 - if (acc_delay > bts->max_ta) { - LOGP(DL1C, LOGL_INFO, "ignoring RACH request %u > max_ta(%u)\n", - acc_delay, btsb->max_ta); - return 0; - } -#endif + bts_update_tbf_ta("PH-RA", ra_ind->u32Fn, fl1h->trx_no, ra_ind->u8Tn, + qta2ta(ra_ind->measParam.i16BurstTiming)); return 0; } diff --git a/src/pcu_l1_if.h b/src/pcu_l1_if.h index b2a9832..d9d970d 100644 --- a/src/pcu_l1_if.h +++ b/src/pcu_l1_if.h @@ -33,6 +33,15 @@ } #endif +static inline uint8_t qta2ta(int16_t qta) +{ + if (qta < 0) + return 0; + if (qta > 252) + qta = 252; + return qta >> 2; +} + /* * L1 Measurement values */ -- To view, visit https://gerrit.osmocom.org/544 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I96fdbb20b09fb85fdd9fb6dcf3c25f6bee7f80e4 Gerrit-PatchSet: 9 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max From gerrit-no-reply at lists.osmocom.org Wed Aug 10 13:07:52 2016 From: gerrit-no-reply at lists.osmocom.org (pravin) Date: Wed, 10 Aug 2016 13:07:52 +0000 Subject: [PATCH] osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Hello Max, Neels Hofmeyr, Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/416 to look at the new patch set (#12). Add decoding of compressed bitmap in EPDAN Implemented tree based algorithm to decode compressed bitmap in EPDAN as described in section 9.1.10 of 3GPP 44.060. This algorithm intends to improve the performance over existing method. New Regression test is added under bitcomp directory. Test case is added to validate decompressed result of the bitmap Present in EPDAN. Test is done for multiple bitmaps of varying length. Invalid inputs are also part of the test vector. Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce --- M src/Makefile.am M src/decoding.cpp A src/egprs_rlc_compression.cpp A src/egprs_rlc_compression.h M src/pcu_main.cpp M tests/Makefile.am A tests/bitcomp/BitcompTest A tests/bitcomp/BitcompTest.cpp A tests/bitcomp/BitcompTest.ok M tests/testsuite.at 10 files changed, 592 insertions(+), 20 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/16/416/12 diff --git a/src/Makefile.am b/src/Makefile.am index 9bdec2f..9b047e7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -62,7 +62,8 @@ rlc.cpp \ osmobts_sock.cpp \ gprs_codel.c \ - gprs_coding_scheme.cpp + gprs_coding_scheme.cpp \ + egprs_rlc_compression.cpp bin_PROGRAMS = \ osmo-pcu @@ -94,7 +95,8 @@ pcu_utils.h \ cxx_linuxlist.h \ gprs_codel.h \ - gprs_coding_scheme.h + gprs_coding_scheme.h \ + egprs_rlc_compression.h osmo_pcu_SOURCES = pcu_main.cpp diff --git a/src/decoding.cpp b/src/decoding.cpp index 7c00ff7..2b00a07 100644 --- a/src/decoding.cpp +++ b/src/decoding.cpp @@ -20,6 +20,7 @@ #include #include #include +#include extern "C" { #include @@ -652,10 +653,10 @@ int num_blocks = 0; struct bitvec urbb; int i; + int rc; bool have_bitmap; int implicitly_acked_blocks; int ssn = desc->STARTING_SEQUENCE_NUMBER; - int rc; if (desc->FINAL_ACK_INDICATION) return handle_final_ack(bits, bsn_begin, bsn_end, window); @@ -695,24 +696,20 @@ if (crbb_len > 0) { int old_len = bits->cur_bit; - struct bitvec crbb; - crbb.data = (uint8_t *)desc->CRBB; - crbb.data_len = sizeof(desc->CRBB); - crbb.cur_bit = desc->CRBB_LENGTH; - - rc = osmo_t4_decode(&crbb, desc->CRBB_STARTING_COLOR_CODE, - bits); - + LOGP(DRLCMACDL, LOGL_DEBUG, "Compress bitmap exist," + "CRBB LEN =%d and Starting color code =%d", + desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE); + rc = decompress_crbb(desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE, + desc->CRBB, bits); if (rc < 0) { LOGP(DRLCMACUL, LOGL_NOTICE, - "Failed to decode CRBB: " - "length %d, data '%s'\n", - desc->CRBB_LENGTH, - osmo_hexdump(crbb.data, crbb.data_len)); + "Failed to decode CRBB: length %d, data '%s'\n", + desc->CRBB_LENGTH, osmo_hexdump( + desc->CRBB, (desc->CRBB_LENGTH + 7)/8)); /* We don't know the SSN offset for the URBB, - * return what we have so far and assume the - * bitmap has stopped here */ + * return what we have so far and assume the + * bitmap has stopped here */ goto aborted; } diff --git a/src/egprs_rlc_compression.cpp b/src/egprs_rlc_compression.cpp new file mode 100644 index 0000000..91021ae --- /dev/null +++ b/src/egprs_rlc_compression.cpp @@ -0,0 +1,308 @@ +/* egprs_rlc_compression.h +* Routines for EGPRS RLC bitmap compression handling +*/ +#include +#include +#include + +extern "C" { +#include +#include +#include +} + +egprs_compress *egprs_compress::s_instance = 0; +Node *egprs_compress::ones_list = NULL; +Node *egprs_compress::zeros_list = NULL; + +Node *egprs_compress::create_tree_node() +{ + Node *new_node; + + new_node = talloc_zero(tall_tree_ctx, Node); + new_node->left = NULL; + new_node->right = NULL; + new_node->run_length = -1; + return new_node; +} + +void egprs_compress::build_codeword(Node *root, const char *cdwd[]) +{ + Node *iter; + int len; + int i; + int idx; + + root->left = NULL; + root->right = NULL; + root->run_length = -1; + + for (idx = 0; idx < MAX_CDWDTBL_LEN; idx++) { + len = strlen((const char *)cdwd[idx]); + iter = root; + for (i = 0; i < len; i++) { + if (cdwd[idx][i] == '0') { + if (iter->left == NULL) + iter->left = create_tree_node(); + iter = iter->left; + } else if (cdwd[idx][i] == '1') { + if (iter->right == NULL) + iter->right = create_tree_node(); + iter = iter->right; + } + } + if (iter != NULL) { + if (idx < 64) + (iter->run_length) = idx; + else + (iter->run_length) = (idx - 63) * 64; + } + } +} + +const char *one_run_len_code_list[MAX_CDWDTBL_LEN] = { + "00110101", + "000111", + "0111", + "1000", + "1011", + "1100", + "1110", + "1111", + "10011", + "10100", + "00111", + "01000", + "001000", + "000011", + "110100", + "110101", + "101010", + "101011", + "0100111", + "0001100", + "0001000", + "0010111", + "0000011", + "0000100", + "0101000", + "0101011", + "0010011", + "0100100", + "0011000", + "00000010", + "00000011", + "00011010", + "00011011", + "00010010", + "00010011", + "00010100", + "00010101", + "00010110", + "00010111", + "00101000", + "00101001", + "00101010", + "00101011", + "00101100", + "00101101", + "00000100", + "00000101", + "00001010", + "00001011", + "01010010", + "01010011", + "01010100", + "01010101", + "00100100", + "00100101", + "01011000", + "01011001", + "01011010", + "01011011", + "01001010", + "01001011", + "00110010", + "00110011", + "00110100", + "11011", + "10010", + "010111", + "0110111", + "00110110", + "00110111", + "01100100", + "01100101", + "01101000", + "01100111", + "011001100", + "011001101", + "011010010", + "011010011", + "011010100" +}; + +const char *zero_run_len_code_list[MAX_CDWDTBL_LEN] = { + "0000110111", + "10", + "11", + "010", + "011", + "0011", + "0010", + "00011", + "000101", + "000100", + "0000100", + "0000101", + "0000111", + "00000100", + "00000111", + "000011000", + "0000010111", + "0000011000", + "0000001000", + "00001100111", + "00001101000", + "00001101100", + "00000110111", + "00000101000", + "00000010111", + "00000011000", + "000011001010", + "000011001011", + "000011001100", + "000011001101", + "000001101000", + "000001101001", + "000001101010", + "000001101011", + "000011010010", + "000011010011", + "000011010100", + "000011010101", + "000011010110", + "000011010111", + "000001101100", + "000001101101", + "000011011010", + "000011011011", + "000001010100", + "000001010101", + "000001010110", + "000001010111", + "000001100100", + "000001100101", + "000001010010", + "000001010011", + "000000100100", + "000000110111", + "000000111000", + "000000100111", + "000000101000", + "000001011000", + "000001011001", + "000000101011", + "000000101100", + "000001011010", + "000001100110", + "000001100111", + "0000001111", + "000011001000", + "000011001001", + "000001011011", + "000000110011", + "000000110100", + "000000110101", + "0000001101100", + "0000001101101", + "0000001001010", + "0000001001011", + "0000001001100", + "0000001001101", + "0000001110010", + "0000001110011" +}; + +/* search_runlen function will return the runlength for the codeword */ +static int search_runlen( + Node *root, /* root of Ones or Zeros tree */ + const uint8_t *bmbuf, /* Received compressed bitmap buf */ + uint8_t bit_pos, /* the start bit pos to read codeword */ + uint8_t *len_codewd, /* length of code word */ + uint16_t *rlen) /* run length value */ +{ + Node *iter; + uint8_t dir; + + iter = root; + *len_codewd = 0; + + while (iter->run_length == -1) { + if ((iter->left == NULL) && (iter->right == NULL)) + return -1; + /* get the bit value at the bitpos and put it in right most of dir */ + dir = ((bmbuf[BITS_TO_BYTES(bit_pos)-1] + >>(7-(MOD8(bit_pos)))) & 0x01); + (bit_pos)++; + (*len_codewd)++; + if (((dir&0x01) == 0) && (iter->left != NULL)) + iter = iter->left; + else if (((dir&0x01) == 1) && (iter->right != NULL)) + iter = iter->right; + else + return -1; + } + (*rlen) = (iter->run_length); + return 1; +} + +/*Function to decompress crbb*/ +int decompress_crbb( + int8_t compress_bmap_len, /* compressed bitmap length */ + uint8_t clr_code_bit, /* run length of Ones or Zeros */ + const uint8_t *orig_crbb_buf, /* received block crbb bitmap */ + bitvec * dest) /*uncompressed bitvector */ +{ + + uint8_t bit_pos = 0; + uint8_t data = 0x0; + node *list = NULL; + uint8_t nbits = 0; /* number of bits of codeword */ + uint16_t run_length = 0; + uint16_t cbmaplen = 0; /* compressed bitmap part after decompression */ + unsigned wp = dest->cur_bit; + int rc = 0; + egprs_compress *compress = egprs_compress::instance(); + + while (compress_bmap_len > 0) { + if (clr_code_bit == 1) { + data = 0xff; + list = compress->ones_list; + } else { + data = 0x00; + list = compress->zeros_list; + } + rc = search_runlen(list, orig_crbb_buf, + bit_pos, &nbits, &run_length); + if (rc == -1) + return -1; + /*If run length > 64, need makeup and terminating code*/ + if (run_length < 64) + clr_code_bit ? clr_code_bit = 0 : clr_code_bit = 1; + cbmaplen = cbmaplen + run_length; + /* put run length of Ones in uncompressed bitmap */ + while (run_length != 0) { + if (run_length > 8) { + bitvec_write_field(dest, wp, data, 8); + run_length = run_length - 8; + } else { + bitvec_write_field(dest, wp, data, run_length); + run_length = 0; + } + } + bit_pos = bit_pos + nbits; + compress_bmap_len = compress_bmap_len - nbits; + } + return 0; +} diff --git a/src/egprs_rlc_compression.h b/src/egprs_rlc_compression.h new file mode 100644 index 0000000..e37fe66 --- /dev/null +++ b/src/egprs_rlc_compression.h @@ -0,0 +1,73 @@ +/* egprs_rlc_compression.h + * Routines for EGPRS RLC bitmap compression handling + */ +#include +#include + +extern "C" { +#include +} + +#include +#include +#include + +#define MAX_CDWDTBL_LEN 79 /* total number of codewords */ +#define BITS_TO_BYTES(X) ((X ? (X/8):0)+1) +#define MOD8(X) (((X)+8) & (0x07)) + +typedef struct node { + struct node *left; + struct node *right; + int run_length; +} Node; + +extern const char *one_run_len_code_list[MAX_CDWDTBL_LEN]; +extern const char *zero_run_len_code_list[MAX_CDWDTBL_LEN]; + +int decompress_crbb(int8_t compress_bmap_len, uint8_t clr_code_bit, + const uint8_t *orig_buf, bitvec *dest); + +/* Creating singleton class + */ +class egprs_compress +{ + static egprs_compress *s_instance; + void *tall_tree_ctx; + + egprs_compress() + { + } + Node *create_tree_node(); + void build_codeword(Node *root, const char *cdwd[]); + void free_codeword(Node *root); + ~egprs_compress() + { + s_instance = NULL; + } +public: + static Node *ones_list; + static Node *zeros_list; + + int decode_tree_init(void *tall_pcu_ctx) + { + tall_tree_ctx = talloc_named_const(tall_pcu_ctx, 0, + "decode-tree context"); + if (!tall_tree_ctx) + return -ENOMEM; + ones_list = talloc(tall_tree_ctx, Node); + zeros_list = talloc(tall_tree_ctx, Node); + instance()->build_codeword( + ones_list, one_run_len_code_list); + instance()->build_codeword( + zeros_list, zero_run_len_code_list); + return 0; + } + static egprs_compress *instance() + { + if (!s_instance) + s_instance = new egprs_compress; + + return s_instance; + } +}; diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2d86cda..4f2853a 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -28,6 +28,7 @@ #include #include #include +#include extern "C" { #include "pcu_vty.h" #include @@ -168,7 +169,6 @@ if (!tall_pcu_ctx) return -ENOMEM; bv_tall_ctx = tall_pcu_ctx; - bts = bts_main_data(); bts->fc_interval = 1; bts->initial_cs_dl = bts->initial_cs_ul = 1; @@ -253,6 +253,11 @@ if (!bts->alloc_algorithm) bts->alloc_algorithm = alloc_algorithm_dynamic; + if (egprs_compress::instance()->decode_tree_init(tall_pcu_ctx) < 0 ){ + fprintf(stderr, "Error initializing tree\n"); + exit(1); + } + rc = pcu_l1if_open(); if (rc < 0) @@ -292,6 +297,5 @@ talloc_report_full(tall_pcu_ctx, stderr); talloc_free(tall_pcu_ctx); - return 0; } diff --git a/tests/Makefile.am b/tests/Makefile.am index 2a3415e..0f4feb1 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,7 +1,7 @@ AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGB_CFLAGS) $(LIBOSMOGSM_CFLAGS) -I$(top_srcdir)/src/ AM_LDFLAGS = -lrt -check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest llc/LlcTest codel/codel_test edge/EdgeTest +check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest llc/LlcTest codel/codel_test edge/EdgeTest bitcomp/BitcompTest noinst_PROGRAMS = emu/pcu_emu rlcmac_RLCMACTest_SOURCES = rlcmac/RLCMACTest.cpp @@ -20,6 +20,14 @@ tbf_TbfTest_SOURCES = tbf/TbfTest.cpp tbf_TbfTest_LDADD = \ + $(top_builddir)/src/libgprs.la \ + $(LIBOSMOGB_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(COMMON_LA) + +bitcomp_BitcompTest_SOURCES = bitcomp/BitcompTest.cpp +bitcomp_BitcompTest_LDADD = \ $(top_builddir)/src/libgprs.la \ $(LIBOSMOGB_LIBS) \ $(LIBOSMOGSM_LIBS) \ @@ -108,6 +116,7 @@ rlcmac/RLCMACTest.ok rlcmac/RLCMACTest.err \ alloc/AllocTest.ok alloc/AllocTest.err \ tbf/TbfTest.ok tbf/TbfTest.err \ + bitcomp/BitcompTest.ok \ types/TypesTest.ok types/TypesTest.err \ ms/MsTest.ok ms/MsTest.err \ llc/LlcTest.ok llc/LlcTest.err \ diff --git a/tests/bitcomp/BitcompTest b/tests/bitcomp/BitcompTest new file mode 100755 index 0000000..7f1384b --- /dev/null +++ b/tests/bitcomp/BitcompTest Binary files differ diff --git a/tests/bitcomp/BitcompTest.cpp b/tests/bitcomp/BitcompTest.cpp new file mode 100644 index 0000000..898f182 --- /dev/null +++ b/tests/bitcomp/BitcompTest.cpp @@ -0,0 +1,169 @@ +#include "egprs_rlc_compression.h" +#include "decoding.h" +#include "bts.h" +#include "tbf.h" +#include "gprs_debug.h" +#include "pcu_utils.h" +#include "gprs_bssgp_pcu.h" +#include "pcu_l1_if.h" + +extern "C" { +#include "pcu_vty.h" + +#include +#include +#include +#include +#include +#include +} + +#define NEW 1 +#define MASK(n) (0xFF << (8-n)) +#define MAX_CRBB_LEN 23 +#define MAX_URBB_LEN 40 +void *tall_pcu_ctx; + +struct test_data { + int8_t crbb_len; + uint8_t cc; + uint8_t crbb_data[MAX_CRBB_LEN]; /* compressed data */ + uint8_t ucmp_data[MAX_URBB_LEN]; /* uncompressed data */ + int ucmp_len; + int verify; +} test[] = { + {67, 1, + {0x02, 0x0c, 0xa0, 0x30, 0xcb, 0x1a, 0x0c, 0xe3, 0x6c}, + {0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x01, 0xff, 0xff, + 0xff, 0xf8, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, + 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xdb + }, + 194, 1 + }, + { 40, 1, + {0x53, 0x06, 0xc5, 0x40, 0x6d}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x03 + }, + 182, 1 + }, + { 8, 1, + {0x02}, + {0xff, 0xff, 0xff, 0xf8 + }, + 29, 1 + }, + { 103, 1, + {0x02, 0x0c, 0xe0, 0x41, 0xa0, 0x0c, 0x36, 0x0d, 0x03, + 0x71, 0xb0, 0x6e, 0x24 + }, + {0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xf8, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, + 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff + }, + 288, 1 + }, + /* Test vector from libosmocore test */ + { 35, 0, + {0xde, 0x88, 0x75, 0x65, 0x80}, + {0x37, 0x47, 0x81, 0xf0}, + 28, 1 + }, + { 18, 1, + {0xdd, 0x41, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00 + }, + 90, 1 + }, + /*Invalid inputs*/ + { 18, 1, + {0x1E, 0x70, 0xc0}, + {0x0}, + 0, 0 + }, + { 14, 1, + {0x00, 0x1E, 0x7c}, + {0x0}, + 0, 0 + }, + { 24, 0, + {0x00, 0x00, 0x00}, + {0x0}, + 0, 0 + } + }; + + +/* To verify the result with expected result */ +int check_result(bitvec bits, uint8_t *exp_data, int exp_len) +{ + if (bits.cur_bit != exp_len) + return 0; + size_t n = (exp_len / 8); + int rem = (exp_len % 8); + + if (memcmp(exp_data, bits.data, n) == 0) { + if (rem == 0) + return 1; + if ((bits.data[n] & MASK(rem)) == ((*(exp_data + n)) & MASK(rem))) + return 1; + else + return 0; + } else { + return 0; + } +} + +/* To test decoding of compressed bitmap by Tree based method + * and to verify the result with expected result + * for invalid input verfication is suppressed + */ +static void test_EPDAN_decode_tree(void) +{ + bitvec dest; + int init_flag = 1; + int itr; + uint8_t bits_data[RLC_EGPRS_MAX_WS/8]; + + printf("=== start %s ===\n", __func__); + + for (itr = 0 ; itr < (sizeof(test) / sizeof(test_data)) ; itr++) { + dest.data = bits_data; + dest.data_len = sizeof(bits_data); + dest.cur_bit = 0; + memset(dest.data, 0, sizeof(bits_data)); + decompress_crbb(test[itr].crbb_len, test[itr].cc, + test[itr].crbb_data, &dest + ); + + if (init_flag) + init_flag = 0; + if (test[itr].verify) { + if (check_result(dest, test[itr].ucmp_data, + test[itr].ucmp_len) == 0) { + LOGP(DRLCMACDL, LOGL_DEBUG, "Tree based", + "decoding :Error\n"); + OSMO_ASSERT(0); + } + } + } + + printf("=== end %s ===\n", __func__); +} + +int main(int argc, char **argv) +{ + tall_pcu_ctx = talloc_named_const(NULL, 1, "moiji-mobile TbfTest context"); + if (!tall_pcu_ctx) + abort(); + /*initialization_of_tree*/ + egprs_compress::instance()->decode_tree_init(tall_pcu_ctx); + test_EPDAN_decode_tree(); + if (getenv("TALLOC_REPORT_FULL")) + talloc_report_full(tall_pcu_ctx, stderr); + talloc_free(tall_pcu_ctx); + return EXIT_SUCCESS; +} diff --git a/tests/bitcomp/BitcompTest.ok b/tests/bitcomp/BitcompTest.ok new file mode 100644 index 0000000..f7720fc --- /dev/null +++ b/tests/bitcomp/BitcompTest.ok @@ -0,0 +1,2 @@ +=== start test_EPDAN_decode_tree === +=== end test_EPDAN_decode_tree === diff --git a/tests/testsuite.at b/tests/testsuite.at index 1049b31..3ab39cc 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -23,6 +23,14 @@ AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/tbf/TbfTest], [0], [expout], [experr]) AT_CLEANUP + +AT_SETUP([bitcomp]) +AT_KEYWORDS([bitcomp]) +cat $abs_srcdir/bitcomp/BitcompTest.ok > expout +cat $abs_srcdir/bitcomp/BitcompTest.err > experr +AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/bitcomp/BitcompTest], [0], [expout], [experr]) +AT_CLEANUP + AT_SETUP([edge]) AT_KEYWORDS([edge]) cat $abs_srcdir/edge/EdgeTest.ok > expout -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 12 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: pravin From gerrit-no-reply at lists.osmocom.org Wed Aug 10 13:54:29 2016 From: gerrit-no-reply at lists.osmocom.org (pravin) Date: Wed, 10 Aug 2016 13:54:29 +0000 Subject: [PATCH] osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Hello Max, Neels Hofmeyr, Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/416 to look at the new patch set (#13). Add decoding of compressed bitmap in EPDAN Implemented tree based algorithm to decode compressed bitmap in EPDAN as described in section 9.1.10 of 3GPP 44.060. This algorithm intends to improve the performance over existing method. New Regression test is added under bitcomp directory. Test case is added to validate decompressed result of the bitmap Present in EPDAN. Test is done for multiple bitmaps of varying length. Invalid inputs are also part of the test vector. Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce --- M src/Makefile.am M src/decoding.cpp A src/egprs_rlc_compression.cpp A src/egprs_rlc_compression.h M src/pcu_main.cpp M tests/Makefile.am A tests/bitcomp/BitcompTest A tests/bitcomp/BitcompTest.cpp A tests/bitcomp/BitcompTest.ok M tests/testsuite.at 10 files changed, 596 insertions(+), 20 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/16/416/13 diff --git a/src/Makefile.am b/src/Makefile.am index 9bdec2f..9b047e7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -62,7 +62,8 @@ rlc.cpp \ osmobts_sock.cpp \ gprs_codel.c \ - gprs_coding_scheme.cpp + gprs_coding_scheme.cpp \ + egprs_rlc_compression.cpp bin_PROGRAMS = \ osmo-pcu @@ -94,7 +95,8 @@ pcu_utils.h \ cxx_linuxlist.h \ gprs_codel.h \ - gprs_coding_scheme.h + gprs_coding_scheme.h \ + egprs_rlc_compression.h osmo_pcu_SOURCES = pcu_main.cpp diff --git a/src/decoding.cpp b/src/decoding.cpp index 7c00ff7..2b00a07 100644 --- a/src/decoding.cpp +++ b/src/decoding.cpp @@ -20,6 +20,7 @@ #include #include #include +#include extern "C" { #include @@ -652,10 +653,10 @@ int num_blocks = 0; struct bitvec urbb; int i; + int rc; bool have_bitmap; int implicitly_acked_blocks; int ssn = desc->STARTING_SEQUENCE_NUMBER; - int rc; if (desc->FINAL_ACK_INDICATION) return handle_final_ack(bits, bsn_begin, bsn_end, window); @@ -695,24 +696,20 @@ if (crbb_len > 0) { int old_len = bits->cur_bit; - struct bitvec crbb; - crbb.data = (uint8_t *)desc->CRBB; - crbb.data_len = sizeof(desc->CRBB); - crbb.cur_bit = desc->CRBB_LENGTH; - - rc = osmo_t4_decode(&crbb, desc->CRBB_STARTING_COLOR_CODE, - bits); - + LOGP(DRLCMACDL, LOGL_DEBUG, "Compress bitmap exist," + "CRBB LEN =%d and Starting color code =%d", + desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE); + rc = decompress_crbb(desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE, + desc->CRBB, bits); if (rc < 0) { LOGP(DRLCMACUL, LOGL_NOTICE, - "Failed to decode CRBB: " - "length %d, data '%s'\n", - desc->CRBB_LENGTH, - osmo_hexdump(crbb.data, crbb.data_len)); + "Failed to decode CRBB: length %d, data '%s'\n", + desc->CRBB_LENGTH, osmo_hexdump( + desc->CRBB, (desc->CRBB_LENGTH + 7)/8)); /* We don't know the SSN offset for the URBB, - * return what we have so far and assume the - * bitmap has stopped here */ + * return what we have so far and assume the + * bitmap has stopped here */ goto aborted; } diff --git a/src/egprs_rlc_compression.cpp b/src/egprs_rlc_compression.cpp new file mode 100644 index 0000000..91021ae --- /dev/null +++ b/src/egprs_rlc_compression.cpp @@ -0,0 +1,308 @@ +/* egprs_rlc_compression.h +* Routines for EGPRS RLC bitmap compression handling +*/ +#include +#include +#include + +extern "C" { +#include +#include +#include +} + +egprs_compress *egprs_compress::s_instance = 0; +Node *egprs_compress::ones_list = NULL; +Node *egprs_compress::zeros_list = NULL; + +Node *egprs_compress::create_tree_node() +{ + Node *new_node; + + new_node = talloc_zero(tall_tree_ctx, Node); + new_node->left = NULL; + new_node->right = NULL; + new_node->run_length = -1; + return new_node; +} + +void egprs_compress::build_codeword(Node *root, const char *cdwd[]) +{ + Node *iter; + int len; + int i; + int idx; + + root->left = NULL; + root->right = NULL; + root->run_length = -1; + + for (idx = 0; idx < MAX_CDWDTBL_LEN; idx++) { + len = strlen((const char *)cdwd[idx]); + iter = root; + for (i = 0; i < len; i++) { + if (cdwd[idx][i] == '0') { + if (iter->left == NULL) + iter->left = create_tree_node(); + iter = iter->left; + } else if (cdwd[idx][i] == '1') { + if (iter->right == NULL) + iter->right = create_tree_node(); + iter = iter->right; + } + } + if (iter != NULL) { + if (idx < 64) + (iter->run_length) = idx; + else + (iter->run_length) = (idx - 63) * 64; + } + } +} + +const char *one_run_len_code_list[MAX_CDWDTBL_LEN] = { + "00110101", + "000111", + "0111", + "1000", + "1011", + "1100", + "1110", + "1111", + "10011", + "10100", + "00111", + "01000", + "001000", + "000011", + "110100", + "110101", + "101010", + "101011", + "0100111", + "0001100", + "0001000", + "0010111", + "0000011", + "0000100", + "0101000", + "0101011", + "0010011", + "0100100", + "0011000", + "00000010", + "00000011", + "00011010", + "00011011", + "00010010", + "00010011", + "00010100", + "00010101", + "00010110", + "00010111", + "00101000", + "00101001", + "00101010", + "00101011", + "00101100", + "00101101", + "00000100", + "00000101", + "00001010", + "00001011", + "01010010", + "01010011", + "01010100", + "01010101", + "00100100", + "00100101", + "01011000", + "01011001", + "01011010", + "01011011", + "01001010", + "01001011", + "00110010", + "00110011", + "00110100", + "11011", + "10010", + "010111", + "0110111", + "00110110", + "00110111", + "01100100", + "01100101", + "01101000", + "01100111", + "011001100", + "011001101", + "011010010", + "011010011", + "011010100" +}; + +const char *zero_run_len_code_list[MAX_CDWDTBL_LEN] = { + "0000110111", + "10", + "11", + "010", + "011", + "0011", + "0010", + "00011", + "000101", + "000100", + "0000100", + "0000101", + "0000111", + "00000100", + "00000111", + "000011000", + "0000010111", + "0000011000", + "0000001000", + "00001100111", + "00001101000", + "00001101100", + "00000110111", + "00000101000", + "00000010111", + "00000011000", + "000011001010", + "000011001011", + "000011001100", + "000011001101", + "000001101000", + "000001101001", + "000001101010", + "000001101011", + "000011010010", + "000011010011", + "000011010100", + "000011010101", + "000011010110", + "000011010111", + "000001101100", + "000001101101", + "000011011010", + "000011011011", + "000001010100", + "000001010101", + "000001010110", + "000001010111", + "000001100100", + "000001100101", + "000001010010", + "000001010011", + "000000100100", + "000000110111", + "000000111000", + "000000100111", + "000000101000", + "000001011000", + "000001011001", + "000000101011", + "000000101100", + "000001011010", + "000001100110", + "000001100111", + "0000001111", + "000011001000", + "000011001001", + "000001011011", + "000000110011", + "000000110100", + "000000110101", + "0000001101100", + "0000001101101", + "0000001001010", + "0000001001011", + "0000001001100", + "0000001001101", + "0000001110010", + "0000001110011" +}; + +/* search_runlen function will return the runlength for the codeword */ +static int search_runlen( + Node *root, /* root of Ones or Zeros tree */ + const uint8_t *bmbuf, /* Received compressed bitmap buf */ + uint8_t bit_pos, /* the start bit pos to read codeword */ + uint8_t *len_codewd, /* length of code word */ + uint16_t *rlen) /* run length value */ +{ + Node *iter; + uint8_t dir; + + iter = root; + *len_codewd = 0; + + while (iter->run_length == -1) { + if ((iter->left == NULL) && (iter->right == NULL)) + return -1; + /* get the bit value at the bitpos and put it in right most of dir */ + dir = ((bmbuf[BITS_TO_BYTES(bit_pos)-1] + >>(7-(MOD8(bit_pos)))) & 0x01); + (bit_pos)++; + (*len_codewd)++; + if (((dir&0x01) == 0) && (iter->left != NULL)) + iter = iter->left; + else if (((dir&0x01) == 1) && (iter->right != NULL)) + iter = iter->right; + else + return -1; + } + (*rlen) = (iter->run_length); + return 1; +} + +/*Function to decompress crbb*/ +int decompress_crbb( + int8_t compress_bmap_len, /* compressed bitmap length */ + uint8_t clr_code_bit, /* run length of Ones or Zeros */ + const uint8_t *orig_crbb_buf, /* received block crbb bitmap */ + bitvec * dest) /*uncompressed bitvector */ +{ + + uint8_t bit_pos = 0; + uint8_t data = 0x0; + node *list = NULL; + uint8_t nbits = 0; /* number of bits of codeword */ + uint16_t run_length = 0; + uint16_t cbmaplen = 0; /* compressed bitmap part after decompression */ + unsigned wp = dest->cur_bit; + int rc = 0; + egprs_compress *compress = egprs_compress::instance(); + + while (compress_bmap_len > 0) { + if (clr_code_bit == 1) { + data = 0xff; + list = compress->ones_list; + } else { + data = 0x00; + list = compress->zeros_list; + } + rc = search_runlen(list, orig_crbb_buf, + bit_pos, &nbits, &run_length); + if (rc == -1) + return -1; + /*If run length > 64, need makeup and terminating code*/ + if (run_length < 64) + clr_code_bit ? clr_code_bit = 0 : clr_code_bit = 1; + cbmaplen = cbmaplen + run_length; + /* put run length of Ones in uncompressed bitmap */ + while (run_length != 0) { + if (run_length > 8) { + bitvec_write_field(dest, wp, data, 8); + run_length = run_length - 8; + } else { + bitvec_write_field(dest, wp, data, run_length); + run_length = 0; + } + } + bit_pos = bit_pos + nbits; + compress_bmap_len = compress_bmap_len - nbits; + } + return 0; +} diff --git a/src/egprs_rlc_compression.h b/src/egprs_rlc_compression.h new file mode 100644 index 0000000..e37fe66 --- /dev/null +++ b/src/egprs_rlc_compression.h @@ -0,0 +1,73 @@ +/* egprs_rlc_compression.h + * Routines for EGPRS RLC bitmap compression handling + */ +#include +#include + +extern "C" { +#include +} + +#include +#include +#include + +#define MAX_CDWDTBL_LEN 79 /* total number of codewords */ +#define BITS_TO_BYTES(X) ((X ? (X/8):0)+1) +#define MOD8(X) (((X)+8) & (0x07)) + +typedef struct node { + struct node *left; + struct node *right; + int run_length; +} Node; + +extern const char *one_run_len_code_list[MAX_CDWDTBL_LEN]; +extern const char *zero_run_len_code_list[MAX_CDWDTBL_LEN]; + +int decompress_crbb(int8_t compress_bmap_len, uint8_t clr_code_bit, + const uint8_t *orig_buf, bitvec *dest); + +/* Creating singleton class + */ +class egprs_compress +{ + static egprs_compress *s_instance; + void *tall_tree_ctx; + + egprs_compress() + { + } + Node *create_tree_node(); + void build_codeword(Node *root, const char *cdwd[]); + void free_codeword(Node *root); + ~egprs_compress() + { + s_instance = NULL; + } +public: + static Node *ones_list; + static Node *zeros_list; + + int decode_tree_init(void *tall_pcu_ctx) + { + tall_tree_ctx = talloc_named_const(tall_pcu_ctx, 0, + "decode-tree context"); + if (!tall_tree_ctx) + return -ENOMEM; + ones_list = talloc(tall_tree_ctx, Node); + zeros_list = talloc(tall_tree_ctx, Node); + instance()->build_codeword( + ones_list, one_run_len_code_list); + instance()->build_codeword( + zeros_list, zero_run_len_code_list); + return 0; + } + static egprs_compress *instance() + { + if (!s_instance) + s_instance = new egprs_compress; + + return s_instance; + } +}; diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2d86cda..4f2853a 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -28,6 +28,7 @@ #include #include #include +#include extern "C" { #include "pcu_vty.h" #include @@ -168,7 +169,6 @@ if (!tall_pcu_ctx) return -ENOMEM; bv_tall_ctx = tall_pcu_ctx; - bts = bts_main_data(); bts->fc_interval = 1; bts->initial_cs_dl = bts->initial_cs_ul = 1; @@ -253,6 +253,11 @@ if (!bts->alloc_algorithm) bts->alloc_algorithm = alloc_algorithm_dynamic; + if (egprs_compress::instance()->decode_tree_init(tall_pcu_ctx) < 0 ){ + fprintf(stderr, "Error initializing tree\n"); + exit(1); + } + rc = pcu_l1if_open(); if (rc < 0) @@ -292,6 +297,5 @@ talloc_report_full(tall_pcu_ctx, stderr); talloc_free(tall_pcu_ctx); - return 0; } diff --git a/tests/Makefile.am b/tests/Makefile.am index 2a3415e..8e61642 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,7 +1,7 @@ AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGB_CFLAGS) $(LIBOSMOGSM_CFLAGS) -I$(top_srcdir)/src/ AM_LDFLAGS = -lrt -check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest llc/LlcTest codel/codel_test edge/EdgeTest +check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest llc/LlcTest codel/codel_test edge/EdgeTest bitcomp/BitcompTest noinst_PROGRAMS = emu/pcu_emu rlcmac_RLCMACTest_SOURCES = rlcmac/RLCMACTest.cpp @@ -25,6 +25,17 @@ $(LIBOSMOGSM_LIBS) \ $(LIBOSMOCORE_LIBS) \ $(COMMON_LA) + +bitcomp_BitcompTest_SOURCES = bitcomp/BitcompTest.cpp +bitcomp_BitcompTest_LDADD = \ + $(top_builddir)/src/libgprs.la \ + $(LIBOSMOGB_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(COMMON_LA) + +bitcomp_BitcompTest_LDFLAGS = \ + -Wl,-u,bssgp_prim_cb edge_EdgeTest_SOURCES = edge/EdgeTest.cpp edge_EdgeTest_LDADD = \ @@ -108,6 +119,7 @@ rlcmac/RLCMACTest.ok rlcmac/RLCMACTest.err \ alloc/AllocTest.ok alloc/AllocTest.err \ tbf/TbfTest.ok tbf/TbfTest.err \ + bitcomp/BitcompTest.ok \ types/TypesTest.ok types/TypesTest.err \ ms/MsTest.ok ms/MsTest.err \ llc/LlcTest.ok llc/LlcTest.err \ diff --git a/tests/bitcomp/BitcompTest b/tests/bitcomp/BitcompTest new file mode 100755 index 0000000..c786fc3 --- /dev/null +++ b/tests/bitcomp/BitcompTest Binary files differ diff --git a/tests/bitcomp/BitcompTest.cpp b/tests/bitcomp/BitcompTest.cpp new file mode 100644 index 0000000..b03ddab --- /dev/null +++ b/tests/bitcomp/BitcompTest.cpp @@ -0,0 +1,170 @@ +#include "egprs_rlc_compression.h" +#include "decoding.h" +#include "bts.h" +#include "tbf.h" +#include "gprs_debug.h" +#include "pcu_utils.h" +#include "gprs_bssgp_pcu.h" +#include "pcu_l1_if.h" + +extern "C" { +#include "pcu_vty.h" + +#include +#include +#include +#include +#include +#include +} + +#define NEW 1 +#define MASK(n) (0xFF << (8-n)) +#define MAX_CRBB_LEN 23 +#define MAX_URBB_LEN 40 +void *tall_pcu_ctx; +int16_t spoof_mnc = 0, spoof_mcc = 0; + +struct test_data { + int8_t crbb_len; + uint8_t cc; + uint8_t crbb_data[MAX_CRBB_LEN]; /* compressed data */ + uint8_t ucmp_data[MAX_URBB_LEN]; /* uncompressed data */ + int ucmp_len; + int verify; +} test[] = { + {67, 1, + {0x02, 0x0c, 0xa0, 0x30, 0xcb, 0x1a, 0x0c, 0xe3, 0x6c}, + {0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x01, 0xff, 0xff, + 0xff, 0xf8, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, + 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xdb + }, + 194, 1 + }, + { 40, 1, + {0x53, 0x06, 0xc5, 0x40, 0x6d}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x03 + }, + 182, 1 + }, + { 8, 1, + {0x02}, + {0xff, 0xff, 0xff, 0xf8 + }, + 29, 1 + }, + { 103, 1, + {0x02, 0x0c, 0xe0, 0x41, 0xa0, 0x0c, 0x36, 0x0d, 0x03, + 0x71, 0xb0, 0x6e, 0x24 + }, + {0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xf8, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, + 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff + }, + 288, 1 + }, + /* Test vector from libosmocore test */ + { 35, 0, + {0xde, 0x88, 0x75, 0x65, 0x80}, + {0x37, 0x47, 0x81, 0xf0}, + 28, 1 + }, + { 18, 1, + {0xdd, 0x41, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00 + }, + 90, 1 + }, + /*Invalid inputs*/ + { 18, 1, + {0x1E, 0x70, 0xc0}, + {0x0}, + 0, 0 + }, + { 14, 1, + {0x00, 0x1E, 0x7c}, + {0x0}, + 0, 0 + }, + { 24, 0, + {0x00, 0x00, 0x00}, + {0x0}, + 0, 0 + } + }; + + +/* To verify the result with expected result */ +int check_result(bitvec bits, uint8_t *exp_data, int exp_len) +{ + if (bits.cur_bit != exp_len) + return 0; + size_t n = (exp_len / 8); + int rem = (exp_len % 8); + + if (memcmp(exp_data, bits.data, n) == 0) { + if (rem == 0) + return 1; + if ((bits.data[n] & MASK(rem)) == ((*(exp_data + n)) & MASK(rem))) + return 1; + else + return 0; + } else { + return 0; + } +} + +/* To test decoding of compressed bitmap by Tree based method + * and to verify the result with expected result + * for invalid input verfication is suppressed + */ +static void test_EPDAN_decode_tree(void) +{ + bitvec dest; + int init_flag = 1; + int itr; + uint8_t bits_data[RLC_EGPRS_MAX_WS/8]; + + printf("=== start %s ===\n", __func__); + + for (itr = 0 ; itr < (sizeof(test) / sizeof(test_data)) ; itr++) { + dest.data = bits_data; + dest.data_len = sizeof(bits_data); + dest.cur_bit = 0; + memset(dest.data, 0, sizeof(bits_data)); + decompress_crbb(test[itr].crbb_len, test[itr].cc, + test[itr].crbb_data, &dest + ); + + if (init_flag) + init_flag = 0; + if (test[itr].verify) { + if (check_result(dest, test[itr].ucmp_data, + test[itr].ucmp_len) == 0) { + LOGP(DRLCMACDL, LOGL_DEBUG, "Tree based", + "decoding :Error\n"); + OSMO_ASSERT(0); + } + } + } + + printf("=== end %s ===\n", __func__); +} + +int main(int argc, char **argv) +{ + tall_pcu_ctx = talloc_named_const(NULL, 1, "moiji-mobile TbfTest context"); + if (!tall_pcu_ctx) + abort(); + /*initialization_of_tree*/ + egprs_compress::instance()->decode_tree_init(tall_pcu_ctx); + test_EPDAN_decode_tree(); + if (getenv("TALLOC_REPORT_FULL")) + talloc_report_full(tall_pcu_ctx, stderr); + talloc_free(tall_pcu_ctx); + return EXIT_SUCCESS; +} diff --git a/tests/bitcomp/BitcompTest.ok b/tests/bitcomp/BitcompTest.ok new file mode 100644 index 0000000..f7720fc --- /dev/null +++ b/tests/bitcomp/BitcompTest.ok @@ -0,0 +1,2 @@ +=== start test_EPDAN_decode_tree === +=== end test_EPDAN_decode_tree === diff --git a/tests/testsuite.at b/tests/testsuite.at index 1049b31..3ab39cc 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -23,6 +23,14 @@ AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/tbf/TbfTest], [0], [expout], [experr]) AT_CLEANUP + +AT_SETUP([bitcomp]) +AT_KEYWORDS([bitcomp]) +cat $abs_srcdir/bitcomp/BitcompTest.ok > expout +cat $abs_srcdir/bitcomp/BitcompTest.err > experr +AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/bitcomp/BitcompTest], [0], [expout], [experr]) +AT_CLEANUP + AT_SETUP([edge]) AT_KEYWORDS([edge]) cat $abs_srcdir/edge/EdgeTest.ok > expout -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 13 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: pravin From gerrit-no-reply at lists.osmocom.org Wed Aug 10 14:05:41 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 10 Aug 2016 14:05:41 +0000 Subject: [PATCH] osmo-pcu[master]: jenkins.sh: ensure $MAKE is set Message-ID: Review at https://gerrit.osmocom.org/679 jenkins.sh: ensure $MAKE is set Change-Id: I2da8acdfe3abf79f68db4d00d04a7d162f0123ce --- M contrib/jenkins.sh 1 file changed, 5 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/79/679/1 diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index 27cdaa9..7d3acc0 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -2,6 +2,11 @@ set -ex +if [ -z "$MAKE" ]; then + echo 'The $MAKE variable is not defined, cannot build' + exit 1 +fi + if [ $sysmobts = "no" -a $sysmodsp = "yes" ]; then echo "This config does not make sense." exit 0 -- To view, visit https://gerrit.osmocom.org/679 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I2da8acdfe3abf79f68db4d00d04a7d162f0123ce Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Wed Aug 10 14:05:41 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 10 Aug 2016 14:05:41 +0000 Subject: [PATCH] osmo-pcu[master]: jenkins.sh: use absolute paths instead of 'cd ..' and $PWD Message-ID: Review at https://gerrit.osmocom.org/680 jenkins.sh: use absolute paths instead of 'cd ..' and $PWD Change-Id: If79d283fa0a559bb7ea319c513d09466eff523d1 --- M contrib/jenkins.sh 1 file changed, 16 insertions(+), 11 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/80/680/1 diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index 7d3acc0..b4b0cb7 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -12,18 +12,22 @@ exit 0 fi -rm -rf deps/install -mkdir deps || true -cd deps +base="$PWD" +deps="$base/deps" +inst="$deps/install" + +rm -rf "$inst" +mkdir "$deps" || true +cd "$deps" osmo-deps.sh libosmocore cd libosmocore autoreconf --install --force -./configure --prefix=$PWD/../install +./configure --prefix="$inst" $MAKE $PARALLEL_MAKE install # Install the API -cd ../ +cd "$deps" if ! test -d layer1-api; then git clone git://git.sysmocom.de/sysmo-bts/layer1-api.git layer1-api @@ -32,16 +36,17 @@ cd layer1-api git fetch origin git reset --hard origin/master -mkdir -p $PWD/../install/include/sysmocom/femtobts/ -cp include/*.h ../install/include/sysmocom/femtobts/ +api_incl="$inst/include/sysmocom/femtobts/" +mkdir -p "$api_incl" +cp include/*.h "$api_incl" -cd ../../ +cd "$base" autoreconf --install --force BTS_CONFIG="--enable-sysmocom-bts=$sysmobts --enable-sysmocom-dsp=$sysmodsp" if [ $sysmobts = "no" ]; then BTS_CONFIG="$BTS_CONFIG --enable-vty-tests" fi -PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig ./configure $BTS_CONFIG -PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig $MAKE $PARALLEL_MAKE -DISTCHECK_CONFIGURE_FLAGS="$BTS_CONFIG" AM_DISTCHECK_CONFIGURE_FLAGS="$BTS_CONFIG" PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig LD_LIBRARY_PATH=$PWD/deps/install/lib $MAKE distcheck +PKG_CONFIG_PATH="$inst/lib/pkgconfig" ./configure $BTS_CONFIG +PKG_CONFIG_PATH="$inst/lib/pkgconfig" $MAKE $PARALLEL_MAKE +DISTCHECK_CONFIGURE_FLAGS="$BTS_CONFIG" AM_DISTCHECK_CONFIGURE_FLAGS="$BTS_CONFIG" PKG_CONFIG_PATH="$inst/lib/pkgconfig" LD_LIBRARY_PATH="$inst/lib" $MAKE distcheck -- To view, visit https://gerrit.osmocom.org/680 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: If79d283fa0a559bb7ea319c513d09466eff523d1 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Wed Aug 10 14:05:42 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 10 Aug 2016 14:05:42 +0000 Subject: [PATCH] osmo-pcu[master]: jenkins.sh: more quotes, cosmetics, less dup Message-ID: Review at https://gerrit.osmocom.org/681 jenkins.sh: more quotes, cosmetics, less dup Rename BTS_CONFIG to PCU_CONFIG. More quotes. Unify bash if-style. Define *_PATH variables once globally instead of duping in every line. Change-Id: If148632c3f340a8a395fa432135e593fecc41e82 --- M contrib/jenkins.sh 1 file changed, 16 insertions(+), 17 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/81/681/1 diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index b4b0cb7..e108e36 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -7,9 +7,9 @@ exit 1 fi -if [ $sysmobts = "no" -a $sysmodsp = "yes" ]; then - echo "This config does not make sense." - exit 0 +if [ "$sysmobts" = "no" -a "$sysmodsp" = "yes" ]; then + echo "This config does not make sense." + exit 0 fi base="$PWD" @@ -17,22 +17,19 @@ inst="$deps/install" rm -rf "$inst" -mkdir "$deps" || true +mkdir -p "$deps" + cd "$deps" osmo-deps.sh libosmocore - cd libosmocore autoreconf --install --force ./configure --prefix="$inst" $MAKE $PARALLEL_MAKE install -# Install the API cd "$deps" -if ! test -d layer1-api; -then +if [ ! -d layer1-api ]; then git clone git://git.sysmocom.de/sysmo-bts/layer1-api.git layer1-api fi - cd layer1-api git fetch origin git reset --hard origin/master @@ -40,13 +37,15 @@ mkdir -p "$api_incl" cp include/*.h "$api_incl" -cd "$base" -autoreconf --install --force -BTS_CONFIG="--enable-sysmocom-bts=$sysmobts --enable-sysmocom-dsp=$sysmodsp" -if [ $sysmobts = "no" ]; then - BTS_CONFIG="$BTS_CONFIG --enable-vty-tests" +PCU_CONFIG="--enable-sysmocom-bts=$sysmobts --enable-sysmocom-dsp=$sysmodsp" +if [ "$sysmobts" = "no" ]; then + PCU_CONFIG="$PCU_CONFIG --enable-vty-tests" fi -PKG_CONFIG_PATH="$inst/lib/pkgconfig" ./configure $BTS_CONFIG -PKG_CONFIG_PATH="$inst/lib/pkgconfig" $MAKE $PARALLEL_MAKE -DISTCHECK_CONFIGURE_FLAGS="$BTS_CONFIG" AM_DISTCHECK_CONFIGURE_FLAGS="$BTS_CONFIG" PKG_CONFIG_PATH="$inst/lib/pkgconfig" LD_LIBRARY_PATH="$inst/lib" $MAKE distcheck +export PKG_CONFIG_PATH="$inst/lib/pkgconfig" +export LD_LIBRARY_PATH="$inst/lib" +cd "$base" +autoreconf --install --force +./configure $PCU_CONFIG +$MAKE $PARALLEL_MAKE +DISTCHECK_CONFIGURE_FLAGS="$PCU_CONFIG" AM_DISTCHECK_CONFIGURE_FLAGS="$PCU_CONFIG" $MAKE distcheck -- To view, visit https://gerrit.osmocom.org/681 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: If148632c3f340a8a395fa432135e593fecc41e82 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Wed Aug 10 14:05:42 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 10 Aug 2016 14:05:42 +0000 Subject: [PATCH] osmo-pcu[master]: jenkins.sh: change build matrix to $with_dsp and $with_vty Message-ID: Review at https://gerrit.osmocom.org/682 jenkins.sh: change build matrix to $with_dsp and $with_vty The new $with_dsp matrix parameter is defined as "sysmo" or empty/"none". The lc15 DSP might be added in the future. Fetch the sysmo layer 1 API only if with_dsp==sysmo. The new $with_vty parameter is independent of $with_dsp, it is now up to jenkins to define a matrix filter. For compat, until jenkins is reconfigured with the new matrix parameters, use $sysmodsp to init the new parameters to reflect previous behavior. The $sysmobts matrix parameter made no sense, drop it. Change-Id: Ia120f918342dc9563814252258b73bfb267e5253 --- M contrib/jenkins.sh 1 file changed, 43 insertions(+), 19 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/82/682/1 diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index e108e36..50f3746 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -7,10 +7,14 @@ exit 1 fi -if [ "$sysmobts" = "no" -a "$sysmodsp" = "yes" ]; then - echo "This config does not make sense." - exit 0 +# Compat: to be able to smoothly reconfigure the jenkins job, handle both +# old and new matrix variables +if [ -z "$with_dsp" -a "$sysmodsp" = yes ]; then + with_dsp="sysmo" +else + with_vty="yes" fi +# end of compat part base="$PWD" deps="$base/deps" @@ -19,6 +23,40 @@ rm -rf "$inst" mkdir -p "$deps" +# Collect configure options for osmo-pcu +PCU_CONFIG="" +if [ "$with_dsp" = sysmo ]; then + PCU_CONFIG="$PCU_CONFIG --enable-sysmocom-dsp" + + # For direct sysmo DSP access, provide the SysmoBTS Layer 1 API + cd "$deps" + if [ ! -d layer1-api ]; then + git clone git://git.sysmocom.de/sysmo-bts/layer1-api.git layer1-api + fi + cd layer1-api + git fetch origin + git reset --hard origin/master + api_incl="$inst/include/sysmocom/femtobts/" + mkdir -p "$api_incl" + cp include/*.h "$api_incl" + +elif [ -z "$with_dsp" -o "$with_dsp" = none ]; then + # Do nothing == don't build direct DSP access. +else + echo 'Invalid $with_dsp value:' $with_dsp + exit 1 +fi + +if [ "$with_vty" = "yes" ]; then + PCU_CONFIG="$PCU_CONFIG --enable-vty-tests" +elif [ -z "$with_vty" -o "$with_vty" = "no" ]; then + # Do nothing == don't do the vty tests +else + echo 'Invalid $with_vty value:' $with_vty + exit 1 +fi + +# Build deps cd "$deps" osmo-deps.sh libosmocore cd libosmocore @@ -26,24 +64,10 @@ ./configure --prefix="$inst" $MAKE $PARALLEL_MAKE install -cd "$deps" -if [ ! -d layer1-api ]; then - git clone git://git.sysmocom.de/sysmo-bts/layer1-api.git layer1-api -fi -cd layer1-api -git fetch origin -git reset --hard origin/master -api_incl="$inst/include/sysmocom/femtobts/" -mkdir -p "$api_incl" -cp include/*.h "$api_incl" - -PCU_CONFIG="--enable-sysmocom-bts=$sysmobts --enable-sysmocom-dsp=$sysmodsp" -if [ "$sysmobts" = "no" ]; then - PCU_CONFIG="$PCU_CONFIG --enable-vty-tests" -fi - export PKG_CONFIG_PATH="$inst/lib/pkgconfig" export LD_LIBRARY_PATH="$inst/lib" + +# Build osmo-pcu cd "$base" autoreconf --install --force ./configure $PCU_CONFIG -- To view, visit https://gerrit.osmocom.org/682 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ia120f918342dc9563814252258b73bfb267e5253 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Wed Aug 10 14:07:36 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 10 Aug 2016 14:07:36 +0000 Subject: [MERGED] libosmocore[master]: configure: check for pkg-config presence In-Reply-To: References: Message-ID: Neels Hofmeyr has submitted this change and it was merged. Change subject: configure: check for pkg-config presence ...................................................................... configure: check for pkg-config presence On a fresh installation, I was puzzled by a configure.ac 'syntax error' for PKG_CHECK_MODULES(TALLOC). It took me some time to figure out that merely pkg-config was missing. Add a check for pkg-config, which isn't as straightforward as I would wish, so comment generously. Change-Id: I2e7cdc37eb59f9947a45fbc5baddbaf71b655bc0 --- M configure.ac 1 file changed, 15 insertions(+), 0 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/configure.ac b/configure.ac index 33c9b5c..1b62278 100644 --- a/configure.ac +++ b/configure.ac @@ -17,6 +17,21 @@ AC_CONFIG_MACRO_DIR([m4]) +dnl check for pkg-config +dnl * If pkg-config is missing, we get a "syntax error" for PKG_CHECK_MODULES. +dnl Instead, we want to say that pkg-config and pkg.m4 are missing. +dnl * The proper way is PKG_PROG_PKG_CONFIG() but unfortunately that does not +dnl produce an intelligible error message if pkg-config is missing entirely +dnl ("syntax error near unexpected token `0.20'"). +dnl * To produce a hint that pkg-config is missing, check for the pkg-config +dnl binary; but AC_PATH_PROG breaks if the distribution provides only +dnl prefixed (-pkg-config) versions, so just print a warning. +AC_PATH_PROG(PKG_CONFIG_INSTALLED, pkg-config, no) +if test "x$PKG_CONFIG_INSTALLED" = "xno"; then + AC_MSG_WARN([You need to install pkg-config]) +fi +PKG_PROG_PKG_CONFIG([0.20]) + dnl check os: some linker flags not available on osx case $host in *-darwin*) -- To view, visit https://gerrit.osmocom.org/663 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I2e7cdc37eb59f9947a45fbc5baddbaf71b655bc0 Gerrit-PatchSet: 2 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Wed Aug 10 14:07:45 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 10 Aug 2016 14:07:45 +0000 Subject: [MERGED] libosmo-abis[master]: gitignore: platform-libtool In-Reply-To: References: Message-ID: Neels Hofmeyr has submitted this change and it was merged. Change subject: gitignore: platform-libtool ...................................................................... gitignore: platform-libtool Change-Id: I73ad62a015827582d1ac005d9a326b86c699d46b --- M .gitignore 1 file changed, 3 insertions(+), 1 deletion(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/.gitignore b/.gitignore index fa9f1fc..08b34f1 100644 --- a/.gitignore +++ b/.gitignore @@ -21,10 +21,12 @@ ltmain.sh install-sh stamp-h1 -libtool #libosmo-abis-* tests/*_test +# libtool and e.g. arm-poky-linux-gnueabi-libtool +*libtool + .tarball-version .version .dirstamp -- To view, visit https://gerrit.osmocom.org/664 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I73ad62a015827582d1ac005d9a326b86c699d46b Gerrit-PatchSet: 1 Gerrit-Project: libosmo-abis Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Wed Aug 10 14:11:10 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Wed, 10 Aug 2016 14:11:10 +0000 Subject: osmo-bts[master]: sysmo: fix dyn TS: Revert "Activate PTCCH UL" [in sysmobts] In-Reply-To: References: Message-ID: Patch Set 1: Code-Review-1 -- To view, visit https://gerrit.osmocom.org/671 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia59d95c75a8a5d3bd596f55cd1dc0906a6a95f7f Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 10 14:12:26 2016 From: gerrit-no-reply at lists.osmocom.org (pravin) Date: Wed, 10 Aug 2016 14:12:26 +0000 Subject: osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Patch Set 11: > Build Failed > > http://jenkins.osmocom.org/jenkins/job/osmo-pcu-gerrit/211/ : > FAILURE In our environment the compilation is successful but jenkins reports it as failed with an error as below, (/home/osmocom-build/jenkins/workspace/osmo-pcu-gerrit/label/linux_amd64_debian8/sysmobts/yes/sysmodsp/yes/osmo-pcu-0.2.811-0bba/_build/src/../../src/pcu_l1_if.cpp:135: undefined reference to `l1if_pdch_req'' ) at location http://jenkins.osmocom.org/jenkins/job/osmo-pcu-gerrit/label=linux_amd64_debian8,sysmobts=yes,sysmodsp=yes/lastFailedBuild/consoleText P;ease let me know what next to be done for this. -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 11 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: pravin Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 10 14:12:53 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 10 Aug 2016 14:12:53 +0000 Subject: osmo-bts[master]: sysmo: fix dyn TS: Revert "Activate PTCCH UL" [in sysmobts] In-Reply-To: References: Message-ID: Patch Set 1: > PTCCH are necessary for OS#1545. What's the actual reason for > incompatibility between dynamic TS and PTCCH? Is there anything in > the spec about it? PTCCH UL is plain not working, as described in the commit message. All you get is an error message upon SAPI activation. How is this solving a problem?? -- To view, visit https://gerrit.osmocom.org/671 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia59d95c75a8a5d3bd596f55cd1dc0906a6a95f7f Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 10 14:17:30 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 10 Aug 2016 14:17:30 +0000 Subject: osmo-bts[master]: sysmo: fix dyn TS: Revert "Activate PTCCH UL" [in sysmobts] In-Reply-To: References: Message-ID: Patch Set 1: > What's the actual reason for incompatibility between dynamic TS > and PTCCH? Is there anything in the spec about it? It's described in detail in the commit message. The SAPI act failure causes the state to not advance to "success". A subsequent switchover then does not happen as the TS is "broken". If PTCCH UL is indeed needed, then you should also check lc15, where it is still disabled. But please make sure this is really needed, because all I can see is that it Just Doesn't Work (TM) :) The dynamic TS feature that a client is really eager for is currently not working on master, so I would like to resolve this soon. -- To view, visit https://gerrit.osmocom.org/671 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia59d95c75a8a5d3bd596f55cd1dc0906a6a95f7f Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 10 14:23:16 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 10 Aug 2016 14:23:16 +0000 Subject: [PATCH] osmo-pcu[master]: jenkins.sh: change build matrix to $with_dsp and $with_vty In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/682 to look at the new patch set (#2). jenkins.sh: change build matrix to $with_dsp and $with_vty The new $with_dsp matrix parameter is defined as "sysmo" or empty/"none". The lc15 DSP might be added in the future. Fetch the sysmo layer 1 API only if with_dsp==sysmo. The new $with_vty parameter is independent of $with_dsp, it is now up to jenkins to define a matrix filter. For compat, until jenkins is reconfigured with the new matrix parameters, use $sysmodsp to init the new parameters to reflect previous behavior. The $sysmobts matrix parameter made no sense, drop it. Change-Id: Ia120f918342dc9563814252258b73bfb267e5253 --- M contrib/jenkins.sh 1 file changed, 43 insertions(+), 19 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/82/682/2 diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index e108e36..7826911 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -7,10 +7,14 @@ exit 1 fi -if [ "$sysmobts" = "no" -a "$sysmodsp" = "yes" ]; then - echo "This config does not make sense." - exit 0 +# Compat: to be able to smoothly reconfigure the jenkins job, handle both +# old and new matrix variables +if [ -z "$with_dsp" -a "$sysmodsp" = yes ]; then + with_dsp="sysmo" +else + with_vty="yes" fi +# end of compat part base="$PWD" deps="$base/deps" @@ -19,6 +23,40 @@ rm -rf "$inst" mkdir -p "$deps" +# Collect configure options for osmo-pcu +PCU_CONFIG="" +if [ "$with_dsp" = sysmo ]; then + PCU_CONFIG="$PCU_CONFIG --enable-sysmocom-dsp" + + # For direct sysmo DSP access, provide the SysmoBTS Layer 1 API + cd "$deps" + if [ ! -d layer1-api ]; then + git clone git://git.sysmocom.de/sysmo-bts/layer1-api.git layer1-api + fi + cd layer1-api + git fetch origin + git reset --hard origin/master + api_incl="$inst/include/sysmocom/femtobts/" + mkdir -p "$api_incl" + cp include/*.h "$api_incl" + +elif [ -z "$with_dsp" -o "$with_dsp" = none ]; then + echo "Direct DSP access disabled" +else + echo 'Invalid $with_dsp value:' $with_dsp + exit 1 +fi + +if [ "$with_vty" = "yes" ]; then + PCU_CONFIG="$PCU_CONFIG --enable-vty-tests" +elif [ -z "$with_vty" -o "$with_vty" = "no" ]; then + echo "VTY tests disabled" +else + echo 'Invalid $with_vty value:' $with_vty + exit 1 +fi + +# Build deps cd "$deps" osmo-deps.sh libosmocore cd libosmocore @@ -26,24 +64,10 @@ ./configure --prefix="$inst" $MAKE $PARALLEL_MAKE install -cd "$deps" -if [ ! -d layer1-api ]; then - git clone git://git.sysmocom.de/sysmo-bts/layer1-api.git layer1-api -fi -cd layer1-api -git fetch origin -git reset --hard origin/master -api_incl="$inst/include/sysmocom/femtobts/" -mkdir -p "$api_incl" -cp include/*.h "$api_incl" - -PCU_CONFIG="--enable-sysmocom-bts=$sysmobts --enable-sysmocom-dsp=$sysmodsp" -if [ "$sysmobts" = "no" ]; then - PCU_CONFIG="$PCU_CONFIG --enable-vty-tests" -fi - export PKG_CONFIG_PATH="$inst/lib/pkgconfig" export LD_LIBRARY_PATH="$inst/lib" + +# Build osmo-pcu cd "$base" autoreconf --install --force ./configure $PCU_CONFIG -- To view, visit https://gerrit.osmocom.org/682 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia120f918342dc9563814252258b73bfb267e5253 Gerrit-PatchSet: 2 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Wed Aug 10 14:25:02 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Wed, 10 Aug 2016 14:25:02 +0000 Subject: osmo-bts[master]: sysmo: fix dyn TS: Revert "Activate PTCCH UL" [in sysmobts] In-Reply-To: References: Message-ID: Patch Set 1: Ok, so why does this SAPI act failure does not manifest on regular static channels? -- To view, visit https://gerrit.osmocom.org/671 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia59d95c75a8a5d3bd596f55cd1dc0906a6a95f7f Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 10 14:34:20 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 10 Aug 2016 14:34:20 +0000 Subject: [MERGED] osmo-pcu[master]: LC: fix build error In-Reply-To: References: Message-ID: Neels Hofmeyr has submitted this change and it was merged. Change subject: LC: fix build error ...................................................................... LC: fix build error Remove extra parameter which causes build to break. The error was introduced in 878bd1f296379ffba949d6fcae2938c13406df5b Change-Id: Id63187d925d448caa4fa85720582550919b1f216 --- M src/osmo-bts-litecell15/lc15_l1_if.c 1 file changed, 1 insertion(+), 1 deletion(-) Approvals: Neels Hofmeyr: Looks good to me, approved Jenkins Builder: Verified diff --git a/src/osmo-bts-litecell15/lc15_l1_if.c b/src/osmo-bts-litecell15/lc15_l1_if.c index a2189f0..fe9dff1 100644 --- a/src/osmo-bts-litecell15/lc15_l1_if.c +++ b/src/osmo-bts-litecell15/lc15_l1_if.c @@ -156,7 +156,7 @@ case GsmL1_Sapi_Pdtch: case GsmL1_Sapi_Pacch: rc = pcu_rx_rts_req_pdtch(fl1h->trx_no, rts_ind->u8Tn, - rts_ind->u16Arfcn, rts_ind->u32Fn, rts_ind->u8BlockNbr); + rts_ind->u32Fn, rts_ind->u8BlockNbr); case GsmL1_Sapi_Ptcch: // FIXME default: -- To view, visit https://gerrit.osmocom.org/670 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: Id63187d925d448caa4fa85720582550919b1f216 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Wed Aug 10 14:39:36 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 10 Aug 2016 14:39:36 +0000 Subject: osmo-bts[master]: sysmo: fix dyn TS: Revert "Activate PTCCH UL" [in sysmobts] In-Reply-To: References: Message-ID: Patch Set 1: > Ok, so why does this SAPI act failure does not manifest on regular > static channels? It DOES manifest in regular channels, as stated in the commit log. Maybe not clearly enough, but I'm all the time talking about a plain PDCH timeslot: it throws the error. Plain PDCH still works after that, because nothing else is done with it. The last PTCCH SAPI fails to be enabled, but no-one cares. A dyn TS sees the same behavior. The error is logged, but GPRS works. However, since the PTCCH SAPI act failed, further state of that TS is broken and dyn TS can no longer be used as TCH/*. So both plain PDCH and dyn TS see the same error and behavior, but for PDCH no further harm is done, while dyn TS stop working. That's why I fail to see how PTCCH UL activation can possibly solve any problem elsewhere: the SAPI is never enabled successfully. -- To view, visit https://gerrit.osmocom.org/671 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia59d95c75a8a5d3bd596f55cd1dc0906a6a95f7f Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 10 14:50:30 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 10 Aug 2016 14:50:30 +0000 Subject: osmo-bts[master]: sysmo: fix dyn TS: Revert "Activate PTCCH UL" [in sysmobts] In-Reply-To: References: Message-ID: Patch Set 1: (Possibly dyn TS should be made more robust for the case where one of the SAPIs fails, but that's a different issue.) -- To view, visit https://gerrit.osmocom.org/671 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia59d95c75a8a5d3bd596f55cd1dc0906a6a95f7f Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 10 15:05:57 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 10 Aug 2016 15:05:57 +0000 Subject: osmo-bts[master]: dyn TS: measurement: use correct nr of subslots, rm code dup In-Reply-To: References: Message-ID: Patch Set 1: > Build Failed Depends on patch 669 in openbsc https://gerrit.osmocom.org/669 -- To view, visit https://gerrit.osmocom.org/675 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I9d9df470c49487bffd56dde42c7bec0da2f50642 Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 10 15:15:20 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 10 Aug 2016 15:15:20 +0000 Subject: [PATCH] openbsc[master]: gsm_pchan2chan_nr: disable a chan_nr assert in BTS, to not b... Message-ID: Review at https://gerrit.osmocom.org/683 gsm_pchan2chan_nr: disable a chan_nr assert in BTS, to not break octphy In https://gerrit.osmocom.org/589 , msuraev reports an assertion on octphy. So disable this recently added assertion until we clarify the invocation in question. Change-Id: Ia0f7ae5b114e179ab56b98adbae9810e81b4b88f --- M openbsc/src/libcommon/gsm_data_shared.c 1 file changed, 10 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/83/683/1 diff --git a/openbsc/src/libcommon/gsm_data_shared.c b/openbsc/src/libcommon/gsm_data_shared.c index 8d99ea4..529f72c 100644 --- a/openbsc/src/libcommon/gsm_data_shared.c +++ b/openbsc/src/libcommon/gsm_data_shared.c @@ -592,7 +592,17 @@ break; default: case GSM_PCHAN_CCCH: +#ifdef ROLE_BSC OSMO_ASSERT(lchan_nr == 0); +#else + /* + * FIXME: On octphy and litecell, we hit above assertion (see + * Max's comment at https://gerrit.osmocom.org/589 ); disabled + * for BTS until this is clarified; remove the #ifdef when it + * is fixed. + */ +#warning "fix caller that passes lchan_nr != 0" +#endif cbits = 0x10; break; } -- To view, visit https://gerrit.osmocom.org/683 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ia0f7ae5b114e179ab56b98adbae9810e81b4b88f Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Wed Aug 10 15:15:20 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 10 Aug 2016 15:15:20 +0000 Subject: [PATCH] openbsc[master]: gsm_pchan2chan_nr(): fix uninitialized cbits Message-ID: Review at https://gerrit.osmocom.org/684 gsm_pchan2chan_nr(): fix uninitialized cbits Commit ec1b5a0e9e2b6549e0ede48e803095e569997355 introduced an unset cbits value for the 'special hack for BCCH', where I break out of the switch without setting cbits. Fix that. Also remove the comment part that says 'return 0', because I don't return 0. Change-Id: I54129d921807971eeafc23f80c57666c67b71377 --- M openbsc/src/libcommon/gsm_data_shared.c 1 file changed, 5 insertions(+), 6 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/84/684/1 diff --git a/openbsc/src/libcommon/gsm_data_shared.c b/openbsc/src/libcommon/gsm_data_shared.c index 529f72c..2488c3a 100644 --- a/openbsc/src/libcommon/gsm_data_shared.c +++ b/openbsc/src/libcommon/gsm_data_shared.c @@ -573,14 +573,13 @@ case GSM_PCHAN_CCCH_SDCCH4_CBCH: /* * As a special hack for BCCH, lchan_nr == 4 may be passed - * here. This should never be sent in an RSL message, so just - * return 0. See osmo-bts-xxx/oml.c:opstart_compl(). + * here. This should never be sent in an RSL message. + * See osmo-bts-xxx/oml.c:opstart_compl(). */ - if (lchan_nr == 4) { + if (lchan_nr == 4) chan_nr = 0; - break; - } - OSMO_ASSERT(lchan_nr < 4); + else + OSMO_ASSERT(lchan_nr < 4); cbits = 0x04; cbits += lchan_nr; break; -- To view, visit https://gerrit.osmocom.org/684 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I54129d921807971eeafc23f80c57666c67b71377 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Wed Aug 10 15:16:26 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 10 Aug 2016 15:16:26 +0000 Subject: openbsc[master]: gsm_pchan2chan_nr(): fix uninitialized cbits In-Reply-To: References: Message-ID: Patch Set 3: Because gerrit/jenkins are behaving strangely with this patch, I've re-submitted as 684. -- To view, visit https://gerrit.osmocom.org/666 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: If69f6b1f6208138d5b91bac51ffd78dab95245e5 Gerrit-PatchSet: 3 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 10 15:16:51 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 10 Aug 2016 15:16:51 +0000 Subject: openbsc[master]: gsm_pchan2chan_nr: disable a chan_nr assert in BTS, to not b... In-Reply-To: References: Message-ID: Patch Set 3: Because gerrit/jenkins are behaving strangely with this patch, I've re-submitted as 683. -- To view, visit https://gerrit.osmocom.org/665 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I05253343d5bcc7b319444376098dc8561dd83944 Gerrit-PatchSet: 3 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 10 15:18:10 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 10 Aug 2016 15:18:10 +0000 Subject: openbsc[master]: gsm_pchan2chan_nr(): fix uninitialized cbits In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 This is a re-submission due to software bugs, so restoring the +2 score from #666 -- To view, visit https://gerrit.osmocom.org/684 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I54129d921807971eeafc23f80c57666c67b71377 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 10 15:18:42 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 10 Aug 2016 15:18:42 +0000 Subject: openbsc[master]: gsm_pchan2chan_nr: disable a chan_nr assert in BTS, to not b... In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 This is a re-submission due to software bugs, so restoring the +2 score from #665 -- To view, visit https://gerrit.osmocom.org/683 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia0f7ae5b114e179ab56b98adbae9810e81b4b88f Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 10 15:18:53 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Wed, 10 Aug 2016 15:18:53 +0000 Subject: openbsc[master]: gsm_pchan2chan_nr: disable a chan_nr assert in BTS, to not b... In-Reply-To: References: Message-ID: Patch Set 1: Verified+1 -- To view, visit https://gerrit.osmocom.org/683 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia0f7ae5b114e179ab56b98adbae9810e81b4b88f Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 10 15:25:08 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 10 Aug 2016 15:25:08 +0000 Subject: [MERGED] openbsc[master]: gsm_pchan2chan_nr(): fix uninitialized cbits In-Reply-To: References: Message-ID: Neels Hofmeyr has submitted this change and it was merged. Change subject: gsm_pchan2chan_nr(): fix uninitialized cbits ...................................................................... gsm_pchan2chan_nr(): fix uninitialized cbits Commit ec1b5a0e9e2b6549e0ede48e803095e569997355 introduced an unset cbits value for the 'special hack for BCCH', where I break out of the switch without setting cbits. Fix that. Also remove the comment part that says 'return 0', because I don't return 0. Change-Id: I54129d921807971eeafc23f80c57666c67b71377 --- M openbsc/src/libcommon/gsm_data_shared.c 1 file changed, 5 insertions(+), 6 deletions(-) Approvals: Neels Hofmeyr: Looks good to me, approved Jenkins Builder: Verified diff --git a/openbsc/src/libcommon/gsm_data_shared.c b/openbsc/src/libcommon/gsm_data_shared.c index 529f72c..2488c3a 100644 --- a/openbsc/src/libcommon/gsm_data_shared.c +++ b/openbsc/src/libcommon/gsm_data_shared.c @@ -573,14 +573,13 @@ case GSM_PCHAN_CCCH_SDCCH4_CBCH: /* * As a special hack for BCCH, lchan_nr == 4 may be passed - * here. This should never be sent in an RSL message, so just - * return 0. See osmo-bts-xxx/oml.c:opstart_compl(). + * here. This should never be sent in an RSL message. + * See osmo-bts-xxx/oml.c:opstart_compl(). */ - if (lchan_nr == 4) { + if (lchan_nr == 4) chan_nr = 0; - break; - } - OSMO_ASSERT(lchan_nr < 4); + else + OSMO_ASSERT(lchan_nr < 4); cbits = 0x04; cbits += lchan_nr; break; -- To view, visit https://gerrit.osmocom.org/684 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I54129d921807971eeafc23f80c57666c67b71377 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Wed Aug 10 15:25:08 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 10 Aug 2016 15:25:08 +0000 Subject: [MERGED] openbsc[master]: gsm_pchan2chan_nr: disable a chan_nr assert in BTS, to not b... In-Reply-To: References: Message-ID: Neels Hofmeyr has submitted this change and it was merged. Change subject: gsm_pchan2chan_nr: disable a chan_nr assert in BTS, to not break octphy ...................................................................... gsm_pchan2chan_nr: disable a chan_nr assert in BTS, to not break octphy In https://gerrit.osmocom.org/589 , msuraev reports an assertion on octphy. So disable this recently added assertion until we clarify the invocation in question. Change-Id: Ia0f7ae5b114e179ab56b98adbae9810e81b4b88f --- M openbsc/src/libcommon/gsm_data_shared.c 1 file changed, 10 insertions(+), 0 deletions(-) Approvals: Max: Verified Neels Hofmeyr: Looks good to me, approved Jenkins Builder: Verified diff --git a/openbsc/src/libcommon/gsm_data_shared.c b/openbsc/src/libcommon/gsm_data_shared.c index 8d99ea4..529f72c 100644 --- a/openbsc/src/libcommon/gsm_data_shared.c +++ b/openbsc/src/libcommon/gsm_data_shared.c @@ -592,7 +592,17 @@ break; default: case GSM_PCHAN_CCCH: +#ifdef ROLE_BSC OSMO_ASSERT(lchan_nr == 0); +#else + /* + * FIXME: On octphy and litecell, we hit above assertion (see + * Max's comment at https://gerrit.osmocom.org/589 ); disabled + * for BTS until this is clarified; remove the #ifdef when it + * is fixed. + */ +#warning "fix caller that passes lchan_nr != 0" +#endif cbits = 0x10; break; } -- To view, visit https://gerrit.osmocom.org/683 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ia0f7ae5b114e179ab56b98adbae9810e81b4b88f Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Wed Aug 10 15:25:51 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 10 Aug 2016 15:25:51 +0000 Subject: [ABANDON] openbsc[master]: gsm_pchan2chan_nr: disable a chan_nr assert in BTS, to not b... In-Reply-To: References: Message-ID: Neels Hofmeyr has abandoned this change. Change subject: gsm_pchan2chan_nr: disable a chan_nr assert in BTS, to not break octphy ...................................................................... Abandoned The re-submission was successful, dropping this. -- To view, visit https://gerrit.osmocom.org/665 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: abandon Gerrit-Change-Id: I05253343d5bcc7b319444376098dc8561dd83944 Gerrit-PatchSet: 3 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Wed Aug 10 15:26:02 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 10 Aug 2016 15:26:02 +0000 Subject: [ABANDON] openbsc[master]: gsm_pchan2chan_nr(): fix uninitialized cbits In-Reply-To: References: Message-ID: Neels Hofmeyr has abandoned this change. Change subject: gsm_pchan2chan_nr(): fix uninitialized cbits ...................................................................... Abandoned The re-submission was successful, dropping this. -- To view, visit https://gerrit.osmocom.org/666 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: abandon Gerrit-Change-Id: If69f6b1f6208138d5b91bac51ffd78dab95245e5 Gerrit-PatchSet: 3 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Wed Aug 10 15:30:36 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Wed, 10 Aug 2016 15:30:36 +0000 Subject: osmo-pcu[master]: jenkins.sh: change build matrix to $with_dsp and $with_vty In-Reply-To: References: Message-ID: Patch Set 2: Code-Review+1 -- To view, visit https://gerrit.osmocom.org/682 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia120f918342dc9563814252258b73bfb267e5253 Gerrit-PatchSet: 2 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 10 15:40:48 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Wed, 10 Aug 2016 15:40:48 +0000 Subject: osmo-bts[master]: sysmo: fix dyn TS: Revert "Activate PTCCH UL" [in sysmobts] In-Reply-To: References: Message-ID: Patch Set 1: According to fw docs the only channel combination with PTCCH support is GsmL1_LogChComb_XIII so it's incompatible with dyn channels - see src/osmo-bts-sysmo/oml.c -- To view, visit https://gerrit.osmocom.org/671 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia59d95c75a8a5d3bd596f55cd1dc0906a6a95f7f Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 10 15:54:57 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Wed, 10 Aug 2016 15:54:57 +0000 Subject: [PATCH] openbsc[master]: Adding SNDCP-XID encoder / decoder In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/641 to look at the new patch set (#7). Adding SNDCP-XID encoder / decoder The SNDCP-XID (or layer-3 xid) is used to exchange layer-3 parameters such as compression. The encoder encodes a bytestream that is then sent as regular XID field from LLC. We will need the SNDCP-XID to negotiate the parameters for our upcomming GPRS data and header compression features Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e --- M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_sndcp_xid.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_sndcp_xid.c M openbsc/tests/Makefile.am M openbsc/tests/sgsn/Makefile.am M openbsc/tests/testsuite.at A openbsc/tests/xid_sndcp/Makefile.am A openbsc/tests/xid_sndcp/sndcp_xid_test.c A openbsc/tests/xid_sndcp/sndcp_xid_test.ok 11 files changed, 2,407 insertions(+), 5 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/41/641/7 diff --git a/openbsc/configure.ac b/openbsc/configure.ac index fbf2930..9cfdc7c 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -230,6 +230,7 @@ tests/gtphub/Makefile tests/mm_auth/Makefile tests/xid/Makefile + tests/xid_sndcp/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index ce5f768..e200b05 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,7 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_llc_xid.h gprs_sndcp.h + gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_sndcp_xid.h b/openbsc/include/openbsc/gprs_sndcp_xid.h new file mode 100644 index 0000000..b2b483c --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_xid.h @@ -0,0 +1,215 @@ +/* GPRS SNDCP XID field encoding/decoding as per 3GPP TS 44.065 */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_SNDCP_XID_H +#define _GPRS_SNDCP_XID_H + +#include +#include + +#define CURRENT_SNDCP_VERSION 0 /* See 3GPP TS 44.065, clause 8 */ +#define MAX_ENTITIES 32 /* 3GPP TS 44.065 reserves 5 bit + * for compression enitity number */ + +/* According to: 3GPP TS 44.065, 6.5.1.1 Format of the protocol control + * information compression field (Figure 7) + * 3GPP TS 44.065, 6.6.1.1 Format of the data compression + * field (Figure 9) */ +struct gprs_sndcp_comp_field { + struct llist_head list; + + /* Propose bit (P), see also: 6.5.1.1.2 and 6.6.1.1.2 */ + unsigned int p; + + /* Entity number, see also: 6.5.1.1.3 and 6.6.1.1.3 */ + unsigned int entity; + + /* Algorithm identifier, see also: 6.5.1.1.4 and 6.6.1.1.4 */ + int algo; + + /* Number of contained PCOMP / DCOMP values */ + unsigned int comp_len; + + /* PCOMP / DCOMP values, see also: 6.5.1.1.5 and 6.6.1.1.5 */ + unsigned int comp[16]; + + /* Note: Only one of the following struct pointers may, + be used unused pointers must be set to NULL! */ + struct gprs_sndcp_pcomp_rfc1144_params *rfc1144_params; + struct gprs_sndcp_pcomp_rfc2507_params *rfc2507_params; + struct gprs_sndcp_pcomp_rohc_params *rohc_params; + struct gprs_sndcp_dcomp_v42bis_params *v42bis_params; + struct gprs_sndcp_dcomp_v44_params *v44_params; +}; + +/* According to: 3GPP TS 44.065, 6.5.1.1.4 Algorithm identifier */ +enum gprs_sndcp_hdr_comp_algo { + RFC_1144, /* TCP/IP header compression, see also 6.5.2 */ + RFC_2507, /* TCP/UDP/IP header compression, see also: 6.5.3 */ + ROHC /* Robust Header Compression, see also 6.5.4 */ +}; + +/* According to: 3GPP TS 44.065, 6.5.1.1.4 Algorithm identifier */ +enum gprs_sndcp_data_comp_algo { + V42BIS, /* V.42bis data compression, see also 6.6.2 */ + V44 /* V44 data compression, see also: 6.6.3 */ +}; + +/* According to: 3GPP TS 44.065, 8 SNDCP XID parameters */ +enum gprs_sndcp_xid_param_types { + SNDCP_XID_VERSION_NUMBER, + SNDCP_XID_DATA_COMPRESSION, /* See also: subclause 6.6.1 */ + SNDCP_XID_PROTOCOL_COMPRESSION, /* See also: subclause 6.5.1 */ +}; + +/* According to: 3GPP TS 44.065, 6.5.2.1 Parameters (Table 5) */ +struct gprs_sndcp_pcomp_rfc1144_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int s01; /* (default 15) */ +}; + +/* According to: 3GPP TS 44.065, 6.5.2.2 Assignment of PCOMP values */ +enum gprs_sndcp_pcomp_rfc1144_pcomp { + RFC1144_PCOMP1, /* Uncompressed TCP */ + RFC1144_PCOMP2, /* Compressed TCP */ + RFC1144_PCOMP_NUM /* Number of pcomp values */ +}; + +/* According to: 3GPP TS 44.065, 6.5.3.1 Parameters (Table 6) */ +struct gprs_sndcp_pcomp_rfc2507_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int f_max_period; /* (default 256) */ + int f_max_time; /* (default 5) */ + int max_header; /* (default 168) */ + int tcp_space; /* (default 15) */ + int non_tcp_space; /* (default 15) */ +}; + +/* According to: 3GPP TS 44.065, 6.5.3.2 Assignment of PCOMP values for RFC2507 */ +enum gprs_sndcp_pcomp_rfc2507_pcomp { + RFC2507_PCOMP1, /* Full Header */ + RFC2507_PCOMP2, /* Compressed TCP */ + RFC2507_PCOMP3, /* Compressed TCP non delta */ + RFC2507_PCOMP4, /* Compressed non TCP */ + RFC2507_PCOMP5, /* Context state */ + RFC2507_PCOMP_NUM /* Number of pcomp values */ +}; + +/* According to: 3GPP TS 44.065, 6.5.4.1 Parameter (Table 10) */ +struct gprs_sndcp_pcomp_rohc_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int max_cid; /* (default 15) */ + int max_header; /* (default 168) */ + unsigned int profile_len; /* (default 1) */ + uint16_t profile[16]; /* (default 0, ROHC uncompressed) */ +}; + +/* According to: 3GPP TS 44.065, 6.5.4.2 Assignment of PCOMP values for ROHC */ +enum gprs_sndcp_pcomp_rohc_pcomp { + ROHC_PCOMP1, /* ROHC small CIDs */ + ROHC_PCOMP2, /* ROHC large CIDs */ + ROHC_PCOMP_NUM /* Number of pcomp values */ +}; + +/* ROHC compression profiles, see also: + http://www.iana.org/assignments/rohc-pro-ids/rohc-pro-ids.xhtml */ +enum gprs_sndcp_xid_rohc_profiles { + ROHC_UNCOMPRESSED = 0x0000, /* ROHC uncompressed [RFC5795] */ + ROHC_RTP = 0x0001, /* ROHC RTP [RFC3095] */ + ROHCV2_RTP = 0x0101, /* ROHCv2 RTP [RFC5225] */ + ROHC_UDP = 0x0002, /* ROHC UDP [RFC3095] */ + ROHCv2_UDP = 0x0102, /* ROHCv2 UDP [RFC5225] */ + ROHC_ESP = 0x0003, /* ROHC ESP [RFC3095] */ + ROHCV2_ESP = 0x0103, /* ROHCv2 ESP [RFC5225] */ + ROHC_IP = 0x0004, /* ROHC IP [RFC3843] */ + ROHCV2_IP = 0x0104, /* ROHCv2 IP [RFC5225] */ + ROHC_LLA = 0x0005, /* ROHC LLA [RFC4362] */ + ROHC_LLA_WITH_R_MODE = 0x0105, /* ROHC LLA with R-mode [RFC3408] */ + ROHC_TCP = 0x0006, /* ROHC TCP [RFC6846] */ + ROHC_RTP_UDP_LITE = 0x0007, /* ROHC RTP/UDP-Lite [RFC4019] */ + ROHCV2_RTP_UDP_LITE = 0x0107, /* ROHCv2 RTP/UDP-Lite [RFC5225] */ + ROHC_UDP_LITE = 0x0008, /* ROHC UDP-Lite [RFC4019] */ + ROHCV2_UDP_LITE = 0x0108, /* ROHCv2 UDP-Lite [RFC5225] */ +}; + +/* According to: 3GPP TS 44.065, 6.6.2.1 Parameters (Table 7a) */ +struct gprs_sndcp_dcomp_v42bis_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int p0; /* (default 3) */ + int p1; /* (default 2048) */ + int p2; /* (default 20) */ + +}; + +/* According to: 3GPP TS 44.065, 6.6.2.2 Assignment of DCOMP values */ +enum gprs_sndcp_dcomp_v42bis_dcomp { + V42BIS_DCOMP1, /* V.42bis enabled */ + V42BIS_DCOMP_NUM /* Number of dcomp values */ +}; + +/* According to: 3GPP TS 44.065, 6.6.3.1 Parameters (Table 7c) */ +struct gprs_sndcp_dcomp_v44_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int c0; /* (default 10000000) */ + int p0; /* (default 3) */ + int p1t; /* Refer to subclause 6.6.3.1.4 */ + int p1r; /* Refer to subclause 6.6.3.1.5 */ + int p3t; /* (default 3 x p1t) */ + int p3r; /* (default 3 x p1r) */ +}; + +/* According to: 3GPP TS 44.065, 6.6.3.2 Assignment of DCOMP values */ +enum gprs_sndcp_dcomp_v44_dcomp { + V44_DCOMP1, /* Packet method compressed */ + V44_DCOMP2, /* Multi packet method compressed */ + V44_DCOMP_NUM /* Number of dcomp values */ +}; + +/* Transform a list with compression fields into an SNDCP-XID message (dst) */ +int gprs_sndcp_compile_xid(uint8_t *dst, unsigned int dst_maxlen, + const struct llist_head *comp_fields); + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +struct llist_head *gprs_sndcp_parse_xid(const void *ctx, + const uint8_t * src, + unsigned int src_len, + const struct llist_head + *comp_fields_req); + +/* Free a list with SNDCP-XID fields */ +struct llist_head *gprs_sndcp_free_comp_fields(struct llist_head *comp_fields); + +/* Find out to which compression class the specified comp-field belongs + * (header compression or data compression?) */ +int gprs_sndcp_get_compression_class(const struct gprs_sndcp_comp_field + *comp_field); + +/* Dump a list with SNDCP-XID fields (Debug) */ +void gprs_sndcp_dump_comp_fields(const struct llist_head *comp_fields, + unsigned int logl); + +#endif diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 1b6de46..fa4a3dd 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -26,11 +26,11 @@ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ - oap.c oap_messages.c gprs_llc_xid.c + oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ - $(LIBCRYPTO_LIBS) -lrt + $(LIBCRYPTO_LIBS) -lrt -lm osmo_gtphub_SOURCES = gtphub_main.c gtphub.c gtphub_sock.c gtphub_ares.c \ gtphub_vty.c sgsn_ares.c gprs_utils.c diff --git a/openbsc/src/gprs/gprs_sndcp_xid.c b/openbsc/src/gprs/gprs_sndcp_xid.c new file mode 100644 index 0000000..03687d5 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_xid.c @@ -0,0 +1,1871 @@ +/* GPRS SNDCP XID field encoding/decoding as per 3GPP TS 44.065 */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* When the propose bit in an SNDCP-XID compression field is set to zero, + * the algorithm identifier is stripped. The algoritm parameters are specific + * for each algorithms. The following struct is used to pass the information + * about the referenced algorithm to the parser. */ +struct entity_algo_table { + unsigned int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + unsigned int algo; /* see also: 6.5.1.1.4 and 6.6.1.1.4 */ + unsigned int compclass; /* Can be either SNDCP_XID_DATA_COMPRESSION or + SNDCP_XID_PROTOCOL_COMPRESSION */ +}; + +/* FUNCTIONS RELATED TO SNDCP-XID ENCODING */ + +/* Encode applicable sapis (works the same in all three compression schemes) */ +static int encode_pcomp_applicable_sapis(uint8_t *dst, + const unsigned int *nsapis, + unsigned int nsapis_len) +{ + /* NOTE: Buffer *dst needs offer at 2 bytes + * of space to store the generation results */ + + uint16_t blob; + unsigned int nsapi; + int i; + + OSMO_ASSERT(dst); + OSMO_ASSERT(nsapis); + + /* Bail if number of possible nsapis exceeds valid range + * (Only 11 nsapis possible for PDP-Contexts) */ + OSMO_ASSERT(nsapis_len <= 11); + + /* Encode applicable SAPIs */ + blob = 0; + for (i = 0; i < nsapis_len; i++) { + nsapi = nsapis[i]; + /* Only NSAPI 5 to 15 are applicable for user traffic (PDP- + * contexts). Only for these NSAPIs SNDCP-XID parameters + * can apply. See also 3GPP TS 44.065, 5.1 Service primitives */ + OSMO_ASSERT(nsapi >= 5 && nsapi <= 15); + blob |= (1 << nsapi); + } + + /* Store result */ + *dst = (blob >> 8) & 0xFF; + dst++; + *dst = blob & 0xFF; + + return 2; +} + +/* Encode rfc1144 parameter field + * (see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */ +static int encode_pcomp_rfc1144_params(uint8_t *dst, unsigned int dst_maxlen, const struct + gprs_sndcp_pcomp_rfc1144_params *params) +{ + /* NOTE: Buffer *dst should offer at least 3 bytes + * of space to store the generation results */ + + int dst_counter = 0; + int rc; + + OSMO_ASSERT(params); + OSMO_ASSERT(dst); + OSMO_ASSERT(dst_maxlen >= 3); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode s01 (see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */ + *dst = params->s01; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + +/* + * Encode rfc2507 parameter field + * (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) + */ +static int encode_pcomp_rfc2507_params(uint8_t *dst, unsigned int dst_maxlen, + const struct + gprs_sndcp_pcomp_rfc2507_params *params) +{ + /* NOTE: Buffer *dst should offer at least 3 bytes + * of space to store the generation results */ + + int dst_counter = 0; + int rc; + + OSMO_ASSERT(params); + OSMO_ASSERT(dst); + OSMO_ASSERT(dst_maxlen >= 9); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode F_MAX_PERIOD (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->f_max_period >= 1); + OSMO_ASSERT(params->f_max_period <= 65535); + *dst = (params->f_max_period >> 8) & 0xFF; + dst++; + dst_counter++; + *dst = (params->f_max_period) & 0xFF; + dst++; + dst_counter++; + + /* Encode F_MAX_TIME (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->f_max_time >= 1); + OSMO_ASSERT(params->f_max_time <= 255); + *dst = params->f_max_time; + dst++; + dst_counter++; + + /* Encode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->max_header >= 60); + OSMO_ASSERT(params->max_header <= 255); + *dst = params->max_header; + dst++; + dst_counter++; + + /* Encode TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->tcp_space >= 3); + OSMO_ASSERT(params->tcp_space <= 255); + *dst = params->tcp_space; + dst++; + dst_counter++; + + /* Encode NON_TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->non_tcp_space >= 3); + OSMO_ASSERT(params->non_tcp_space <= 65535); + *dst = (params->non_tcp_space >> 8) & 0xFF; + dst++; + dst_counter++; + *dst = (params->non_tcp_space) & 0xFF; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + +/* Encode ROHC parameter field + * (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ +static int encode_pcomp_rohc_params(uint8_t *dst, unsigned int dst_maxlen, + const struct gprs_sndcp_pcomp_rohc_params + *params) +{ + /* NOTE: Buffer *dst should offer at least 36 + * (2 * 16 Profiles + 2 * 3 Parameter) bytes + * of memory space to store generation results */ + + int i; + int dst_counter = 0; + int rc; + + OSMO_ASSERT(params); + OSMO_ASSERT(dst); + OSMO_ASSERT(dst_maxlen >= 38); + + /* Bail if number of ROHC profiles exceeds limit + * (ROHC supports only a maximum of 16 different profiles) */ + OSMO_ASSERT(params->profile_len >= 0); + OSMO_ASSERT(params->profile_len <= 16); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode MAX_CID (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + OSMO_ASSERT(params->max_cid >= 0); + OSMO_ASSERT(params->max_cid <= 16383); + *dst = (params->max_cid >> 8) & 0xFF; + dst++; + *dst = params->max_cid & 0xFF; + dst++; + dst_counter += 2; + + /* Encode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + OSMO_ASSERT(params->max_header >= 60); + OSMO_ASSERT(params->max_header <= 255); + *dst = (params->max_header >> 8) & 0xFF; + dst++; + *dst = params->max_header & 0xFF; + dst++; + dst_counter += 2; + + /* Encode ROHC Profiles (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + for (i = 0; i < params->profile_len; i++) { + *dst = (params->profile[i] >> 8) & 0xFF; + dst++; + *dst = params->profile[i] & 0xFF; + dst++; + dst_counter += 2; + } + + /* Return generated length */ + return dst_counter; +} + +/* Encode V.42bis parameter field + * (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ +static int encode_dcomp_v42bis_params(uint8_t *dst, unsigned int dst_maxlen, + const struct + gprs_sndcp_dcomp_v42bis_params *params) +{ + /* NOTE: Buffer *dst should offer at least 6 bytes + * of space to store the generation results */ + + int dst_counter = 0; + int rc; + + OSMO_ASSERT(params); + OSMO_ASSERT(dst); + OSMO_ASSERT(dst_maxlen >= 6); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode P0 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + OSMO_ASSERT(params->p0 >= 0); + OSMO_ASSERT(params->p0 <= 3); + *dst = params->p0 & 0x03; + dst++; + dst_counter++; + + /* Encode P1 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + OSMO_ASSERT(params->p1 >= 512); + OSMO_ASSERT(params->p1 <= 65535); + *dst = (params->p1 >> 8) & 0xFF; + dst++; + *dst = params->p1 & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P2 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + OSMO_ASSERT(params->p2 >= 6); + OSMO_ASSERT(params->p2 <= 250); + *dst = params->p2; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + +/* Encode V44 parameter field + * (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ +static int encode_dcomp_v44_params(uint8_t *dst, unsigned int dst_maxlen, + const struct gprs_sndcp_dcomp_v44_params + *params) +{ + /* NOTE: Buffer *dst should offer at least 12 bytes + * of space to store the generation results */ + + int dst_counter = 0; + int rc; + + OSMO_ASSERT(params); + OSMO_ASSERT(dst); + OSMO_ASSERT(dst_maxlen >= 12); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode C0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->c0 == 0x80 || params->c0 == 0xC0); + *dst = params->c0 & 0xC0; + dst++; + dst_counter++; + + /* Encode P0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p0 >= 0); + OSMO_ASSERT(params->p0 <= 3); + *dst = params->p0 & 0x03; + dst++; + dst_counter++; + + /* Encode P1T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p1t >= 256); + OSMO_ASSERT(params->p1t <= 65535); + *dst = (params->p1t >> 8) & 0xFF; + dst++; + *dst = params->p1t & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P1R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p1r >= 256); + OSMO_ASSERT(params->p1r <= 65535); + *dst = (params->p1r >> 8) & 0xFF; + dst++; + *dst = params->p1r & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P3T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p3t >= 0); + OSMO_ASSERT(params->p3t <= 65535); + OSMO_ASSERT(params->p3t >= 2 * params->p1t); + *dst = (params->p3t >> 8) & 0xFF; + dst++; + *dst = params->p3t & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P3R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p3r >= 0); + OSMO_ASSERT(params->p3r <= 65535); + OSMO_ASSERT(params->p3r >= 2 * params->p1r); + *dst = (params->p3r >> 8) & 0xFF; + dst++; + *dst = params->p3r & 0xFF; + dst++; + dst_counter += 2; + + /* Return generated length */ + return dst_counter; +} + +/* Encode data or protocol control information compression field + * (see also: 3GPP TS 44.065, 6.6.1.1, Figure 9 and + * 3GPP TS 44.065, 6.5.1.1, Figure 7) */ +static int encode_comp_field(uint8_t *dst, unsigned int dst_maxlen, + const struct gprs_sndcp_comp_field *comp_field) +{ + int dst_counter = 0; + int len; + int expected_length; + int i; + + OSMO_ASSERT(dst); + OSMO_ASSERT(comp_field); + + uint8_t payload_bytes[256]; + int payload_bytes_len = -1; + + /* If possible, try do encode payload bytes first */ + if (comp_field->rfc1144_params) { + payload_bytes_len = + encode_pcomp_rfc1144_params(payload_bytes, + sizeof(payload_bytes), + comp_field->rfc1144_params); + } else if (comp_field->rfc2507_params) { + payload_bytes_len = + encode_pcomp_rfc2507_params(payload_bytes, + sizeof(payload_bytes), + comp_field->rfc2507_params); + } else if (comp_field->rohc_params) { + payload_bytes_len = + encode_pcomp_rohc_params(payload_bytes, + sizeof(payload_bytes), + comp_field->rohc_params); + } else if (comp_field->v42bis_params) { + payload_bytes_len = + encode_dcomp_v42bis_params(payload_bytes, + sizeof(payload_bytes), + comp_field->v42bis_params); + } else if (comp_field->v44_params) { + payload_bytes_len = + encode_dcomp_v44_params(payload_bytes, + sizeof(payload_bytes), + comp_field->v44_params); + } else + OSMO_ASSERT(false); + + /* Bail immediately if payload byte generation failed */ + OSMO_ASSERT(payload_bytes_len >= 0); + + /* Bail if comp_len is out of bounds */ + OSMO_ASSERT(comp_field->comp_len <= sizeof(comp_field->comp)); + + /* Calculate length field of the data block */ + if (comp_field->p) { + len = + payload_bytes_len + + ceil((double)(comp_field->comp_len) / 2.0); + expected_length = len + 3; + } else { + len = payload_bytes_len; + expected_length = len + 2; + } + + /* Bail immediately if no sufficient memory space is supplied */ + OSMO_ASSERT(dst_maxlen >= expected_length); + + /* Check if the entity number is within bounds */ + OSMO_ASSERT(comp_field->entity <= 0x1f); + + /* Check if the algorithm number is within bounds */ + OSMO_ASSERT(comp_field->algo >= 0 || comp_field->algo <= 0x1f); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode Propose bit */ + if (comp_field->p) + *dst |= (1 << 7); + + /* Encode entity number */ + *dst |= comp_field->entity & 0x1F; + dst++; + dst_counter++; + + /* Encode algorithm number */ + if (comp_field->p) { + *dst |= comp_field->algo & 0x1F; + dst++; + dst_counter++; + } + + /* Encode length field */ + *dst |= len & 0xFF; + dst++; + dst_counter++; + + /* Encode PCOMP/DCOMP values */ + if (comp_field->p) { + for (i = 0; i < comp_field->comp_len; i++) { + /* Check if submitted PCOMP/DCOMP + values are within bounds */ + if ((comp_field->comp[i] < 0) + || (comp_field->comp[i] > 0x0F)) + return -EINVAL; + + if (i & 1) { + *dst |= comp_field->comp[i] & 0x0F; + dst++; + dst_counter++; + } else + *dst |= (comp_field->comp[i] << 4) & 0xF0; + } + + if (i & 1) { + dst++; + dst_counter++; + } + } + + /* Append payload bytes */ + memcpy(dst, payload_bytes, payload_bytes_len); + dst_counter += payload_bytes_len; + + /* Return generated length */ + return dst_counter; +} + +/* Find out to which compression class the specified comp-field belongs + * (header compression or data compression?) */ +int gprs_sndcp_get_compression_class(const struct gprs_sndcp_comp_field + *comp_field) +{ + OSMO_ASSERT(comp_field); + + if (comp_field->rfc1144_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->rfc2507_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->rohc_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->v42bis_params) + return SNDCP_XID_DATA_COMPRESSION; + else if (comp_field->v44_params) + return SNDCP_XID_DATA_COMPRESSION; + else + return -EINVAL; +} + +/* Convert all compression fields to bytstreams */ +static int gprs_sndcp_pack_fields(const struct llist_head *comp_fields, + uint8_t *dst, + unsigned int dst_maxlen, int class) +{ + struct gprs_sndcp_comp_field *comp_field; + int byte_counter = 0; + int rc; + + OSMO_ASSERT(comp_fields); + OSMO_ASSERT(dst); + + llist_for_each_entry_reverse(comp_field, comp_fields, list) { + if (class == gprs_sndcp_get_compression_class(comp_field)) { + rc = encode_comp_field(dst + byte_counter, + dst_maxlen - byte_counter, + comp_field); + + /* When input data is correct, there is + * no reason for the encoder to fail! */ + OSMO_ASSERT(rc >= 0); + + byte_counter += rc; + } + } + + /* Return generated length */ + return byte_counter; +} + +/* Transform a list with compression fields into an SNDCP-XID message (dst) */ +int gprs_sndcp_compile_xid(uint8_t *dst, unsigned int dst_maxlen, + const struct llist_head *comp_fields) +{ + int rc; + int byte_counter = 0; + uint8_t comp_bytes[512]; + uint8_t xid_version_number[1] = { CURRENT_SNDCP_VERSION }; + + OSMO_ASSERT(comp_fields); + OSMO_ASSERT(dst); + + /* Exit immediately if no sufficient memory space is supplied */ + OSMO_ASSERT(dst_maxlen >= 2 + sizeof(xid_version_number)); + + /* Prepend header */ + dst = + tlv_put(dst, SNDCP_XID_VERSION_NUMBER, + sizeof(xid_version_number), xid_version_number); + byte_counter += (sizeof(xid_version_number) + 2); + + /* Add data compression fields */ + rc = gprs_sndcp_pack_fields(comp_fields, comp_bytes, + sizeof(comp_bytes), + SNDCP_XID_DATA_COMPRESSION); + OSMO_ASSERT(rc >= 0); + + if (rc > 0) { + dst = tlv_put(dst, SNDCP_XID_DATA_COMPRESSION, rc, comp_bytes); + byte_counter += rc + 2; + } + + /* Add header compression fields */ + rc = gprs_sndcp_pack_fields(comp_fields, comp_bytes, + sizeof(comp_bytes), + SNDCP_XID_PROTOCOL_COMPRESSION); + OSMO_ASSERT(rc >= 0); + + if (rc > 0) { + dst = tlv_put(dst, SNDCP_XID_PROTOCOL_COMPRESSION, rc, + comp_bytes); + byte_counter += rc + 2; + } + + /* Return generated length */ + return byte_counter; +} + +/* FUNCTIONS RELATED TO SNDCP-XID DECODING */ + +/* Decode applicable sapis (works the same in all three compression schemes) */ +static int decode_pcomp_applicable_sapis(unsigned int *nsapis, + unsigned int *nsapis_len, + const uint8_t *src, + unsigned int src_len) +{ + uint16_t blob; + int i; + int nsapi_len = 0; + + OSMO_ASSERT(src); + + /* Exit immediately if no result can be stored */ + if (!nsapis) + return -EINVAL; + + /* Exit immediately if not enough input data is available */ + if (src_len < 2) + return -EINVAL; + + /* Read bitmask */ + blob = *src; + blob = (blob << 8) & 0xFF00; + src++; + blob |= (*src) & 0xFF; + blob = (blob >> 5); + + /* Decode applicable SAPIs */ + for (i = 0; i < 15; i++) { + if ((blob >> i) & 1) { + nsapis[nsapi_len] = i + 5; + nsapi_len++; + } + } + + /* Return consumed length */ + *nsapis_len = nsapi_len; + return 2; +} + +/* Decode 16 bit field */ +static int decode_pcomp_16_bit_field(int *value_int, uint16_t * value_uint16, + const uint8_t *src, + unsigned int src_len, + int value_min, int value_max) +{ + uint16_t blob; + + OSMO_ASSERT(src); + + /* Reset values to zero (just to be sure) */ + if (value_int) + *value_int = -1; + if (value_uint16) + *value_uint16 = 0; + + /* Exit if not enough src are available */ + if (src_len < 2) + return -EINVAL; + + /* Decode bit value */ + blob = *src; + blob = (blob << 8) & 0xFF00; + src++; + blob |= *src; + + /* Check if parsed value is within bounds */ + if (blob < value_min) + return -EINVAL; + if (blob > value_max) + return -EINVAL; + + /* Hand back results to the caller */ + if (value_int) + *value_int = blob; + if (value_uint16) + *value_uint16 = blob; + + /* Return consumed length */ + return 2; +} + +/* Decode 8 bit field */ +static int decode_pcomp_8_bit_field(int *value_int, uint8_t *value_uint8, + const uint8_t *src, + unsigned int src_len, + int value_min, int value_max) +{ + uint8_t blob; + + OSMO_ASSERT(src); + + /* Reset values to invalid (just to be sure) */ + if (value_int) + *value_int = -1; + if (value_uint8) + *value_uint8 = 0; + + /* Exit if not enough src are available */ + if (src_len < 1) + return -EINVAL; + + /* Decode bit value */ + blob = *src; + + /* Check if parsed value is within bounds */ + if (blob < value_min) + return -EINVAL; + if (blob > value_max) + return -EINVAL; + + /* Hand back results to the caller */ + if (value_int) + *value_int = blob; + if (value_uint8) + *value_uint8 = blob; + + /* Return consumed length */ + return 1; +} + +/* Decode rfc1144 parameter field see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */ +static int decode_pcomp_rfc1144_params(struct gprs_sndcp_pcomp_rfc1144_params + *params, const uint8_t *src, + unsigned int src_len) +{ + int rc; + int byte_counter = 0; + + OSMO_ASSERT(params); + OSMO_ASSERT(src); + + /* Mark all optional parameters invalid by default */ + params->s01 = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode parameter S0 -1 + * (see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */ + rc = decode_pcomp_8_bit_field(¶ms->s01, NULL, src, + src_len - byte_counter, 0, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Decode rfc2507 parameter field + * (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ +static int decode_pcomp_rfc2507_params(struct gprs_sndcp_pcomp_rfc2507_params + *params, const uint8_t *src, + unsigned int src_len) +{ + int rc; + int byte_counter = 0; + + OSMO_ASSERT(params); + OSMO_ASSERT(src); + + /* Mark all optional parameters invalid by default */ + params->f_max_period = -1; + params->f_max_time = -1; + params->max_header = -1; + params->tcp_space = -1; + params->non_tcp_space = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode F_MAX_PERIOD (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_16_bit_field(¶ms->f_max_period, NULL, src, + src_len - byte_counter, 1, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode F_MAX_TIME (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_8_bit_field(¶ms->f_max_time, NULL, src, + src_len - byte_counter, 1, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_8_bit_field(¶ms->max_header, NULL, src, + src_len - byte_counter, 60, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_8_bit_field(¶ms->tcp_space, NULL, src, + src_len - byte_counter, 3, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode NON_TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_16_bit_field(¶ms->non_tcp_space, NULL, src, + src_len - byte_counter, 3, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Decode ROHC parameter field (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ +static int decode_pcomp_rohc_params(struct gprs_sndcp_pcomp_rohc_params *params, + const uint8_t *src, unsigned int src_len) +{ + int rc; + int byte_counter = 0; + int i; + + OSMO_ASSERT(params); + OSMO_ASSERT(src); + + /* Mark all optional parameters invalid by default */ + params->max_cid = -1; + params->max_header = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_CID (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + rc = decode_pcomp_16_bit_field(¶ms->max_cid, NULL, src, + src_len - byte_counter, 0, 16383); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + rc = decode_pcomp_16_bit_field(¶ms->max_header, NULL, src, + src_len - byte_counter, 60, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode Profiles (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + for (i = 0; i < 16; i++) { + params->profile_len = 0; + rc = decode_pcomp_16_bit_field(NULL, ¶ms->profile[i], src, + src_len - byte_counter, 0, + 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + params->profile_len = i + 1; + } + + /* Return consumed length */ + return byte_counter; +} + +/* Decode V.42bis parameter field + * (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ +static int decode_dcomp_v42bis_params(struct gprs_sndcp_dcomp_v42bis_params + *params, const uint8_t *src, + unsigned int src_len) +{ + int rc; + int byte_counter = 0; + + OSMO_ASSERT(params); + OSMO_ASSERT(src); + + /* Mark all optional parameters invalid by default */ + params->p0 = -1; + params->p1 = -1; + params->p2 = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode P0 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + rc = decode_pcomp_8_bit_field(¶ms->p0, NULL, src, + src_len - byte_counter, 0, 3); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + rc = decode_pcomp_16_bit_field(¶ms->p1, NULL, src, + src_len - byte_counter, 512, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P2 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + rc = decode_pcomp_8_bit_field(¶ms->p2, NULL, src, + src_len - byte_counter, 6, 250); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Decode V44 parameter field (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ +static int decode_dcomp_v44_params(struct gprs_sndcp_dcomp_v44_params *params, + const uint8_t *src, unsigned int src_len) +{ + int rc; + int byte_counter = 0; + + OSMO_ASSERT(params); + OSMO_ASSERT(src); + + /* Mark all optional parameters invalid by default */ + params->c0 = -1; + params->p0 = -1; + params->p1t = -1; + params->p1r = -1; + params->p3t = -1; + params->p3r = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode C0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_8_bit_field(¶ms->c0, NULL, src, + src_len - byte_counter, 0, 255); + if (rc <= 0) + return byte_counter; + if ((params->c0 != 0x80) && (params->c0 != 0xC0)) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Decode P0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_8_bit_field(¶ms->p0, NULL, src, + src_len - byte_counter, 0, 3); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_16_bit_field(¶ms->p1t, NULL, src, + src_len - byte_counter, 265, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_16_bit_field(¶ms->p1r, NULL, src, + src_len - byte_counter, 265, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P3T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_16_bit_field(¶ms->p3t, NULL, src, + src_len - byte_counter, 265, 65535); + if (rc <= 0) + return byte_counter; + if (params->p3t < 2 * params->p1t) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Decode P3R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_16_bit_field(¶ms->p3r, NULL, src, + src_len - byte_counter, 265, 65535); + if (rc <= 0) + return byte_counter; + if (params->p3r < 2 * params->p1r) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Lookup algorithm identfier by entity ID */ +static int lookup_algorithm_identifier(int entity, const struct + entity_algo_table + *lt, unsigned int lt_len, int compclass) +{ + int i; + + if (!lt) + return -1; + + for (i = 0; i < lt_len; i++) { + if ((lt[i].entity == entity) + && (lt[i].compclass == compclass)) + return lt[i].algo; + } + + return -1; +} + +/* Helper function for decode_comp_field(), decodes + * numeric pcomp/dcomp values */ +static int decode_comp_values(struct gprs_sndcp_comp_field *comp_field, + const uint8_t *src, int compclass) +{ + int src_counter = 0; + int i; + + OSMO_ASSERT(comp_field); + OSMO_ASSERT(src); + + if (comp_field->p) { + /* Determine the number of expected PCOMP/DCOMP values */ + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + /* For protocol compression */ + switch (comp_field->algo) { + case RFC_1144: + comp_field->comp_len = RFC1144_PCOMP_NUM; + break; + case RFC_2507: + comp_field->comp_len = RFC2507_PCOMP_NUM; + break; + case ROHC: + comp_field->comp_len = ROHC_PCOMP_NUM; + break; + + /* Exit if the algorithem type encodes + something unknown / unspecified */ + default: + return -EINVAL; + } + } else { + /* For data compression */ + switch (comp_field->algo) { + case V42BIS: + comp_field->comp_len = V42BIS_DCOMP_NUM; + break; + case V44: + comp_field->comp_len = V44_DCOMP_NUM; + break; + + /* Exit if the algorithem type encodes + something unknown / unspecified */ + default: + return -EINVAL; + } + } + + for (i = 0; i < comp_field->comp_len; i++) { + if (i & 1) { + comp_field->comp[i] = (*src) & 0x0F; + src++; + src_counter++; + } else + comp_field->comp[i] = ((*src) >> 4) & 0x0F; + } + + if (i & 1) { + src++; + src_counter++; + } + } + + return src_counter; +} + +/* Helper function for decode_comp_field(), decodes the parameters + * which are protocol compression specific */ +static int decode_pcomp_params(struct gprs_sndcp_comp_field *comp_field, + const uint8_t *src, int src_len) +{ + int rc; + + OSMO_ASSERT(comp_field); + OSMO_ASSERT(src); + + switch (comp_field->algo) { + case RFC_1144: + comp_field->rfc1144_params = talloc_zero(comp_field, struct + gprs_sndcp_pcomp_rfc1144_params); + rc = decode_pcomp_rfc1144_params(comp_field->rfc1144_params, + src, src_len); + if (rc < 0) + talloc_free(comp_field->rfc1144_params); + break; + case RFC_2507: + comp_field->rfc2507_params = talloc_zero(comp_field, struct + gprs_sndcp_pcomp_rfc2507_params); + rc = decode_pcomp_rfc2507_params(comp_field->rfc2507_params, + src, src_len); + if (rc < 0) + talloc_free(comp_field->rfc1144_params); + break; + case ROHC: + comp_field->rohc_params = talloc_zero(comp_field, struct + gprs_sndcp_pcomp_rohc_params); + rc = decode_pcomp_rohc_params(comp_field->rohc_params, src, + src_len); + if (rc < 0) + talloc_free(comp_field->rohc_params); + break; + + /* If no suitable decoder is detected, + leave the remaining bytes undecoded */ + default: + rc = src_len; + } + + if (rc < 0) { + comp_field->rfc1144_params = NULL; + comp_field->rfc2507_params = NULL; + comp_field->rohc_params = NULL; + } + + return rc; +} + +/* Helper function for decode_comp_field(), decodes the parameters + * which are data compression specific */ +static int decode_dcomp_params(struct gprs_sndcp_comp_field *comp_field, + const uint8_t *src, int src_len) +{ + int rc; + + OSMO_ASSERT(comp_field); + OSMO_ASSERT(src); + + switch (comp_field->algo) { + case V42BIS: + comp_field->v42bis_params = talloc_zero(comp_field, struct + gprs_sndcp_dcomp_v42bis_params); + rc = decode_dcomp_v42bis_params(comp_field->v42bis_params, src, + src_len); + if (rc < 0) + talloc_free(comp_field->v42bis_params); + break; + case V44: + comp_field->v44_params = talloc_zero(comp_field, struct + gprs_sndcp_dcomp_v44_params); + rc = decode_dcomp_v44_params(comp_field->v44_params, src, + src_len); + if (rc < 0) + talloc_free(comp_field->v44_params); + break; + + /* If no suitable decoder is detected, + * leave the remaining bytes undecoded */ + default: + rc = src_len; + } + + if (rc < 0) { + comp_field->v42bis_params = NULL; + comp_field->v44_params = NULL; + } + + return rc; +} + +/* Decode data or protocol control information compression field + * (see also: 3GPP TS 44.065, 6.6.1.1, Figure 9 and + * 3GPP TS 44.065, 6.5.1.1, Figure 7) */ +static int decode_comp_field(struct gprs_sndcp_comp_field *comp_field, + const uint8_t *src, unsigned int src_len, + const struct entity_algo_table *lt, + unsigned int lt_len, int compclass) +{ + int src_counter = 0; + unsigned int len; + int rc; + + OSMO_ASSERT(comp_field); + + /* Exit immediately if it is clear that no + parseable data is present */ + if (src_len < 1 || !src) + return -EINVAL; + + /* Zero out target struct */ + memset(comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + + /* Decode Propose bit and Entity number */ + if ((*src) & 0x80) + comp_field->p = 1; + comp_field->entity = (*src) & 0x1F; + src_counter++; + src++; + + /* Decode algorithm number (if present) */ + if (comp_field->p) { + comp_field->algo = (*src) & 0x1F; + src_counter++; + src++; + } + /* Alternatively take the information from the lookup table */ + else + comp_field->algo = + lookup_algorithm_identifier(comp_field->entity, lt, + lt_len, compclass); + + /* Decode length field */ + len = *src; + src_counter++; + src++; + + /* Decode PCOMP/DCOMP values */ + rc = decode_comp_values(comp_field, src, compclass); + if (rc < 0) + return -EINVAL; + src_counter += rc; + src += rc; + len -= rc; + + /* Decode algorithm specific payload data */ + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + rc = decode_pcomp_params(comp_field, src, len); + else if (compclass == SNDCP_XID_DATA_COMPRESSION) + rc = decode_dcomp_params(comp_field, src, len); + else + return -EINVAL; + + if (rc >= 0) + src_counter += rc; + else + return -EINVAL; + + /* Return consumed length */ + return src_counter; +} + +/* Helper function for gprs_sndcp_decode_xid() to decode XID blocks */ +static int decode_xid_block(struct llist_head *comp_fields, uint8_t tag, + uint16_t tag_len, const uint8_t *val, + const struct entity_algo_table *lt, + unsigned int lt_len) +{ + struct gprs_sndcp_comp_field *comp_field; + int byte_counter = 0; + int comp_field_count = 0; + int rc; + + OSMO_ASSERT(comp_fields); + OSMO_ASSERT(val); + + byte_counter = 0; + do { + /* Bail if more than the maximum number of + comp_fields is generated */ + if (comp_field_count > MAX_ENTITIES * 2) { + return -EINVAL; + } + + /* Parse and add comp_field */ + comp_field = + talloc_zero(comp_fields, struct gprs_sndcp_comp_field); + + rc = decode_comp_field(comp_field, val + byte_counter, + tag_len - byte_counter, lt, lt_len, tag); + + if (rc < 0) { + talloc_free(comp_field); + return -EINVAL; + } + + byte_counter += rc; + llist_add(&comp_field->list, comp_fields); + comp_field_count++; + } + while (tag_len - byte_counter > 0); + + return byte_counter; +} + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +static int gprs_sndcp_decode_xid(struct llist_head *comp_fields, + const uint8_t *src, unsigned int src_len, + const struct + entity_algo_table + *lt, unsigned int lt_len) +{ + int src_pos = 0; + uint8_t tag; + uint16_t tag_len; + const uint8_t *val; + int byte_counter = 0; + int rc; + int tlv_count = 0; + + OSMO_ASSERT(comp_fields); + OSMO_ASSERT(src); + + /* Valid TLV-Tag and types */ + static const struct tlv_definition sndcp_xid_def = { + .def = { + [SNDCP_XID_VERSION_NUMBER] = {TLV_TYPE_TLV,}, + [SNDCP_XID_DATA_COMPRESSION] = {TLV_TYPE_TLV,}, + [SNDCP_XID_PROTOCOL_COMPRESSION] = {TLV_TYPE_TLV,}, + }, + }; + + /* Parse TLV-Encoded SNDCP-XID message and defer payload + to the apporpiate sub-parser functions */ + while (1) { + + /* Bail if an the maximum number of TLV fields + * have been parsed */ + if (tlv_count >= 3) { + gprs_sndcp_free_comp_fields(comp_fields); + return -EINVAL; + } + + /* Parse TLV field */ + rc = tlv_parse_one(&tag, &tag_len, &val, &sndcp_xid_def, + src + src_pos, src_len - src_pos); + if (rc > 0) + src_pos += rc; + else { + gprs_sndcp_free_comp_fields(comp_fields); + return -EINVAL; + } + + /* Decode compression parameters */ + if ((tag == SNDCP_XID_PROTOCOL_COMPRESSION) + || (tag == SNDCP_XID_DATA_COMPRESSION)) { + rc = decode_xid_block(comp_fields, tag, tag_len, val, + lt, lt_len); + + if (rc < 0) { + gprs_sndcp_free_comp_fields(comp_fields); + return -EINVAL; + } else + byte_counter += rc; + } + + /* Stop when no further TLV elements can be expected */ + if (src_len - src_pos <= 2) + break; + + tlv_count++; + } + + return 0; +} + +/* Fill up lookutable from a list with comression entitiy fields */ +static int gprs_sndcp_fill_table(struct + entity_algo_table *lt, + unsigned int lt_len, + const struct llist_head *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field; + int i = 0; + + OSMO_ASSERT(lt); + OSMO_ASSERT(comp_fields); + + if (!comp_fields) + return -EINVAL; + if (!lt) + return -EINVAL; + + memset(lt, 0, lt_len * sizeof(lt)); + + llist_for_each_entry(comp_field, comp_fields, list) { + + lt[i].entity = comp_field->entity; + lt[i].algo = comp_field->algo; + lt[i].compclass = gprs_sndcp_get_compression_class(comp_field); + + if (lt[i].compclass < 0) { + memset(lt, 0, lt_len * sizeof(lt)); + return -EINVAL; + } + + i++; + } + + return i; +} + +/* Complete comp field params + * (if a param (dst) is not valid, it will be copied from source (src) */ +static int complete_comp_field_params(struct gprs_sndcp_comp_field + *comp_field_dst, const struct + gprs_sndcp_comp_field *comp_field_src) +{ + OSMO_ASSERT(comp_field_dst); + OSMO_ASSERT(comp_field_src); + + if (comp_field_dst->algo < 0) + return -EINVAL; + + if (comp_field_dst->rfc1144_params && comp_field_src->rfc1144_params) { + if (comp_field_dst->rfc1144_params->s01 < 0) { + comp_field_dst->rfc1144_params->s01 = + comp_field_src->rfc1144_params->s01; + } + return 0; + } + + if (comp_field_dst->rfc2507_params && comp_field_src->rfc2507_params) { + + if (comp_field_dst->rfc2507_params->f_max_period < 0) { + comp_field_dst->rfc2507_params->f_max_period = + comp_field_src->rfc2507_params->f_max_period; + } + if (comp_field_dst->rfc2507_params->f_max_time < 0) { + comp_field_dst->rfc2507_params->f_max_time = + comp_field_src->rfc2507_params->f_max_time; + } + if (comp_field_dst->rfc2507_params->max_header < 0) { + comp_field_dst->rfc2507_params->max_header = + comp_field_src->rfc2507_params->max_header; + } + if (comp_field_dst->rfc2507_params->tcp_space < 0) { + comp_field_dst->rfc2507_params->tcp_space = + comp_field_src->rfc2507_params->tcp_space; + } + if (comp_field_dst->rfc2507_params->non_tcp_space < 0) { + comp_field_dst->rfc2507_params->non_tcp_space = + comp_field_src->rfc2507_params->non_tcp_space; + } + return 0; + } + + if (comp_field_dst->rohc_params && comp_field_src->rohc_params) { + if (comp_field_dst->rohc_params->max_cid < 0) { + comp_field_dst->rohc_params->max_cid = + comp_field_src->rohc_params->max_cid; + } + if (comp_field_dst->rohc_params->max_header < 0) { + comp_field_dst->rohc_params->max_header = + comp_field_src->rohc_params->max_header; + } + if (comp_field_dst->rohc_params->profile_len > 0) { + memcpy(comp_field_dst->rohc_params->profile, + comp_field_src->rohc_params->profile, + sizeof(comp_field_dst->rohc_params->profile)); + comp_field_dst->rohc_params->profile_len = + comp_field_src->rohc_params->profile_len; + } + + return 0; + } + + if (comp_field_dst->v42bis_params && comp_field_src->v42bis_params) { + if (comp_field_dst->v42bis_params->p0 < 0) { + comp_field_dst->v42bis_params->p0 = + comp_field_src->v42bis_params->p0; + } + if (comp_field_dst->v42bis_params->p1 < 0) { + comp_field_dst->v42bis_params->p1 = + comp_field_src->v42bis_params->p1; + } + if (comp_field_dst->v42bis_params->p2 < 0) { + comp_field_dst->v42bis_params->p2 = + comp_field_src->v42bis_params->p2; + } + return 0; + } + + if (comp_field_dst->v44_params && comp_field_src->v44_params) { + if (comp_field_dst->v44_params->c0 < 0) { + comp_field_dst->v44_params->c0 = + comp_field_src->v44_params->c0; + } + if (comp_field_dst->v44_params->p0 < 0) { + comp_field_dst->v44_params->p0 = + comp_field_src->v44_params->p0; + } + if (comp_field_dst->v44_params->p1t < 0) { + comp_field_dst->v44_params->p1t = + comp_field_src->v44_params->p1t; + } + if (comp_field_dst->v44_params->p1r < 0) { + comp_field_dst->v44_params->p1r = + comp_field_src->v44_params->p1r; + } + if (comp_field_dst->v44_params->p3t < 0) { + comp_field_dst->v44_params->p3t = + comp_field_src->v44_params->p3t; + } + if (comp_field_dst->v44_params->p3r < 0) { + comp_field_dst->v44_params->p3r = + comp_field_src->v44_params->p3r; + } + return 0; + } + + /* There should be at least exist one param set + * in the destination struct, otherwise something + * must be wrong! */ + return -EINVAL; +} + +/* Complete missing parameters in a comp_field */ +static int gprs_sndcp_complete_comp_field(struct gprs_sndcp_comp_field + *comp_field, const struct llist_head + *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field_src; + int rc = 0; + + OSMO_ASSERT(comp_field); + OSMO_ASSERT(comp_fields); + + llist_for_each_entry(comp_field_src, comp_fields, list) { + if (comp_field_src->entity == comp_field->entity) { + + /* Complete header fields */ + if (comp_field_src->comp_len > 0) { + memcpy(comp_field->comp, + comp_field_src->comp, + sizeof(comp_field_src->comp)); + comp_field->comp_len = comp_field_src->comp_len; + } + + /* Complete parameter fields */ + rc = complete_comp_field_params(comp_field, + comp_field_src); + } + } + + return rc; +} + +/* Complete missing parameters of all comp_field in a list */ +static int gprs_sndcp_complete_comp_fields(struct llist_head + *comp_fields_incomplete, + const struct llist_head *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field_incomplete; + int rc; + + OSMO_ASSERT(comp_fields_incomplete); + OSMO_ASSERT(comp_fields); + + llist_for_each_entry(comp_field_incomplete, comp_fields_incomplete, + list) { + + rc = gprs_sndcp_complete_comp_field(comp_field_incomplete, + comp_fields); + if (rc < 0) + return -EINVAL; + + } + + return 0; +} + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +struct llist_head *gprs_sndcp_parse_xid(const void *ctx, + const uint8_t *src, + unsigned int src_len, + const struct llist_head + *comp_fields_req) +{ + int rc; + int lt_len; + struct llist_head *comp_fields; + struct entity_algo_table lt[MAX_ENTITIES * 2]; + + OSMO_ASSERT(src); + + comp_fields = talloc_zero(ctx, struct llist_head); + INIT_LLIST_HEAD(comp_fields); + + if (comp_fields_req) { + /* Generate lookup table */ + lt_len = + gprs_sndcp_fill_table(lt, MAX_ENTITIES * 2, + comp_fields_req); + if (lt_len < 0) + return NULL; + + /* Parse SNDCP-CID XID-Field */ + rc = gprs_sndcp_decode_xid(comp_fields, src, src_len, lt, + lt_len); + if (rc < 0) + return NULL; + + rc = gprs_sndcp_complete_comp_fields(comp_fields, + comp_fields_req); + if (rc < 0) + return NULL; + + } else { + /* Parse SNDCP-CID XID-Field */ + rc = gprs_sndcp_decode_xid(comp_fields, src, src_len, NULL, 0); + if (rc < 0) + return NULL; + } + + return comp_fields; +} + +/* Free a list with SNDCP-XID fields */ +struct llist_head *gprs_sndcp_free_comp_fields(struct llist_head *comp_fields) +{ + if (comp_fields != NULL) + talloc_free(comp_fields); + return NULL; +} + +/* Helper for gprs_sndcp_dump_comp_fields(), + * dumps protocol compression parameters */ +static void dump_pcomp_params(const struct gprs_sndcp_comp_field + *comp_field, unsigned int logl) +{ + int i; + + OSMO_ASSERT(comp_field); + + switch (comp_field->algo) { + case RFC_1144: + if (comp_field->rfc1144_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_pcomp_rfc1144_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_pcomp_rfc1144_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%i;\n", + comp_field->rfc1144_params->nsapi_len); + if (comp_field->rfc1144_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rfc1144_params->nsapi_len; i++) { + LOGP(DSNDCP, logl, + " nsapi[%i]=%i;\n", i, + comp_field->rfc1144_params->nsapi[i]); + } + LOGP(DSNDCP, logl, " s01=%i;\n", + comp_field->rfc1144_params->s01); + LOGP(DSNDCP, logl, " }\n"); + break; + case RFC_2507: + if (comp_field->rfc2507_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_pcomp_rfc2507_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_pcomp_rfc2507_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%i;\n", + comp_field->rfc2507_params->nsapi_len); + if (comp_field->rfc2507_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rfc2507_params->nsapi_len; i++) { + LOGP(DSNDCP, logl, + " nsapi[%i]=%i;\n", i, + comp_field->rfc2507_params->nsapi[i]); + } + LOGP(DSNDCP, logl, + " f_max_period=%i;\n", + comp_field->rfc2507_params->f_max_period); + LOGP(DSNDCP, logl, + " f_max_time=%i;\n", + comp_field->rfc2507_params->f_max_time); + LOGP(DSNDCP, logl, + " max_header=%i;\n", + comp_field->rfc2507_params->max_header); + LOGP(DSNDCP, logl, + " tcp_space=%i;\n", + comp_field->rfc2507_params->tcp_space); + LOGP(DSNDCP, logl, + " non_tcp_space=%i;\n", + comp_field->rfc2507_params->non_tcp_space); + LOGP(DSNDCP, logl, " }\n"); + break; + case ROHC: + if (comp_field->rohc_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_pcomp_rohc_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_pcomp_rohc_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%i;\n", + comp_field->rohc_params->nsapi_len); + if (comp_field->rohc_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rohc_params->nsapi_len; i++) { + LOGP(DSNDCP, logl, + " nsapi[%i]=%i;\n", i, + comp_field->rohc_params->nsapi[i]); + } + LOGP(DSNDCP, logl, + " max_cid=%i;\n", comp_field->rohc_params->max_cid); + LOGP(DSNDCP, logl, + " max_header=%i;\n", + comp_field->rohc_params->max_header); + LOGP(DSNDCP, logl, + " profile_len=%i;\n", + comp_field->rohc_params->profile_len); + if (comp_field->rohc_params->profile_len == 0) + LOGP(DSNDCP, logl, " profile[] = NULL;\n"); + for (i = 0; i < comp_field->rohc_params->profile_len; i++) + LOGP(DSNDCP, logl, + " profile[%i]=%04x;\n", + i, comp_field->rohc_params->profile[i]); + LOGP(DSNDCP, logl, " }\n"); + break; + } + +} + +/* Helper for gprs_sndcp_dump_comp_fields(), + * data protocol compression parameters */ +static void dump_dcomp_params(const struct gprs_sndcp_comp_field + *comp_field, unsigned int logl) +{ + int i; + + OSMO_ASSERT(comp_field); + + switch (comp_field->algo) { + case V42BIS: + if (comp_field->v42bis_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_dcomp_v42bis_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_dcomp_v42bis_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%i;\n", + comp_field->v42bis_params->nsapi_len); + if (comp_field->v42bis_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->v42bis_params->nsapi_len; i++) + LOGP(DSNDCP, logl, + " nsapi[%i]=%i;\n", i, + comp_field->v42bis_params->nsapi[i]); + LOGP(DSNDCP, logl, " p0=%i;\n", + comp_field->v42bis_params->p0); + LOGP(DSNDCP, logl, " p1=%i;\n", + comp_field->v42bis_params->p1); + LOGP(DSNDCP, logl, " p2=%i;\n", + comp_field->v42bis_params->p2); + LOGP(DSNDCP, logl, " }\n"); + break; + case V44: + if (comp_field->v44_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_dcomp_v44_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_dcomp_v44_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%i;\n", + comp_field->v44_params->nsapi_len); + if (comp_field->v44_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->v44_params->nsapi_len; i++) { + LOGP(DSNDCP, logl, + " nsapi[%i]=%i;\n", i, + comp_field->v44_params->nsapi[i]); + } + LOGP(DSNDCP, logl, " c0=%i;\n", + comp_field->v44_params->c0); + LOGP(DSNDCP, logl, " p0=%i;\n", + comp_field->v44_params->p0); + LOGP(DSNDCP, logl, " p1t=%i;\n", + comp_field->v44_params->p1t); + LOGP(DSNDCP, logl, " p1r=%i;\n", + comp_field->v44_params->p1r); + LOGP(DSNDCP, logl, " p3t=%i;\n", + comp_field->v44_params->p3t); + LOGP(DSNDCP, logl, " p3r=%i;\n", + comp_field->v44_params->p3r); + LOGP(DSNDCP, logl, " }\n"); + break; + } +} + +/* Dump a list with SNDCP-XID fields (Debug) */ +void gprs_sndcp_dump_comp_fields(const struct llist_head *comp_fields, + unsigned int logl) +{ + struct gprs_sndcp_comp_field *comp_field; + int i; + int compclass; + + OSMO_ASSERT(comp_fields); + + llist_for_each_entry(comp_field, comp_fields, list) { + LOGP(DSNDCP, logl, "SNDCP-XID:\n"); + LOGP(DSNDCP, logl, "struct gprs_sndcp_comp_field {\n"); + LOGP(DSNDCP, logl, " entity=%i;\n", comp_field->entity); + LOGP(DSNDCP, logl, " algo=%i;\n", comp_field->algo); + LOGP(DSNDCP, logl, " comp_len=%i;\n", comp_field->comp_len); + if (comp_field->comp_len == 0) + LOGP(DSNDCP, logl, " comp[] = NULL;\n"); + for (i = 0; i < comp_field->comp_len; i++) { + LOGP(DSNDCP, logl, " comp[%i]=%i;\n", i, + comp_field->comp[i]); + } + + compclass = gprs_sndcp_get_compression_class(comp_field); + + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + dump_pcomp_params(comp_field, logl); + } else if (compclass == SNDCP_XID_DATA_COMPRESSION) { + dump_dcomp_params(comp_field, logl); + } + + LOGP(DSNDCP, logl, "}\n"); + LOGP(DSNDCP, logl, "\n"); + } + +} diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index ba5ca28..071166b 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid xid_sndcp if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 74af159..45d1780 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -31,6 +31,7 @@ $(top_builddir)/src/gprs/oap.o \ $(top_builddir)/src/gprs/oap_messages.o \ $(top_builddir)/src/gprs/gprs_llc_xid.o \ + $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ @@ -38,5 +39,5 @@ $(LIBOSMOGB_LIBS) \ $(LIBCARES_LIBS) \ $(LIBCRYPTO_LIBS) \ - -lgtp -lrt + -lgtp -lrt -lm diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index 6470ab9..22b3db9 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -129,3 +129,10 @@ cat $abs_srcdir/xid/xid_test.ok > expout AT_CHECK([$abs_top_builddir/tests/xid/xid_test], [], [expout], [ignore]) AT_CLEANUP + +AT_SETUP([xid_sndcp]) +AT_KEYWORDS([xid_sndcp]) +cat $abs_srcdir/xid_sndcp/sndcp_xid_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/xid_sndcp/sndcp_xid_test], [], [expout], [ignore]) +AT_CLEANUP + diff --git a/openbsc/tests/xid_sndcp/Makefile.am b/openbsc/tests/xid_sndcp/Makefile.am new file mode 100644 index 0000000..99b9d1a --- /dev/null +++ b/openbsc/tests/xid_sndcp/Makefile.am @@ -0,0 +1,20 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) + +EXTRA_DIST = sndcp_xid_test.ok + +noinst_PROGRAMS = sndcp_xid_test + +sndcp_xid_test_SOURCES = sndcp_xid_test.c + +sndcp_xid_test_LDADD = \ + $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOGB_LIBS) \ + $(LIBCARES_LIBS) \ + $(LIBCRYPTO_LIBS) \ + -lgtp -lrt -lm + + diff --git a/openbsc/tests/xid_sndcp/sndcp_xid_test.c b/openbsc/tests/xid_sndcp/sndcp_xid_test.c new file mode 100644 index 0000000..955d39e --- /dev/null +++ b/openbsc/tests/xid_sndcp/sndcp_xid_test.c @@ -0,0 +1,276 @@ +/* Test SNDCP-XID Encoding/Decoding */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include + +#include +#include + +#include + +#include +#include + +/* Test SNDCP-XID decoding with a real world sample */ +static void test_xid_decode_realworld(const void *ctx) +{ + struct llist_head *comp_fields; + int rc; + printf("Testing SNDCP XID-Decoder/Encoder (real world data)\n"); + + /* Example of a real world SNDCP-XID message */ + uint8_t xid[] = + { 0x00, 0x01, 0x00, 0x02, 0x31, 0x82, 0x02, 0x27, 0x89, 0xff, 0xe0, + 0x00, 0x0f, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, + 0x01, 0x02, 0x00, 0x03, 0x01, 0x03, 0x00, 0x04, 0x01, 0x04, 0x00, 0x05, + 0x01, 0x05, 0x00, 0x06, 0x00, 0x07, 0x01, 0x07, 0x00, 0x08, 0x01, 0x08, + 0x80, 0x00, 0x04, 0x12, 0x00, 0x40, 0x07 }; + uint8_t xid_r[512]; + + /* Parse and show contained comp fields */ + comp_fields = gprs_sndcp_parse_xid(ctx, xid, sizeof(xid), NULL); + OSMO_ASSERT(comp_fields); + printf("Decoded:\n"); + gprs_sndcp_dump_comp_fields(comp_fields, DSNDCP); + + /* Encode comp-fields again */ + rc = gprs_sndcp_compile_xid(xid_r,sizeof(xid_r), comp_fields); + printf("Result length=%i\n",rc); + printf("Encoded: %s\n", osmo_hexdump_nospc(xid, sizeof(xid))); + printf("Rencoded: %s\n", osmo_hexdump_nospc(xid_r, rc)); + + OSMO_ASSERT(rc == 54); + OSMO_ASSERT(memcmp(xid, xid_r, sizeof(xid)) == 0); + + /* Free comp fields */ + gprs_sndcp_free_comp_fields(comp_fields); + + printf("\n"); +} + +/* Encode and decode test with artificial test data */ +static void test_xid_encode_decode(const void *ctx) +{ + printf("Testing SNDCP XID-Encoder/Decoder\n"); + + LLIST_HEAD(comp_fields); + struct gprs_sndcp_pcomp_rfc1144_params rfc1144_params; + struct gprs_sndcp_comp_field rfc1144_comp_field; + struct gprs_sndcp_pcomp_rfc2507_params rfc2507_params; + struct gprs_sndcp_comp_field rfc2507_comp_field; + struct gprs_sndcp_pcomp_rohc_params rohc_params; + struct gprs_sndcp_comp_field rohc_comp_field; + struct gprs_sndcp_dcomp_v42bis_params v42bis_params; + struct gprs_sndcp_comp_field v42bis_comp_field; + struct gprs_sndcp_dcomp_v44_params v44_params; + struct gprs_sndcp_comp_field v44_comp_field; + struct llist_head *comp_fields_dec; + + uint8_t xid[512]; + unsigned int xid_len = sizeof(xid); + int rc; + + memset(&rfc1144_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + memset(&rfc2507_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + memset(&rohc_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + memset(&v42bis_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + memset(&v44_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + + /* Setup which NSAPIs shall make use of rfc1144 */ + rfc1144_params.nsapi[0] = 5; + rfc1144_params.nsapi_len = 1; + + /* Setup rfc1144 operating parameters */ + rfc1144_params.s01 = 7; + + /* Setup rfc1144 compression field */ + rfc1144_comp_field.p = 1; + rfc1144_comp_field.entity = 0; + rfc1144_comp_field.algo = RFC_1144; + rfc1144_comp_field.comp[RFC1144_PCOMP1] = 1; + rfc1144_comp_field.comp[RFC1144_PCOMP2] = 2; + rfc1144_comp_field.comp_len = RFC1144_PCOMP_NUM; + rfc1144_comp_field.rfc1144_params = &rfc1144_params; + + /* Setup which NSAPIs shall make use of rfc1144 */ + rfc2507_params.nsapi[0] = 6; + rfc2507_params.nsapi_len = 1; + + /* Setup rfc2507 operating parameters */ + rfc2507_params.f_max_period = 256; + rfc2507_params.f_max_time = 5; + rfc2507_params.max_header = 168; + rfc2507_params.tcp_space = 15; + rfc2507_params.non_tcp_space = 15; + + /* Setup rfc2507 compression field */ + rfc2507_comp_field.p = 1; + rfc2507_comp_field.entity = 1; + rfc2507_comp_field.algo = RFC_2507; + rfc2507_comp_field.comp[RFC2507_PCOMP1] = 3; + rfc2507_comp_field.comp[RFC2507_PCOMP2] = 4; + rfc2507_comp_field.comp[RFC2507_PCOMP3] = 5; + rfc2507_comp_field.comp[RFC2507_PCOMP4] = 6; + rfc2507_comp_field.comp[RFC2507_PCOMP5] = 7; + rfc2507_comp_field.comp_len = RFC2507_PCOMP_NUM; + rfc2507_comp_field.rfc2507_params = &rfc2507_params; + + /* Setup which NSAPIs shall make use of ROHC */ + rohc_params.nsapi[0] = 5; + rohc_params.nsapi[1] = 6; + rohc_params.nsapi[2] = 7; + rohc_params.nsapi[3] = 8; + rohc_params.nsapi[4] = 9; + rohc_params.nsapi[5] = 10; + rohc_params.nsapi[6] = 11; + rohc_params.nsapi[7] = 12; + rohc_params.nsapi[8] = 13; + rohc_params.nsapi[9] = 14; + rohc_params.nsapi[10] = 15; + rohc_params.nsapi_len = 11; + + /* Setup ROHC operating parameters */ + rohc_params.max_cid = 15; /* default */ + rohc_params.max_header = 168; /* default */ + rohc_params.profile[0] = ROHC_UNCOMPRESSED; + rohc_params.profile[1] = ROHC_RTP; + rohc_params.profile[2] = ROHCV2_RTP; + rohc_params.profile[3] = ROHC_UDP; + rohc_params.profile[4] = ROHCv2_UDP; + rohc_params.profile[5] = ROHC_ESP; + rohc_params.profile[6] = ROHCV2_ESP; + rohc_params.profile[7] = ROHC_IP; + rohc_params.profile[8] = ROHCV2_IP; + rohc_params.profile[9] = ROHC_LLA; + rohc_params.profile[10] = ROHC_LLA_WITH_R_MODE; + rohc_params.profile[11] = ROHC_TCP; + rohc_params.profile[12] = ROHC_RTP_UDP_LITE; + rohc_params.profile[13] = ROHCV2_RTP_UDP_LITE; + rohc_params.profile[14] = ROHC_UDP_LITE; + rohc_params.profile[15] = ROHCV2_UDP_LITE; + rohc_params.profile_len = 16; + + /* Setup ROHC compression field */ + rohc_comp_field.p = 1; + rohc_comp_field.entity = 2; + rohc_comp_field.algo = ROHC; + rohc_comp_field.comp[ROHC_PCOMP1] = 8; + rohc_comp_field.comp[ROHC_PCOMP2] = 9; + rohc_comp_field.comp_len = ROHC_PCOMP_NUM; + rohc_comp_field.rohc_params = &rohc_params; + + /* Setup which NSAPIs shall make use of v42bis */ + v42bis_params.nsapi[0] = 5; + v42bis_params.nsapi_len = 1; + + /* Setup v42bis operating parameters */ + v42bis_params.p0 = 3; + v42bis_params.p1 = 2048; + v42bis_params.p2 = 20; + + /* Setup v42bis compression field */ + v42bis_comp_field.p = 1; + v42bis_comp_field.entity = 3; + v42bis_comp_field.algo = V42BIS; + v42bis_comp_field.comp[V42BIS_DCOMP1] = 10; + v42bis_comp_field.comp_len = V42BIS_DCOMP_NUM; + v42bis_comp_field.v42bis_params = &v42bis_params; + + /* Setup which NSAPIs shall make use of v44 */ + v44_params.nsapi[0] = 5; + v44_params.nsapi_len = 1; + + /* Setup v44 operating parameters */ + v44_params.c0 = 0x80; + v44_params.p0 = 3; + v44_params.p1t = 300; + v44_params.p1r = 300; + v44_params.p3t = 600; + v44_params.p3r = 600; + + /* Setup v44 compression field */ + v44_comp_field.p = 1; + v44_comp_field.entity = 3; + v44_comp_field.algo = V44; + v44_comp_field.comp[V44_DCOMP1] = 10; + v44_comp_field.comp[V44_DCOMP2] = 11; + v44_comp_field.comp_len = V44_DCOMP_NUM; + v44_comp_field.v44_params = &v44_params; + + /* Add compression field(s) to list */ + llist_add(&v44_comp_field.list, &comp_fields); + llist_add(&v42bis_comp_field.list, &comp_fields); + llist_add(&rfc1144_comp_field.list, &comp_fields); + llist_add(&rfc2507_comp_field.list, &comp_fields); + llist_add(&rohc_comp_field.list, &comp_fields); + printf("Test input data:\n"); + gprs_sndcp_dump_comp_fields(&comp_fields, DSNDCP); + + /* Encode SNDCP-XID fields */ + rc = gprs_sndcp_compile_xid(xid, xid_len, &comp_fields); + OSMO_ASSERT(rc > 0); + + printf("Encoded: %s (%i bytes)\n", osmo_hexdump_nospc(xid, rc), rc); + + /* Parse and show contained comp fields */ + comp_fields_dec = gprs_sndcp_parse_xid(ctx, xid, rc, NULL); + OSMO_ASSERT(comp_fields_dec); + + printf("Decoded:\n"); + gprs_sndcp_dump_comp_fields(comp_fields_dec, DSNDCP); + + /* Free comp fields */ + gprs_sndcp_free_comp_fields(comp_fields_dec); +} + +static struct log_info_cat gprs_categories[] = { + [DSNDCP] = { + .name = "DSNDCP", + .description = + "GPRS Sub-Network Dependent Control Protocol (SNDCP)", + .enabled = 1,.loglevel = LOGL_DEBUG, + } +}; + +static struct log_info info = { + .cat = gprs_categories, + .num_cat = ARRAY_SIZE(gprs_categories), +}; + +int main(int argc, char **argv) +{ + void *xid_ctx; + + osmo_init_logging(&info); + + xid_ctx = talloc_named_const(NULL, 0, "xid_ctx"); + + test_xid_decode_realworld(xid_ctx); + test_xid_encode_decode(xid_ctx); + + printf("Done\n"); + + talloc_report_full(xid_ctx, stderr); + OSMO_ASSERT(talloc_total_blocks(xid_ctx) == 1); + return 0; +} diff --git a/openbsc/tests/xid_sndcp/sndcp_xid_test.ok b/openbsc/tests/xid_sndcp/sndcp_xid_test.ok new file mode 100644 index 0000000..f357282 --- /dev/null +++ b/openbsc/tests/xid_sndcp/sndcp_xid_test.ok @@ -0,0 +1,11 @@ +Testing SNDCP XID-Decoder/Encoder (real world data) +Decoded: +Result length=54 +Encoded: 000100023182022789ffe0000f00a8000000010101000201020003010300040104000501050006000701070008010880000412004007 +Rencoded: 000100023182022789ffe0000f00a8000000010101000201020003010300040104000501050006000701070008010880000412004007 + +Testing SNDCP XID-Encoder/Decoder +Test input data: +Encoded: 000100011a83010dab00208003012c012c02580258830007a000200308001402408000041200200781010c3456700040010005a80f000f82022789ffe0000f00a80000000101010002010200030103000401040005010500060007010700080108 (97 bytes) +Decoded: +Done -- To view, visit https://gerrit.osmocom.org/641 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e Gerrit-PatchSet: 7 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Wed Aug 10 15:54:57 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Wed, 10 Aug 2016 15:54:57 +0000 Subject: [PATCH] openbsc[master]: Adding compression control In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/642 to look at the new patch set (#9). Adding compression control In this commit two modules were added: gprs_sndcp_comp.h/c: This part handles the creation and destruction of conpression entites. It handles the allocation and freeing of the memory and offers functions to query compression parameters (i.e. which compression entity should be used if a packet from NSAPI x has to be compressed?) gprs_sndcp_pcomp.c/h: This is the code that performs the actual header compression. It takes care that the packets are compressed/decompressed with the right modes etc. It works, but is not yet ready for merging. Both files depend on each other so that they only can be merged both at the same time. Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 --- M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_sndcp_comp.h A openbsc/include/openbsc/gprs_sndcp_pcomp.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_sndcp_comp.c A openbsc/src/gprs/gprs_sndcp_pcomp.c M openbsc/tests/sgsn/Makefile.am 7 files changed, 756 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/42/642/9 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index f402fea..88a7e2c 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,7 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ - slhc.h + slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_sndcp_comp.h b/openbsc/include/openbsc/gprs_sndcp_comp.h new file mode 100644 index 0000000..e2d79ab --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_comp.h @@ -0,0 +1,85 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_SNDCP_COMP_H +#define _GPRS_SNDCP_COMP_H + +#include +#include +#include + +/* Header / Data compression entity */ +struct gprs_sndcp_comp { + struct llist_head list; + + /* Serves as an ID in case we want to delete this entity later */ + int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + + /* Specifies to which NSAPIs the compression entity is assigned */ + int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + int nsapi[11]; /* Applicable NSAPIs (default 0) */ + + /* Assigned pcomp values */ + int comp_len; /* Number of contained PCOMP / DCOMP values */ + int comp[16]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */ + + /* Algorithm parameters */ + int algo; /* Algorithm type (see gprs_sndcp_xid.h) */ + int compclass; /* See gprs_sndcp_xid.h/c */ + void *state; /* Algorithm status and parameters */ +}; + +/* Free a list with compression entities */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities); + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, int entity); + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_entities_add(const void *ctx, struct + llist_head + *comp_entities, const struct + gprs_sndcp_comp_field + *comp_field); + +/* Find compression entity by its entity number */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_entity(const struct llist_head + *comp_entities, int entity); + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head + *comp_entities, int comp); + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head + *comp_entities, int nsapi); + +/* Find a comp_index for a given pcomp/dcomp value */ +int gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp + *comp_entity, int comp); + +/* Find a pcomp/dcomp value for a given comp_index */ +int gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp + *comp_entity, int comp_index); + +#endif diff --git a/openbsc/include/openbsc/gprs_sndcp_pcomp.h b/openbsc/include/openbsc/gprs_sndcp_pcomp.h new file mode 100644 index 0000000..5dafdbb --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_pcomp.h @@ -0,0 +1,47 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_SNDCP_pcomp_H +#define _GPRS_SNDCP_pcomp_H + +#include +#include +#include + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field); + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity); + +/* Expand header compressed packet */ +int gprs_sndcp_pcomp_expand(uint8_t *packet, int packet_len, int pcomp, + const struct llist_head *comp_entities); + +/* Expand header compressed packet */ +int gprs_sndcp_pcomp_compress(uint8_t *packet, int packet_len, + int *pcomp, + const struct llist_head *comp_entities, + int nsapi); + +#endif diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 245636b..2910c02 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -27,7 +27,7 @@ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ - slhc.c + slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/gprs_sndcp_comp.c b/openbsc/src/gprs/gprs_sndcp_comp.c new file mode 100644 index 0000000..8153fd2 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_comp.c @@ -0,0 +1,320 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +/* Create a new compression entity from a XID-Field */ +static struct gprs_sndcp_comp *gprs_sndcp_comp_create(const void + *ctx, const struct + gprs_sndcp_comp_field + *comp_field) +{ + OSMO_ASSERT(comp_field); + + struct gprs_sndcp_comp *comp_entity; + comp_entity = talloc_zero(ctx, struct gprs_sndcp_comp); + + /* Copy relevant information from the SNDCP-XID field */ + comp_entity->entity = comp_field->entity; + comp_entity->comp_len = comp_field->comp_len; + memcpy(comp_entity->comp, comp_field->comp, + comp_field->comp_len * sizeof(int)); + + if (comp_field->rfc1144_params) { + comp_entity->nsapi_len = comp_field->rfc1144_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc1144_params->nsapi, + comp_entity->nsapi_len * sizeof(int)); + } else if (comp_field->rfc2507_params) { + comp_entity->nsapi_len = comp_field->rfc2507_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc2507_params->nsapi, + comp_entity->nsapi_len * sizeof(int)); + } else if (comp_field->rohc_params) { + comp_entity->nsapi_len = comp_field->rohc_params->nsapi_len; + memcpy(comp_entity->nsapi, comp_field->rohc_params->nsapi, + comp_entity->nsapi_len * sizeof(int)); + } else if (comp_field->v42bis_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + comp_entity->nsapi_len * sizeof(int)); + } else if (comp_field->v44_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + comp_entity->nsapi_len * sizeof(int)); + } else { + talloc_free(comp_entity); + LOGP(DSNDCP, LOGL_ERROR, + "Comp field contained invalid parameters, compression entity not created!\n"); + return NULL; + } + + comp_entity->algo = comp_field->algo; + comp_entity->state = NULL; + + /* Determine of which class our compression entity will be + * (Protocol or Data compresson ?) */ + comp_entity->compclass = gprs_sndcp_get_compression_class(comp_field); + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + if (gprs_sndcp_pcomp_init(ctx, comp_entity, comp_field) == 0) + LOGP(DSNDCP, LOGL_INFO, + "New header compression entity (%i) created.\n", + comp_entity->entity); + else { + talloc_free(comp_entity); + LOGP(DSNDCP, LOGL_ERROR, + "Header compression entity (%i) creation failed!\n", + comp_entity->entity); + return NULL; + } + } else { + LOGP(DSNDCP, LOGL_INFO, + "New data compression entity (%i) created.\n", + comp_entity->entity); + } + + return comp_entity; +} + +/* Free a list with compression entities */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities) +{ + struct llist_head *ce, *ce2; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + /* Free compression entity */ + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %i ...\n", + comp_entity->entity); + gprs_sndcp_pcomp_term(comp_entity); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %i ...\n", + comp_entity->entity); + } + } + + llist_for_each_safe(ce, ce2, comp_entities) { + llist_del(ce); + talloc_free(ce); + } + +} + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, int entity) +{ + struct gprs_sndcp_comp *comp_entity; + struct gprs_sndcp_comp *comp_entity_to_delete = NULL; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) + comp_entity_to_delete = comp_entity; + } + + if (comp_entity_to_delete) { + if (comp_entity_to_delete->compclass == + SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %i ...\n", + comp_entity_to_delete->entity); + gprs_sndcp_pcomp_term(comp_entity_to_delete); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %i ...\n", + comp_entity_to_delete->entity); + } + + /* Delete compression entity */ + llist_del(&comp_entity_to_delete->list); + talloc_free(comp_entity_to_delete); + } + +} + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_entities_add(const void *ctx, struct + llist_head + *comp_entities, const struct + gprs_sndcp_comp_field + *comp_field) +{ + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(comp_entities); + OSMO_ASSERT(comp_field); + + /* Just to be sure, if the entity is already in + * the list it will be deleted now */ + gprs_sndcp_comp_delete(comp_entities, comp_field->entity); + + /* Create and add a new entity to the list */ + comp_entity = gprs_sndcp_comp_create(ctx, comp_field); + + if (comp_entity) { + llist_add(&comp_entity->list, comp_entities); + return comp_entity; + } + + return NULL; +} + +/* Find compression entity by its entity number */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_entity(const struct + llist_head + *comp_entities, int entity) +{ + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) + return comp_entity; + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given entity number %i.\n", + entity); + return NULL; +} + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct + llist_head + *comp_entities, int comp) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return comp_entity; + } + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given pcomp/dcomp value %i.\n", + comp); + return NULL; +} + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct + llist_head + *comp_entities, int nsapi) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->nsapi_len; i++) { + if (comp_entity->nsapi[i] == nsapi) + return comp_entity; + } + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given nsapi value %i\n", + nsapi); + return NULL; + +} + +/* Find a comp_index for a given pcomp/dcomp value */ +int gprs_sndcp_comp_get_idx(const struct + gprs_sndcp_comp + *comp_entity, int comp) +{ + int i; + + OSMO_ASSERT(comp_entity); + + /* A pcomp/dcomp field set to zero always disables + * all sort of compression and is assigned fix. So we + * just return zero in this case */ + if (comp == 0) + return 0; + + /* Look in the pcomp/dcomp list for the index */ + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return i + 1; + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching comp_index for given pcomp/dcomp value %i\n", + comp); + return 0; + +} + +/* Find a pcomp/dcomp value for a given comp_index */ +int gprs_sndcp_comp_get_comp(const struct + gprs_sndcp_comp + *comp_entity, int comp_index) +{ + OSMO_ASSERT(comp_entity); + + /* A comp_index of zero translates to zero right away. */ + if (comp_index == 0) + return 0; + + if (comp_index > comp_entity->comp_len) { + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching pcomp/dcomp value for given comp_index value %i.\n", + comp_index); + return 0; + } + + /* Look in the pcomp/dcomp list for the comp_index */ + return comp_entity->comp[comp_index - 1]; + +} diff --git a/openbsc/src/gprs/gprs_sndcp_pcomp.c b/openbsc/src/gprs/gprs_sndcp_pcomp.c new file mode 100644 index 0000000..786bcff --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_pcomp.c @@ -0,0 +1,300 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a new header compression + * entity is created by gprs_sndcp.c */ + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + comp_entity->state = + slhc_init(ctx, comp_field->rfc1144_params->s01 + 1, + comp_field->rfc1144_params->s01 + 1); + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression initalized.\n"); + return 0; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a header compression + * entity is deleted by gprs_sndcp.c */ + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + if (comp_entity->state) { + slhc_free((struct slcompress *) comp_entity-> + state); + comp_entity->state = NULL; + } + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression terminated.\n"); + return; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + + +/* Display compressor status */ +static void gprs_sndcp_pcomp_rfc1144_stat(struct slcompress *comp) +{ + slhc_i_status(comp); + slhc_o_status(comp); +} + + +/* Compress a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_compress(struct slcompress *comp, + uint8_t *packet, + int packet_len, + int *pcomp_index) +{ + uint8_t *packet_compressed; + uint8_t *packet_compressed_ptr; /* Not used */ + int packet_compressed_len; + + /* Reserve some space for to store the compression result */ + packet_compressed = talloc_zero_size(NULL, packet_len); + + /* Run compressor */ + memcpy(packet_compressed, packet, packet_len); + packet_compressed_len = + slhc_compress(comp, packet, packet_len, + (uint8_t *) packet_compressed, + &packet_compressed_ptr, 0); + + /* Copy back compression result */ + memcpy(packet, packet_compressed, packet_len); + talloc_free(packet_compressed); + + /* Generate pcomp_index */ + if ((packet[0] & SL_TYPE_COMPRESSED_TCP) == SL_TYPE_COMPRESSED_TCP) { + *pcomp_index = 2; + } else if ((packet[0] & SL_TYPE_UNCOMPRESSED_TCP) == + SL_TYPE_UNCOMPRESSED_TCP) { + *pcomp_index = 1; + + /* Remove tag for uncompressed TCP, because the + * packet type is already define by pcomp */ + packet[0] &= 0x4F; + } else + *pcomp_index = 0; + + return packet_compressed_len; +} + +/* Expand a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_expand(struct slcompress *comp, + uint8_t *packet, + int packet_len, + int pcomp_index) +{ + int packet_decompressed_len; + int type = -1; + + /* Note: this function should never be called with pcomp_index=0, + * since this condition is already filtered + * out by gprs_sndcp_pcomp_expand() */ + + /* Determine the packet type by the PCOMP index */ + switch (pcomp_index) { + case 1: + type = SL_TYPE_UNCOMPRESSED_TCP; + break; + case 2: + type = SL_TYPE_COMPRESSED_TCP; + break; + } + + /* Restore the original version nibble on + * marked uncompressed packets */ + if (type == SL_TYPE_UNCOMPRESSED_TCP) { + LOGP(DSNDCP, LOGL_INFO, + "Uncompressed rfc1144 packet received...\n"); + + + /* Just in case the phone tags uncompressed tcp-packets + * (normally this is handled by pcomp so there is + * no need for tagging the packets) */ + packet[0] &= 0x4F; + packet_decompressed_len = + slhc_remember(comp, packet, packet_len); + return packet_decompressed_len; + } + + /* Uncompress compressed packets */ + else if (type == SL_TYPE_COMPRESSED_TCP) { + LOGP(DSNDCP, LOGL_INFO, + "Compressed rfc1144 packet received...\n"); + packet_decompressed_len = + slhc_uncompress(comp, packet, packet_len); + return packet_decompressed_len; + } + + + /* Regular or unknown packets will not be touched */ + return packet_len; +} + + +/* Expand header compressed packet */ +int gprs_sndcp_pcomp_expand(uint8_t *packet, int packet_len, int pcomp, + const struct llist_head *comp_entities) +{ + int rc; + int pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + /* Skip on pcomp=0 */ + if (pcomp == 0) { + LOGP(DSNDCP, LOGL_INFO, + "Uncompressed packet received (pcomp=0), skipping compression...\n"); + return packet_len; + } + + /* Find out which compression entity handles the packet */ + comp_entity = + gprs_sndcp_comp_by_comp(comp_entities, pcomp); + + /* Skip compression if no suitable compression entity can be found! */ + if (comp_entity == NULL) { + LOGP(DSNDCP, LOGL_ERROR, + "Compressed packet received (pcomp=%i) but no suitable compression entity found, skipping compression...\n", + pcomp); + return packet_len; + } + + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144) + + + /* Find pcomp_index */ + pcomp_index = gprs_sndcp_comp_get_idx(comp_entity, pcomp); + + /* Run decompression algo */ + rc = gprs_sndcp_pcomp_rfc1144_expand((struct slcompress *) + comp_entity->state, packet, + packet_len, pcomp_index); + gprs_sndcp_pcomp_rfc1144_stat((struct slcompress *) comp_entity-> + state); + + + LOGP(DSNDCP, LOGL_DEBUG, + "Header expansion done, old length=%i, new length=%i, pcomp=%i, pcomp_index=%i\n", + packet_len, rc, pcomp, pcomp_index); + + return rc; +} + + +/* Expand header compressed packet */ +int gprs_sndcp_pcomp_compress(uint8_t *packet, int packet_len, + int *pcomp, + const struct llist_head *comp_entities, + int nsapi) +{ + int rc; + int pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + /* Find out which compression entity handles the packet */ + comp_entity = gprs_sndcp_comp_by_nsapi(comp_entities, nsapi); + + /* Skip compression if no suitable compression entity can be found! */ + if (comp_entity == NULL) { + LOGP(DSNDCP, LOGL_INFO, + "No suitable compression entity found for nsapi %i, skipping compression...\n", + nsapi); + *pcomp = 0; + return packet_len; + } + + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144) + + + /* Run compression algo */ + rc = gprs_sndcp_pcomp_rfc1144_compress((struct slcompress *) + comp_entity->state, + packet, packet_len, + &pcomp_index); + gprs_sndcp_pcomp_rfc1144_stat((struct slcompress *) comp_entity-> state); + + /* Find pcomp value */ + *pcomp = gprs_sndcp_comp_get_comp(comp_entity, pcomp_index); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header compression done, old length=%i, new length=%i, pcomp=%i, pcomp_index=%i\n", + packet_len, rc, *pcomp, pcomp_index); + return rc; +} + + diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 3e66978..1804280 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -33,6 +33,8 @@ $(top_builddir)/src/gprs/gprs_llc_xid.o \ $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ $(top_builddir)/src/gprs/slhc.o \ + $(top_builddir)/src/gprs/gprs_sndcp_comp.o \ + $(top_builddir)/src/gprs/gprs_sndcp_pcomp.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ -- To view, visit https://gerrit.osmocom.org/642 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 Gerrit-PatchSet: 9 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Wed Aug 10 15:54:57 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Wed, 10 Aug 2016 15:54:57 +0000 Subject: [PATCH] openbsc[master]: V42BIS integration In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/644 to look at the new patch set (#14). V42BIS integration The previously committed SPANDSP v42bis implementation has been edited to function outside the SPANDSP library. Debug printf statements were changed into DEBUGP statements. Als removed the assembely code in top_bit(). Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d --- M openbsc/include/openbsc/debug.h M openbsc/include/openbsc/v42bis.h R openbsc/include/openbsc/v42bis_private.h M openbsc/src/gprs/v42bis.c 4 files changed, 19 insertions(+), 21 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/44/644/14 diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 90ddca5..ca3d4ad 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -37,6 +37,7 @@ DGTPHUB, DRANAP, DSUA, + DV42BIS, Debug_LastEntry, }; diff --git a/openbsc/include/openbsc/v42bis.h b/openbsc/include/openbsc/v42bis.h index f13e5c5..e7592e8 100644 --- a/openbsc/include/openbsc/v42bis.h +++ b/openbsc/include/openbsc/v42bis.h @@ -36,6 +36,8 @@ #if !defined(_SPANDSP_V42BIS_H_) #define _SPANDSP_V42BIS_H_ +#define SPAN_DECLARE(x) x + #define V42BIS_MAX_BITS 12 #define V42BIS_MAX_CODEWORDS 4096 /* 2^V42BIS_MAX_BITS */ #define V42BIS_TABLE_SIZE 5021 /* This should be a prime >(2^V42BIS_MAX_BITS) */ diff --git a/openbsc/include/openbsc/private_v42bis.h b/openbsc/include/openbsc/v42bis_private.h similarity index 100% rename from openbsc/include/openbsc/private_v42bis.h rename to openbsc/include/openbsc/v42bis_private.h diff --git a/openbsc/src/gprs/v42bis.c b/openbsc/src/gprs/v42bis.c index 6d38916..fd88b53 100644 --- a/openbsc/src/gprs/v42bis.c +++ b/openbsc/src/gprs/v42bis.c @@ -31,9 +31,8 @@ /*! \file */ -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif +#define FALSE 0 +#define TRUE 1 #include #include @@ -44,13 +43,9 @@ #include #include -#include "spandsp/telephony.h" -#include "spandsp/logging.h" -#include "spandsp/bit_operations.h" -#include "spandsp/v42bis.h" +#include +#include -#include "spandsp/private/logging.h" -#include "spandsp/private/v42bis.h" /* Fixed parameters from the spec. */ #define V42BIS_N3 8 /* Character size (bits) */ @@ -310,7 +305,7 @@ { if (ss->transparent) { - printf("Going compressed\n"); + DEBUGP(DV42BIS,"Going compressed\n"); /* 7.8.1 Transition to compressed mode */ /* Switch out of transparent now, between codes. We need to send the octet which did not match, just before switching. */ @@ -332,7 +327,7 @@ { if (!ss->transparent) { - printf("Going transparent\n"); + DEBUGP(DV42BIS,"Going transparent\n"); /* 7.8.2 Transition to transparent mode */ /* Switch into transparent now, between codes, and the unmatched octet should go out in transparent mode, just below */ @@ -401,7 +396,7 @@ { if (s->compress.dict[i].parent_code != 0xFFFF) { - printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); + DEBUGP(DV42BIS,"Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); } } return 0; @@ -454,13 +449,13 @@ ss->escaped = FALSE; if (code == V42BIS_ECM) { - printf("Hit V42BIS_ECM\n"); + DEBUGP(DV42BIS,"Hit V42BIS_ECM\n"); ss->transparent = FALSE; code_len = ss->v42bis_parm_c2; } else if (code == V42BIS_EID) { - printf("Hit V42BIS_EID\n"); + DEBUGP(DV42BIS,"Hit V42BIS_EID\n"); ss->output_buf[ss->output_octet_count++] = ss->escape_code - 1; if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) { @@ -470,11 +465,11 @@ } else if (code == V42BIS_RESET) { - printf("Hit V42BIS_RESET\n"); + DEBUGP(DV42BIS,"Hit V42BIS_RESET\n"); } else { - printf("Hit V42BIS_???? - %" PRIu32 "\n", code); + DEBUGP(DV42BIS,"Hit V42BIS_???? - %" PRIu32 "\n", code); } } else if (code == ss->escape_code) @@ -500,17 +495,17 @@ switch (new_code) { case V42BIS_ETM: - printf("Hit V42BIS_ETM\n"); + DEBUGP(DV42BIS,"Hit V42BIS_ETM\n"); ss->transparent = TRUE; code_len = 8; break; case V42BIS_FLUSH: - printf("Hit V42BIS_FLUSH\n"); + DEBUGP(DV42BIS,"Hit V42BIS_FLUSH\n"); v42bis_decompress_flush(s); break; case V42BIS_STEPUP: /* We need to increase the codeword size */ - printf("Hit V42BIS_STEPUP\n"); + DEBUGP(DV42BIS,"Hit V42BIS_STEPUP\n"); if (ss->v42bis_parm_c3 >= s->v42bis_parm_n2) { /* Invalid condition */ @@ -547,7 +542,7 @@ /* Trace back through the octets which form the string, and output them. */ while (code >= V42BIS_N5) { -if (code > 4095) {printf("Code is 0x%" PRIu32 "\n", code); exit(2);} +if (code > 4095) {DEBUGP(DV42BIS,"Code is 0x%" PRIu32 "\n", code); exit(2);} *string-- = ss->dict[code].node_octet; code = ss->dict[code].parent_code; } @@ -631,7 +626,7 @@ { if (s->decompress.dict[i].parent_code != 0xFFFF) { - printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); + DEBUGP(DV42BIS,"Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); } } return 0; -- To view, visit https://gerrit.osmocom.org/644 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d Gerrit-PatchSet: 14 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Wed Aug 10 15:54:57 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Wed, 10 Aug 2016 15:54:57 +0000 Subject: [PATCH] openbsc[master]: Adding SLHC (RFC1144 header compression) code from linux kernel In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/634 to look at the new patch set (#4). Adding SLHC (RFC1144 header compression) code from linux kernel Slhc is an Implementation of RFC1144 TCP/IP header compression. We will need RFC1144 compression to compress GPRS TCP/IP traffic. The implementation pushed with this commit was taken from git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git git://git.kernel.org/pub/scm/linux/kernel/git/wtarreau/linux-2.4.git commit 29b4817d4018df78086157ea3a55c1d9424a7cfc Change-Id: Ied69c143678dc4a64cecc671f5c4dfebe19d8519 --- A openbsc/include/openbsc/slhc_vj.h A openbsc/src/gprs/slhc.c 2 files changed, 927 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/34/634/4 diff --git a/openbsc/include/openbsc/slhc_vj.h b/openbsc/include/openbsc/slhc_vj.h new file mode 100644 index 0000000..8716d59 --- /dev/null +++ b/openbsc/include/openbsc/slhc_vj.h @@ -0,0 +1,183 @@ +#ifndef _SLHC_H +#define _SLHC_H +/* + * Definitions for tcp compression routines. + * + * $Header: slcompress.h,v 1.10 89/12/31 08:53:02 van Exp $ + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van at helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + * + * + * modified for KA9Q Internet Software Package by + * Katie Stevens (dkstevens at ucdavis.edu) + * University of California, Davis + * Computing Services + * - 01-31-90 initial adaptation + * + * - Feb 1991 Bill_Simpson at um.cc.umich.edu + * variable number of conversation slots + * allow zero or one slots + * separate routines + * status display + */ + +/* + * Compressed packet format: + * + * The first octet contains the packet type (top 3 bits), TCP + * 'push' bit, and flags that indicate which of the 4 TCP sequence + * numbers have changed (bottom 5 bits). The next octet is a + * conversation number that associates a saved IP/TCP header with + * the compressed packet. The next two octets are the TCP checksum + * from the original datagram. The next 0 to 15 octets are + * sequence number changes, one change per bit set in the header + * (there may be no changes and there are two special cases where + * the receiver implicitly knows what changed -- see below). + * + * There are 5 numbers which can change (they are always inserted + * in the following order): TCP urgent pointer, window, + * acknowledgment, sequence number and IP ID. (The urgent pointer + * is different from the others in that its value is sent, not the + * change in value.) Since typical use of SLIP links is biased + * toward small packets (see comments on MTU/MSS below), changes + * use a variable length coding with one octet for numbers in the + * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the + * range 256 - 65535 or 0. (If the change in sequence number or + * ack is more than 65535, an uncompressed packet is sent.) + */ + +/* + * Packet types (must not conflict with IP protocol version) + * + * The top nibble of the first octet is the packet type. There are + * three possible types: IP (not proto TCP or tcp with one of the + * control flags set); uncompressed TCP (a normal IP/TCP packet but + * with the 8-bit protocol field replaced by an 8-bit connection id -- + * this type of packet syncs the sender & receiver); and compressed + * TCP (described above). + * + * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and + * is logically part of the 4-bit "changes" field that follows. Top + * three bits are actual packet type. For backward compatibility + * and in the interest of conserving bits, numbers are chosen so the + * IP protocol version number (4) which normally appears in this nibble + * means "IP packet". + */ + + +#include +#include + +/* SLIP compression masks for len/vers byte */ +#define SL_TYPE_IP 0x40 +#define SL_TYPE_UNCOMPRESSED_TCP 0x70 +#define SL_TYPE_COMPRESSED_TCP 0x80 +#define SL_TYPE_ERROR 0x00 + +/* Bits in first octet of compressed packet */ +#define NEW_C 0x40 /* flag bits for what changed in a packet */ +#define NEW_I 0x20 +#define NEW_S 0x08 +#define NEW_A 0x04 +#define NEW_W 0x02 +#define NEW_U 0x01 + +/* reserved, special-case values of above */ +#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */ +#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */ +#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U) + +#define TCP_PUSH_BIT 0x10 + +/* + * data type and sizes conversion assumptions: + * + * VJ code KA9Q style generic + * u_char byte_t unsigned char 8 bits + * u_short int16 unsigned short 16 bits + * u_int int16 unsigned short 16 bits + * u_long unsigned long unsigned long 32 bits + * int int32 long 32 bits + */ + +typedef __u8 byte_t; +typedef __u32 int32; + +/* + * "state" data for each active tcp conversation on the wire. This is + * basically a copy of the entire IP/TCP header from the last packet + * we saw from the conversation together with a small identifier + * the transmit & receive ends of the line use to locate saved header. + */ +struct cstate { + byte_t cs_this; /* connection id number (xmit) */ + struct cstate *next; /* next in ring (xmit) */ + struct iphdr cs_ip; /* ip/tcp hdr from most recent packet */ + struct tcphdr cs_tcp; + unsigned char cs_ipopt[64]; + unsigned char cs_tcpopt[64]; + int cs_hsize; +}; +#define NULLSLSTATE (struct cstate *)0 + +/* + * all the state data for one serial line (we need one of these per line). + */ +struct slcompress { + struct cstate *tstate; /* transmit connection states (array)*/ + struct cstate *rstate; /* receive connection states (array)*/ + + byte_t tslot_limit; /* highest transmit slot id (0-l)*/ + byte_t rslot_limit; /* highest receive slot id (0-l)*/ + + byte_t xmit_oldest; /* oldest xmit in ring */ + byte_t xmit_current; /* most recent xmit id */ + byte_t recv_current; /* most recent rcvd id */ + + byte_t flags; +#define SLF_TOSS 0x01 /* tossing rcvd frames until id received */ + + int32 sls_o_nontcp; /* outbound non-TCP packets */ + int32 sls_o_tcp; /* outbound TCP packets */ + int32 sls_o_uncompressed; /* outbound uncompressed packets */ + int32 sls_o_compressed; /* outbound compressed packets */ + int32 sls_o_searches; /* searches for connection state */ + int32 sls_o_misses; /* times couldn't find conn. state */ + + int32 sls_i_uncompressed; /* inbound uncompressed packets */ + int32 sls_i_compressed; /* inbound compressed packets */ + int32 sls_i_error; /* inbound error packets */ + int32 sls_i_tossed; /* inbound packets tossed because of error */ + + int32 sls_i_runt; + int32 sls_i_badcheck; +}; +#define NULLSLCOMPR (struct slcompress *)0 + +/* In slhc.c: */ +struct slcompress *slhc_init(int rslots, int tslots); +void slhc_free(struct slcompress *comp); + +int slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, + unsigned char *ocp, unsigned char **cpp, int compress_cid); +int slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize); +int slhc_remember(struct slcompress *comp, unsigned char *icp, int isize); +int slhc_toss(struct slcompress *comp); + +#endif /* _SLHC_H */ diff --git a/openbsc/src/gprs/slhc.c b/openbsc/src/gprs/slhc.c new file mode 100644 index 0000000..27ed252 --- /dev/null +++ b/openbsc/src/gprs/slhc.c @@ -0,0 +1,744 @@ +/* + * Routines to compress and uncompress tcp packets (for transmission + * over low speed serial lines). + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van at helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + * + * + * modified for KA9Q Internet Software Package by + * Katie Stevens (dkstevens at ucdavis.edu) + * University of California, Davis + * Computing Services + * - 01-31-90 initial adaptation (from 1.19) + * PPP.05 02-15-90 [ks] + * PPP.08 05-02-90 [ks] use PPP protocol field to signal compression + * PPP.15 09-90 [ks] improve mbuf handling + * PPP.16 11-02 [karn] substantially rewritten to use NOS facilities + * + * - Feb 1991 Bill_Simpson at um.cc.umich.edu + * variable number of conversation slots + * allow zero or one slots + * separate routines + * status display + * - Jul 1994 Dmitry Gorodchanin + * Fixes for memory leaks. + * - Oct 1994 Dmitry Gorodchanin + * Modularization. + * - Jan 1995 Bjorn Ekwall + * Use ip_fast_csum from ip.h + * - July 1995 Christos A. Polyzols + * Spotted bug in tcp option checking + * + * + * This module is a difficult issue. It's clearly inet code but it's also clearly + * driver code belonging close to PPP and SLIP + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_INET +/* Entire module is for IP only */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned char *encode(unsigned char *cp, unsigned short n); +static long decode(unsigned char **cpp); +static unsigned char * put16(unsigned char *cp, unsigned short x); +static unsigned short pull16(unsigned char **cpp); + +/* Allocate compression data structure + * slots must be in range 0 to 255 (zero meaning no compression) + * Returns pointer to structure or ERR_PTR() on error. + */ +struct slcompress * +slhc_init(int rslots, int tslots) +{ + register short i; + register struct cstate *ts; + struct slcompress *comp; + + if (rslots < 0 || rslots > 255 || tslots < 0 || tslots > 255) + return ERR_PTR(-EINVAL); + + comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL); + if (! comp) + goto out_fail; + + if (rslots > 0) { + size_t rsize = rslots * sizeof(struct cstate); + comp->rstate = kzalloc(rsize, GFP_KERNEL); + if (! comp->rstate) + goto out_free; + comp->rslot_limit = rslots - 1; + } + + if (tslots > 0) { + size_t tsize = tslots * sizeof(struct cstate); + comp->tstate = kzalloc(tsize, GFP_KERNEL); + if (! comp->tstate) + goto out_free2; + comp->tslot_limit = tslots - 1; + } + + comp->xmit_oldest = 0; + comp->xmit_current = 255; + comp->recv_current = 255; + /* + * don't accept any packets with implicit index until we get + * one with an explicit index. Otherwise the uncompress code + * will try to use connection 255, which is almost certainly + * out of range + */ + comp->flags |= SLF_TOSS; + + if ( tslots > 0 ) { + ts = comp->tstate; + for(i = comp->tslot_limit; i > 0; --i){ + ts[i].cs_this = i; + ts[i].next = &(ts[i - 1]); + } + ts[0].next = &(ts[comp->tslot_limit]); + ts[0].cs_this = 0; + } + return comp; + +out_free2: + kfree(comp->rstate); +out_free: + kfree(comp); +out_fail: + return ERR_PTR(-ENOMEM); +} + + +/* Free a compression data structure */ +void +slhc_free(struct slcompress *comp) +{ + if ( comp == NULLSLCOMPR ) + return; + + if ( comp->tstate != NULLSLSTATE ) + kfree( comp->tstate ); + + if ( comp->rstate != NULLSLSTATE ) + kfree( comp->rstate ); + + kfree( comp ); +} + + +/* Put a short in host order into a char array in network order */ +static inline unsigned char * +put16(unsigned char *cp, unsigned short x) +{ + *cp++ = x >> 8; + *cp++ = x; + + return cp; +} + + +/* Encode a number */ +static unsigned char * +encode(unsigned char *cp, unsigned short n) +{ + if(n >= 256 || n == 0){ + *cp++ = 0; + cp = put16(cp,n); + } else { + *cp++ = n; + } + return cp; +} + +/* Pull a 16-bit integer in host order from buffer in network byte order */ +static unsigned short +pull16(unsigned char **cpp) +{ + short rval; + + rval = *(*cpp)++; + rval <<= 8; + rval |= *(*cpp)++; + return rval; +} + +/* Decode a number */ +static long +decode(unsigned char **cpp) +{ + register int x; + + x = *(*cpp)++; + if(x == 0){ + return pull16(cpp) & 0xffff; /* pull16 returns -1 on error */ + } else { + return x & 0xff; /* -1 if PULLCHAR returned error */ + } +} + +/* + * icp and isize are the original packet. + * ocp is a place to put a copy if necessary. + * cpp is initially a pointer to icp. If the copy is used, + * change it to ocp. + */ + +int +slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, + unsigned char *ocp, unsigned char **cpp, int compress_cid) +{ + register struct cstate *ocs = &(comp->tstate[comp->xmit_oldest]); + register struct cstate *lcs = ocs; + register struct cstate *cs = lcs->next; + register unsigned long deltaS, deltaA; + register short changes = 0; + int hlen; + unsigned char new_seq[16]; + register unsigned char *cp = new_seq; + struct iphdr *ip; + struct tcphdr *th, *oth; + __sum16 csum; + + + /* + * Don't play with runt packets. + */ + + if(isizeprotocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x3fff)) { + /* Send as regular IP */ + if(ip->protocol != IPPROTO_TCP) + comp->sls_o_nontcp++; + else + comp->sls_o_tcp++; + return isize; + } + /* Extract TCP header */ + + th = (struct tcphdr *)(((unsigned char *)ip) + ip->ihl*4); + hlen = ip->ihl*4 + th->doff*4; + + /* Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or + * some other control bit is set). Also uncompressible if + * it's a runt. + */ + if(hlen > isize || th->syn || th->fin || th->rst || + ! (th->ack)){ + /* TCP connection stuff; send as regular IP */ + comp->sls_o_tcp++; + return isize; + } + /* + * Packet is compressible -- we're going to send either a + * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way, + * we need to locate (or create) the connection state. + * + * States are kept in a circularly linked list with + * xmit_oldest pointing to the end of the list. The + * list is kept in lru order by moving a state to the + * head of the list whenever it is referenced. Since + * the list is short and, empirically, the connection + * we want is almost always near the front, we locate + * states via linear search. If we don't find a state + * for the datagram, the oldest state is (re-)used. + */ + for ( ; ; ) { + if( ip->saddr == cs->cs_ip.saddr + && ip->daddr == cs->cs_ip.daddr + && th->source == cs->cs_tcp.source + && th->dest == cs->cs_tcp.dest) + goto found; + + /* if current equal oldest, at end of list */ + if ( cs == ocs ) + break; + lcs = cs; + cs = cs->next; + comp->sls_o_searches++; + } + /* + * Didn't find it -- re-use oldest cstate. Send an + * uncompressed packet that tells the other side what + * connection number we're using for this conversation. + * + * Note that since the state list is circular, the oldest + * state points to the newest and we only need to set + * xmit_oldest to update the lru linkage. + */ + comp->sls_o_misses++; + comp->xmit_oldest = lcs->cs_this; + goto uncompressed; + +found: + /* + * Found it -- move to the front on the connection list. + */ + if(lcs == ocs) { + /* found at most recently used */ + } else if (cs == ocs) { + /* found at least recently used */ + comp->xmit_oldest = lcs->cs_this; + } else { + /* more than 2 elements */ + lcs->next = cs->next; + cs->next = ocs->next; + ocs->next = cs; + } + + /* + * Make sure that only what we expect to change changed. + * Check the following: + * IP protocol version, header length & type of service. + * The "Don't fragment" bit. + * The time-to-live field. + * The TCP header length. + * IP options, if any. + * TCP options, if any. + * If any of these things are different between the previous & + * current datagram, we send the current datagram `uncompressed'. + */ + oth = &cs->cs_tcp; + + if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl + || ip->tos != cs->cs_ip.tos + || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000)) + || ip->ttl != cs->cs_ip.ttl + || th->doff != cs->cs_tcp.doff + || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) + || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){ + goto uncompressed; + } + + /* + * Figure out which of the changing fields changed. The + * receiver expects changes in the order: urgent, window, + * ack, seq (the order minimizes the number of temporaries + * needed in this section of code). + */ + if(th->urg){ + deltaS = ntohs(th->urg_ptr); + cp = encode(cp,deltaS); + changes |= NEW_U; + } else if(th->urg_ptr != oth->urg_ptr){ + /* argh! URG not set but urp changed -- a sensible + * implementation should never do this but RFC793 + * doesn't prohibit the change so we have to deal + * with it. */ + goto uncompressed; + } + if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){ + cp = encode(cp,deltaS); + changes |= NEW_W; + } + if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){ + if(deltaA > 0x0000ffff) + goto uncompressed; + cp = encode(cp,deltaA); + changes |= NEW_A; + } + if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){ + if(deltaS > 0x0000ffff) + goto uncompressed; + cp = encode(cp,deltaS); + changes |= NEW_S; + } + + switch(changes){ + case 0: /* Nothing changed. If this packet contains data and the + * last one didn't, this is probably a data packet following + * an ack (normal on an interactive connection) and we send + * it compressed. Otherwise it's probably a retransmit, + * retransmitted ack or window probe. Send it uncompressed + * in case the other side missed the compressed version. + */ + if(ip->tot_len != cs->cs_ip.tot_len && + ntohs(cs->cs_ip.tot_len) == hlen) + break; + goto uncompressed; + case SPECIAL_I: + case SPECIAL_D: + /* actual changes match one of our special case encodings -- + * send packet uncompressed. + */ + goto uncompressed; + case NEW_S|NEW_A: + if(deltaS == deltaA && + deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ + /* special case for echoed terminal traffic */ + changes = SPECIAL_I; + cp = new_seq; + } + break; + case NEW_S: + if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ + /* special case for data xfer */ + changes = SPECIAL_D; + cp = new_seq; + } + break; + } + deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id); + if(deltaS != 1){ + cp = encode(cp,deltaS); + changes |= NEW_I; + } + if(th->psh) + changes |= TCP_PUSH_BIT; + /* Grab the cksum before we overwrite it below. Then update our + * state with this packet's header. + */ + csum = th->check; + memcpy(&cs->cs_ip,ip,20); + memcpy(&cs->cs_tcp,th,20); + /* We want to use the original packet as our compressed packet. + * (cp - new_seq) is the number of bytes we need for compressed + * sequence numbers. In addition we need one byte for the change + * mask, one for the connection id and two for the tcp checksum. + * So, (cp - new_seq) + 4 bytes of header are needed. + */ + deltaS = cp - new_seq; + if(compress_cid == 0 || comp->xmit_current != cs->cs_this){ + cp = ocp; + *cpp = ocp; + *cp++ = changes | NEW_C; + *cp++ = cs->cs_this; + comp->xmit_current = cs->cs_this; + } else { + cp = ocp; + *cpp = ocp; + *cp++ = changes; + } + *(__sum16 *)cp = csum; + cp += 2; +/* deltaS is now the size of the change section of the compressed header */ + memcpy(cp,new_seq,deltaS); /* Write list of deltas */ + memcpy(cp+deltaS,icp+hlen,isize-hlen); + comp->sls_o_compressed++; + ocp[0] |= SL_TYPE_COMPRESSED_TCP; + return isize - hlen + deltaS + (cp - ocp); + + /* Update connection state cs & send uncompressed packet (i.e., + * a regular ip/tcp packet but with the 'conversation id' we hope + * to use on future compressed packets in the protocol field). + */ +uncompressed: + memcpy(&cs->cs_ip,ip,20); + memcpy(&cs->cs_tcp,th,20); + if (ip->ihl > 5) + memcpy(cs->cs_ipopt, ip+1, ((ip->ihl) - 5) * 4); + if (th->doff > 5) + memcpy(cs->cs_tcpopt, th+1, ((th->doff) - 5) * 4); + comp->xmit_current = cs->cs_this; + comp->sls_o_uncompressed++; + memcpy(ocp, icp, isize); + *cpp = ocp; + ocp[9] = cs->cs_this; + ocp[0] |= SL_TYPE_UNCOMPRESSED_TCP; + return isize; +} + + +int +slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) +{ + register int changes; + long x; + register struct tcphdr *thp; + register struct iphdr *ip; + register struct cstate *cs; + int len, hdrlen; + unsigned char *cp = icp; + + /* We've got a compressed packet; read the change byte */ + comp->sls_i_compressed++; + if(isize < 3){ + comp->sls_i_error++; + return 0; + } + changes = *cp++; + if(changes & NEW_C){ + /* Make sure the state index is in range, then grab the state. + * If we have a good state index, clear the 'discard' flag. + */ + x = *cp++; /* Read conn index */ + if(x < 0 || x > comp->rslot_limit) + goto bad; + + comp->flags &=~ SLF_TOSS; + comp->recv_current = x; + } else { + /* this packet has an implicit state index. If we've + * had a line error since the last time we got an + * explicit state index, we have to toss the packet. */ + if(comp->flags & SLF_TOSS){ + comp->sls_i_tossed++; + return 0; + } + } + cs = &comp->rstate[comp->recv_current]; + thp = &cs->cs_tcp; + ip = &cs->cs_ip; + + thp->check = *(__sum16 *)cp; + cp += 2; + + thp->psh = (changes & TCP_PUSH_BIT) ? 1 : 0; +/* + * we can use the same number for the length of the saved header and + * the current one, because the packet wouldn't have been sent + * as compressed unless the options were the same as the previous one + */ + + hdrlen = ip->ihl * 4 + thp->doff * 4; + + switch(changes & SPECIALS_MASK){ + case SPECIAL_I: /* Echoed terminal traffic */ + { + register short i; + i = ntohs(ip->tot_len) - hdrlen; + thp->ack_seq = htonl( ntohl(thp->ack_seq) + i); + thp->seq = htonl( ntohl(thp->seq) + i); + } + break; + + case SPECIAL_D: /* Unidirectional data */ + thp->seq = htonl( ntohl(thp->seq) + + ntohs(ip->tot_len) - hdrlen); + break; + + default: + if(changes & NEW_U){ + thp->urg = 1; + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->urg_ptr = htons(x); + } else + thp->urg = 0; + if(changes & NEW_W){ + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->window = htons( ntohs(thp->window) + x); + } + if(changes & NEW_A){ + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->ack_seq = htonl( ntohl(thp->ack_seq) + x); + } + if(changes & NEW_S){ + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->seq = htonl( ntohl(thp->seq) + x); + } + break; + } + if(changes & NEW_I){ + if((x = decode(&cp)) == -1) { + goto bad; + } + ip->id = htons (ntohs (ip->id) + x); + } else + ip->id = htons (ntohs (ip->id) + 1); + + /* + * At this point, cp points to the first byte of data in the + * packet. Put the reconstructed TCP and IP headers back on the + * packet. Recalculate IP checksum (but not TCP checksum). + */ + + len = isize - (cp - icp); + if (len < 0) + goto bad; + len += hdrlen; + ip->tot_len = htons(len); + ip->check = 0; + + memmove(icp + hdrlen, cp, len - hdrlen); + + cp = icp; + memcpy(cp, ip, 20); + cp += 20; + + if (ip->ihl > 5) { + memcpy(cp, cs->cs_ipopt, (ip->ihl - 5) * 4); + cp += (ip->ihl - 5) * 4; + } + + put_unaligned(ip_fast_csum(icp, ip->ihl), + &((struct iphdr *)icp)->check); + + memcpy(cp, thp, 20); + cp += 20; + + if (thp->doff > 5) { + memcpy(cp, cs->cs_tcpopt, ((thp->doff) - 5) * 4); + cp += ((thp->doff) - 5) * 4; + } + + return len; +bad: + comp->sls_i_error++; + return slhc_toss( comp ); +} + + +int +slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +{ + register struct cstate *cs; + unsigned ihl; + + unsigned char index; + + if(isize < 20) { + /* The packet is shorter than a legal IP header */ + comp->sls_i_runt++; + return slhc_toss( comp ); + } + /* Peek at the IP header's IHL field to find its length */ + ihl = icp[0] & 0xf; + if(ihl < 20 / 4){ + /* The IP header length field is too small */ + comp->sls_i_runt++; + return slhc_toss( comp ); + } + index = icp[9]; + icp[9] = IPPROTO_TCP; + + if (ip_fast_csum(icp, ihl)) { + /* Bad IP header checksum; discard */ + comp->sls_i_badcheck++; + return slhc_toss( comp ); + } + if(index > comp->rslot_limit) { + comp->sls_i_error++; + return slhc_toss(comp); + } + + /* Update local state */ + cs = &comp->rstate[comp->recv_current = index]; + comp->flags &=~ SLF_TOSS; + memcpy(&cs->cs_ip,icp,20); + memcpy(&cs->cs_tcp,icp + ihl*4,20); + if (ihl > 5) + memcpy(cs->cs_ipopt, icp + sizeof(struct iphdr), (ihl - 5) * 4); + if (cs->cs_tcp.doff > 5) + memcpy(cs->cs_tcpopt, icp + ihl*4 + sizeof(struct tcphdr), (cs->cs_tcp.doff - 5) * 4); + cs->cs_hsize = ihl*2 + cs->cs_tcp.doff*2; + /* Put headers back on packet + * Neither header checksum is recalculated + */ + comp->sls_i_uncompressed++; + return isize; +} + +int +slhc_toss(struct slcompress *comp) +{ + if ( comp == NULLSLCOMPR ) + return 0; + + comp->flags |= SLF_TOSS; + return 0; +} + +#else /* CONFIG_INET */ + +int +slhc_toss(struct slcompress *comp) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss"); + return -EINVAL; +} +int +slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress"); + return -EINVAL; +} +int +slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, + unsigned char *ocp, unsigned char **cpp, int compress_cid) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress"); + return -EINVAL; +} + +int +slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember"); + return -EINVAL; +} + +void +slhc_free(struct slcompress *comp) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free"); +} +struct slcompress * +slhc_init(int rslots, int tslots) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init"); + return NULL; +} + +#endif /* CONFIG_INET */ + +/* VJ header compression */ +EXPORT_SYMBOL(slhc_init); +EXPORT_SYMBOL(slhc_free); +EXPORT_SYMBOL(slhc_remember); +EXPORT_SYMBOL(slhc_compress); +EXPORT_SYMBOL(slhc_uncompress); +EXPORT_SYMBOL(slhc_toss); + +MODULE_LICENSE("Dual BSD/GPL"); -- To view, visit https://gerrit.osmocom.org/634 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ied69c143678dc4a64cecc671f5c4dfebe19d8519 Gerrit-PatchSet: 4 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Wed Aug 10 15:54:57 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Wed, 10 Aug 2016 15:54:57 +0000 Subject: [PATCH] openbsc[master]: SLHC (RFC1144 header compression) integration In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/635 to look at the new patch set (#4). SLHC (RFC1144 header compression) integration The previously pushed slhc implementation has been modified to compile and function outside of the kernel. Also debug log messages were added and datatypes ware matched. The implementation is now ready to be used Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 --- M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/debug.h R openbsc/include/openbsc/slhc.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/slhc.c M openbsc/tests/sgsn/Makefile.am 6 files changed, 115 insertions(+), 89 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/35/635/4 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index e200b05..f402fea 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,8 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h + gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ + slhc.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 43ebb19..90ddca5 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -29,6 +29,7 @@ DBSSGP, DLLC, DSNDCP, + DSLHC, DNAT, DCTRL, DSMPP, diff --git a/openbsc/include/openbsc/slhc_vj.h b/openbsc/include/openbsc/slhc.h similarity index 97% rename from openbsc/include/openbsc/slhc_vj.h rename to openbsc/include/openbsc/slhc.h index 8716d59..cd5a47c 100644 --- a/openbsc/include/openbsc/slhc_vj.h +++ b/openbsc/include/openbsc/slhc.h @@ -171,7 +171,8 @@ #define NULLSLCOMPR (struct slcompress *)0 /* In slhc.c: */ -struct slcompress *slhc_init(int rslots, int tslots); +struct slcompress *slhc_init(const void *ctx, int rslots, int tslots); + void slhc_free(struct slcompress *comp); int slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, @@ -180,4 +181,7 @@ int slhc_remember(struct slcompress *comp, unsigned char *icp, int isize); int slhc_toss(struct slcompress *comp); +void slhc_i_status(struct slcompress *comp); +void slhc_o_status(struct slcompress *comp); + #endif /* _SLHC_H */ diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index fa4a3dd..245636b 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -26,7 +26,8 @@ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ - oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c + oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ + slhc.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/slhc.c b/openbsc/src/gprs/slhc.c index 27ed252..ed095f9 100644 --- a/openbsc/src/gprs/slhc.c +++ b/openbsc/src/gprs/slhc.c @@ -50,61 +50,77 @@ * driver code belonging close to PPP and SLIP */ -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#ifdef CONFIG_INET -/* Entire module is for IP only */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#define ERR_PTR(x) x + static unsigned char *encode(unsigned char *cp, unsigned short n); static long decode(unsigned char **cpp); static unsigned char * put16(unsigned char *cp, unsigned short x); static unsigned short pull16(unsigned char **cpp); +/* Replacement for kernel space function ip_fast_csum() */ +static uint16_t ip_fast_csum(uint8_t *iph, int ihl) +{ + int i; + uint16_t temp; + uint32_t accumulator = 0xFFFF; + + for(i=0;i0xFFFF) + { + accumulator++; + accumulator&=0xFFFF; + } + } + + return (uint16_t)(htons(~accumulator)&0xFFFF); +} + +/* Replacement for kernel space function put_unaligned() */ +static void put_unaligned(uint16_t val, void *ptr) +{ + memcpy(ptr,&val,sizeof(val)); +} + + /* Allocate compression data structure * slots must be in range 0 to 255 (zero meaning no compression) * Returns pointer to structure or ERR_PTR() on error. */ struct slcompress * -slhc_init(int rslots, int tslots) +slhc_init(const void *ctx, int rslots, int tslots) { register short i; register struct cstate *ts; struct slcompress *comp; if (rslots < 0 || rslots > 255 || tslots < 0 || tslots > 255) - return ERR_PTR(-EINVAL); + return NULL; - comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL); + comp = (struct slcompress *)talloc_zero_size(ctx,sizeof(struct slcompress)); if (! comp) goto out_fail; if (rslots > 0) { size_t rsize = rslots * sizeof(struct cstate); - comp->rstate = kzalloc(rsize, GFP_KERNEL); + comp->rstate = (struct cstate *) talloc_zero_size(ctx, rsize); if (! comp->rstate) goto out_free; comp->rslot_limit = rslots - 1; @@ -112,7 +128,7 @@ if (tslots > 0) { size_t tsize = tslots * sizeof(struct cstate); - comp->tstate = kzalloc(tsize, GFP_KERNEL); + comp->tstate = (struct cstate *) talloc_zero_size(ctx, tsize); if (! comp->tstate) goto out_free2; comp->tslot_limit = tslots - 1; @@ -141,11 +157,11 @@ return comp; out_free2: - kfree(comp->rstate); + talloc_free(comp->rstate); out_free: - kfree(comp); + talloc_free(comp); out_fail: - return ERR_PTR(-ENOMEM); + return NULL; } @@ -153,16 +169,18 @@ void slhc_free(struct slcompress *comp) { + LOGP(DSLHC, LOGL_DEBUG, "slhc_free(): Freeing compression states...\n"); + if ( comp == NULLSLCOMPR ) return; if ( comp->tstate != NULLSLSTATE ) - kfree( comp->tstate ); + talloc_free(comp->tstate ); if ( comp->rstate != NULLSLSTATE ) - kfree( comp->rstate ); + talloc_free( comp->rstate ); - kfree( comp ); + talloc_free( comp ); } @@ -256,6 +274,7 @@ comp->sls_o_nontcp++; else comp->sls_o_tcp++; + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Not a TCP packat, will not touch...\n"); return isize; } /* Extract TCP header */ @@ -271,6 +290,7 @@ ! (th->ack)){ /* TCP connection stuff; send as regular IP */ comp->sls_o_tcp++; + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Packet is part of a TCP connection, will not touch...\n"); return isize; } /* @@ -287,6 +307,9 @@ * states via linear search. If we don't find a state * for the datagram, the oldest state is (re-)used. */ + + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Compressible packet detected!\n"); + for ( ; ; ) { if( ip->saddr == cs->cs_ip.saddr && ip->daddr == cs->cs_ip.daddr @@ -310,11 +333,14 @@ * state points to the newest and we only need to set * xmit_oldest to update the lru linkage. */ + + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Header not yet seen, will memorize header for the next turn...\n"); comp->sls_o_misses++; comp->xmit_oldest = lcs->cs_this; goto uncompressed; found: + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Header already seen, trying to compress...\n"); /* * Found it -- move to the front on the connection list. */ @@ -351,6 +377,7 @@ || th->doff != cs->cs_tcp.doff || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){ + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): The header contains unexpected changes, can't compress...\n"); goto uncompressed; } @@ -369,6 +396,7 @@ * implementation should never do this but RFC793 * doesn't prohibit the change so we have to deal * with it. */ + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): URG not set but urp changed, can't compress...\n"); goto uncompressed; } if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){ @@ -376,14 +404,18 @@ changes |= NEW_W; } if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){ - if(deltaA > 0x0000ffff) + if(deltaA > 0x0000ffff) { + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): (deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L, can't compress...\n"); goto uncompressed; + } cp = encode(cp,deltaA); changes |= NEW_A; } if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){ - if(deltaS > 0x0000ffff) + if(deltaS > 0x0000ffff) { + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): (deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L, can't compress...\n"); goto uncompressed; + } cp = encode(cp,deltaS); changes |= NEW_S; } @@ -399,12 +431,14 @@ if(ip->tot_len != cs->cs_ip.tot_len && ntohs(cs->cs_ip.tot_len) == hlen) break; + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Retransmitted packet detected, can't compress...\n"); goto uncompressed; case SPECIAL_I: case SPECIAL_D: /* actual changes match one of our special case encodings -- * send packet uncompressed. */ + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Special case detected, can't compress...\n"); goto uncompressed; case NEW_S|NEW_A: if(deltaS == deltaA && @@ -467,6 +501,7 @@ * to use on future compressed packets in the protocol field). */ uncompressed: + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Packet will be sent uncompressed...\n"); memcpy(&cs->cs_ip,ip,20); memcpy(&cs->cs_tcp,th,20); if (ip->ihl > 5) @@ -538,6 +573,8 @@ switch(changes & SPECIALS_MASK){ case SPECIAL_I: /* Echoed terminal traffic */ + LOGP(DSLHC, LOGL_DEBUG, "slhc_uncompress(): Echoed terminal traffic detected\n"); + { register short i; i = ntohs(ip->tot_len) - hdrlen; @@ -547,11 +584,13 @@ break; case SPECIAL_D: /* Unidirectional data */ + LOGP(DSLHC, LOGL_DEBUG, "slhc_uncompress(): Unidirectional data detected\n"); thp->seq = htonl( ntohl(thp->seq) + ntohs(ip->tot_len) - hdrlen); break; default: + LOGP(DSLHC, LOGL_DEBUG, "slhc_uncompress(): default packet type detected\n"); if(changes & NEW_U){ thp->urg = 1; if((x = decode(&cp)) == -1) { @@ -601,6 +640,7 @@ ip->tot_len = htons(len); ip->check = 0; + LOGP(DSLHC, LOGL_DEBUG, "slhc_uncompress(): making space for the reconstructed header...\n"); memmove(icp + hdrlen, cp, len - hdrlen); cp = icp; @@ -625,6 +665,7 @@ return len; bad: + LOGP(DSLHC, LOGL_DEBUG, "slhc_uncompress(): bad packet detected!\n"); comp->sls_i_error++; return slhc_toss( comp ); } @@ -641,6 +682,7 @@ if(isize < 20) { /* The packet is shorter than a legal IP header */ comp->sls_i_runt++; + LOGP(DSLHC, LOGL_DEBUG, "slhc_remember(): The packet is shorter than a legal IP header ==> slhc_toss()\n"); return slhc_toss( comp ); } /* Peek at the IP header's IHL field to find its length */ @@ -648,6 +690,7 @@ if(ihl < 20 / 4){ /* The IP header length field is too small */ comp->sls_i_runt++; + LOGP(DSLHC, LOGL_DEBUG, "slhc_remember(): The IP header length field is too small ==> slhc_toss()\n"); return slhc_toss( comp ); } index = icp[9]; @@ -656,10 +699,12 @@ if (ip_fast_csum(icp, ihl)) { /* Bad IP header checksum; discard */ comp->sls_i_badcheck++; + LOGP(DSLHC, LOGL_DEBUG, "slhc_remember(): Bad IP header checksum; discard ==> slhc_toss()\n"); return slhc_toss( comp ); } if(index > comp->rslot_limit) { comp->sls_i_error++; + LOGP(DSLHC, LOGL_DEBUG, "slhc_remember(): index > comp->rslot_limit ==> slhc_toss()\n"); return slhc_toss(comp); } @@ -683,6 +728,7 @@ int slhc_toss(struct slcompress *comp) { + LOGP(DSLHC, LOGL_DEBUG, "slhc_toss(): Reset compression state...\n"); if ( comp == NULLSLCOMPR ) return 0; @@ -690,55 +736,27 @@ return 0; } -#else /* CONFIG_INET */ - -int -slhc_toss(struct slcompress *comp) +void slhc_i_status(struct slcompress *comp) { - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss"); - return -EINVAL; -} -int -slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress"); - return -EINVAL; -} -int -slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, - unsigned char *ocp, unsigned char **cpp, int compress_cid) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress"); - return -EINVAL; + if (comp != NULLSLCOMPR) { + LOGP(DSLHC, LOGL_DEBUG, "slhc_i_status(): %d Cmp, %d Uncmp, %d Bad, %d Tossed\n", + comp->sls_i_compressed, + comp->sls_i_uncompressed, + comp->sls_i_error, + comp->sls_i_tossed); + } } -int -slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +void slhc_o_status(struct slcompress *comp) { - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember"); - return -EINVAL; + if (comp != NULLSLCOMPR) { + LOGP(DSLHC, LOGL_DEBUG, "slhc_o_status(): %d Cmp, %d Uncmp, %d AsIs, %d NotTCP %d Searches, %d Misses\n", + comp->sls_o_compressed, + comp->sls_o_uncompressed, + comp->sls_o_tcp, + comp->sls_o_nontcp, + comp->sls_o_searches, + comp->sls_o_misses); + } } -void -slhc_free(struct slcompress *comp) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free"); -} -struct slcompress * -slhc_init(int rslots, int tslots) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init"); - return NULL; -} - -#endif /* CONFIG_INET */ - -/* VJ header compression */ -EXPORT_SYMBOL(slhc_init); -EXPORT_SYMBOL(slhc_free); -EXPORT_SYMBOL(slhc_remember); -EXPORT_SYMBOL(slhc_compress); -EXPORT_SYMBOL(slhc_uncompress); -EXPORT_SYMBOL(slhc_toss); - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 45d1780..3e66978 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -32,6 +32,7 @@ $(top_builddir)/src/gprs/oap_messages.o \ $(top_builddir)/src/gprs/gprs_llc_xid.o \ $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ + $(top_builddir)/src/gprs/slhc.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ -- To view, visit https://gerrit.osmocom.org/635 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 Gerrit-PatchSet: 4 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Wed Aug 10 15:54:57 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Wed, 10 Aug 2016 15:54:57 +0000 Subject: [PATCH] openbsc[master]: Moving grs_sndcp.h header file to include In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/636 to look at the new patch set (#4). Moving grs_sndcp.h header file to include For some reason gprs_sndcp.h is located in src/gprs. This commit moves gprs_sndcp.h to include/openbsc and fixes the include path in gprs_sndcp.c and gprs_sndcp_vty.c Change-Id: If4e4f1252c81d7907c1b4d738c982bb172b128c9 --- M openbsc/include/openbsc/Makefile.am R openbsc/include/openbsc/gprs_sndcp.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/gprs_sndcp.c M openbsc/src/gprs/gprs_sndcp_vty.c 5 files changed, 3 insertions(+), 7 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/36/636/4 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 11f650d..ce5f768 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,7 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_llc_xid.h + gtphub.h gprs_llc_xid.h gprs_sndcp.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/src/gprs/gprs_sndcp.h b/openbsc/include/openbsc/gprs_sndcp.h similarity index 100% rename from openbsc/src/gprs/gprs_sndcp.h rename to openbsc/include/openbsc/gprs_sndcp.h diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 8cbdd91..1b6de46 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -6,8 +6,6 @@ OSMO_LIBS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) \ $(LIBOSMOCTRL_LIBS) $(LIBOSMOGB_LIBS) -noinst_HEADERS = gprs_sndcp.h - bin_PROGRAMS = osmo-gbproxy if HAVE_LIBGTP diff --git a/openbsc/src/gprs/gprs_sndcp.c b/openbsc/src/gprs/gprs_sndcp.c index 75f95c9..4f71121 100644 --- a/openbsc/src/gprs/gprs_sndcp.c +++ b/openbsc/src/gprs/gprs_sndcp.c @@ -34,8 +34,7 @@ #include #include #include - -#include "gprs_sndcp.h" +#include /* Chapter 7.2: SN-PDU Formats */ struct sndcp_common_hdr { diff --git a/openbsc/src/gprs/gprs_sndcp_vty.c b/openbsc/src/gprs/gprs_sndcp_vty.c index deeef07..430881f 100644 --- a/openbsc/src/gprs/gprs_sndcp_vty.c +++ b/openbsc/src/gprs/gprs_sndcp_vty.c @@ -35,8 +35,7 @@ #include #include #include - -#include "gprs_sndcp.h" +#include #include #include -- To view, visit https://gerrit.osmocom.org/636 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: If4e4f1252c81d7907c1b4d738c982bb172b128c9 Gerrit-PatchSet: 4 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Wed Aug 10 15:54:57 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Wed, 10 Aug 2016 15:54:57 +0000 Subject: [PATCH] openbsc[master]: Adding LLC-XID related modifications in LLC In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/652 to look at the new patch set (#10). Adding LLC-XID related modifications in LLC With this commit the already existing XID mechanism has been modified to suit the needs for the upcomming SNDCP-XID patches. This commit should not break anything since it does not alter the current behaviour (incoming XID is still just echoed, on GMM-Reset a basic XID message is still echoed) Change-Id: I65b9d625e72d3d61c99abdc7041773701d694d52 --- M openbsc/include/openbsc/gprs_llc.h M openbsc/src/gprs/gprs_llc.c M openbsc/tests/sgsn/Makefile.am 3 files changed, 308 insertions(+), 57 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/52/652/10 diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h index 0e497a0..c3b82b1 100644 --- a/openbsc/include/openbsc/gprs_llc.h +++ b/openbsc/include/openbsc/gprs_llc.h @@ -4,6 +4,7 @@ #include #include #include +#include /* Section 4.7 LLC Layer Structure */ enum gprs_llc_sapi { @@ -166,6 +167,13 @@ uint16_t nsei; struct gprs_llc_lle lle[NUM_SAPIS]; + /* Copy of the XID fields we have sent with the last + * network originated XID-Request. Since the phone + * may strip the optional fields in the confirmation + * we need to remeber those fields in order to be + * able to create the compression entity. */ + struct llist_head *xid; + /* Internal management */ uint32_t age_timestamp; }; @@ -219,6 +227,10 @@ int gprs_llgmm_reset_oldmsg(struct msgb* oldmsg, uint8_t sapi, struct gprs_llc_llme *llme); +/* Set of LL-XID negotiation (See also: TS 101 351, Section 7.2.2.4) */ +int gprs_ll_xid_req(struct gprs_llc_lle *lle, + struct gprs_llc_xid_field *l3_xid_field); + /* 04.64 Chapter 7.2.1.1 LLGMM-ASSIGN */ int gprs_llgmm_assign(struct gprs_llc_llme *llme, uint32_t old_tlli, uint32_t new_tlli); diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c index 7724ebb..a627ee9 100644 --- a/openbsc/src/gprs/gprs_llc.c +++ b/openbsc/src/gprs/gprs_llc.c @@ -38,8 +38,279 @@ #include #include #include +#include +#include static struct gprs_llc_llme *llme_alloc(uint32_t tlli); +static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg, + int command); +static int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi, + int command, enum gprs_llc_u_cmd u_cmd, int pf_bit); + +/* BEGIN XID RELATED */ + +/* Generate XID message */ +static int gprs_llc_generate_xid(uint8_t *bytes, int bytes_len, + struct gprs_llc_xid_field *l3_xid_field, + struct gprs_llc_llme *llme) +{ + /* Note: Called by gprs_ll_xid_req() */ + + LLIST_HEAD(xid_fields); + + struct gprs_llc_xid_field xid_version; + struct gprs_llc_xid_field xid_n201u; + struct gprs_llc_xid_field xid_n201i; + + xid_version.type = GPRS_LLC_XID_T_VERSION; + xid_version.data = (uint8_t *) "\x00"; + xid_version.data_len = 1; + + xid_n201u.type = GPRS_LLC_XID_T_N201_U; + xid_n201u.data = (uint8_t *) "\x05\xf0"; + xid_n201u.data_len = 2; + + xid_n201i.type = GPRS_LLC_XID_T_N201_I; + xid_n201i.data = (uint8_t *) "\x05\xf0"; + xid_n201i.data_len = 2; + + /* Add locally managed XID Fields */ + llist_add(&xid_n201i.list, &xid_fields); + llist_add(&xid_n201u.list, &xid_fields); + llist_add(&xid_version.list, &xid_fields); + + /* Append layer 3 XID field (if present) */ + if (l3_xid_field) { + /* Enforce layer 3 XID type (just to be sure) */ + l3_xid_field->type = GPRS_LLC_XID_T_L3_PAR; + + /* Add Layer 3 XID field to the list */ + llist_add(&l3_xid_field->list, &xid_fields); + } + + llme->xid = gprs_llc_copy_xid(llme->xid, &xid_fields); + + return gprs_llc_compile_xid(bytes, bytes_len, &xid_fields); +} + +/* Generate XID message that will cause the GMM to reset */ +static int gprs_llc_generate_xid_for_gmm_reset(uint8_t *bytes, + int bytes_len, uint32_t iov_ui, + struct gprs_llc_llme *llme) +{ + /* Called by gprs_llgmm_reset() and + * gprs_llgmm_reset_oldmsg() */ + + LLIST_HEAD(xid_fields); + + struct gprs_llc_xid_field xid_reset; + struct gprs_llc_xid_field xid_iovui; + + /* First XID component must be RESET */ + xid_reset.type = GPRS_LLC_XID_T_RESET; + xid_reset.data = NULL; + xid_reset.data_len = 0; + + /* Add new IOV-UI */ + xid_iovui.type = GPRS_LLC_XID_T_IOV_UI; + xid_iovui.data = (uint8_t *) & iov_ui; + xid_iovui.data_len = 4; + + /* Add locally managed XID Fields */ + llist_add(&xid_iovui.list, &xid_fields); + llist_add(&xid_reset.list, &xid_fields); + + llme->xid = gprs_llc_copy_xid(llme->xid, &xid_fields); + + return gprs_llc_compile_xid(bytes, bytes_len, &xid_fields); +} + +/* Process an incoming XID confirmation */ +static int gprs_llc_process_xid_conf(uint8_t *bytes, int bytes_len, + struct gprs_llc_lle *lle) +{ + /* Note: This function handles the response of a network originated + * XID-Request. There XID messages reflected by the phone are analyzed + * and processed here. The caller is called by rx_llc_xid(). */ + + struct llist_head *xid_fields; + struct gprs_llc_xid_field *xid_field; + struct gprs_llc_xid_field *xid_field_request; + + /* Parse and analyze XID-Response */ + xid_fields = gprs_llc_parse_xid(NULL, bytes, bytes_len); + + if (xid_fields) { + + gprs_llc_dump_xid_fields(xid_fields, LOGL_DEBUG); + llist_for_each_entry(xid_field, xid_fields, list) { + + /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { + LOGP(DLLC, LOGL_NOTICE, + "Ignoring SNDCP-XID-Field: XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + xid_field->data); + } + + /* Process LLC-XID fields: */ + else { + + /* FIXME: Do something more useful with the + * echoed XID-Information. Currently we + * just ignore the response completely and + * by doing so we blindly accept any changes + * the MS might have done to the our XID + * inquiry. There is a remainig risk of + * malfunction! */ + LOGP(DLLC, LOGL_NOTICE, + "Ignoring XID-Field: XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + xid_field->data); + } + } + gprs_llc_free_xid(xid_fields); + } + + /* Flush pending XID fields */ + lle->llme->xid = gprs_llc_free_xid(lle->llme->xid); + + return 0; +} + +/* Process an incoming XID indication and generate an appropiate response */ +static int gprs_llc_process_xid_ind(uint8_t *bytes_request, + int bytes_request_len, + uint8_t *bytes_response, + int bytes_response_maxlen, + struct gprs_llc_lle *lle) +{ + /* Note: This function computes the response that is sent back to the + * phone when a phone originated XID is received. The function is + * called by rx_llc_xid() */ + + int rc = -EINVAL; + + struct llist_head *xid_fields; + struct llist_head *xid_fields_response; + + struct gprs_llc_xid_field *xid_field; + struct gprs_llc_xid_field *xid_field_response; + + /* Flush eventually pending XID fields */ + lle->llme->xid = gprs_llc_free_xid(lle->llme->xid); + + /* Parse and analyze XID-Request */ + xid_fields = + gprs_llc_parse_xid(lle->llme, bytes_request, bytes_request_len); + if (xid_fields) { + xid_fields_response = talloc_zero(lle->llme, struct llist_head); + INIT_LLIST_HEAD(xid_fields_response); + gprs_llc_dump_xid_fields(xid_fields, LOGL_DEBUG); + + /* Process LLC-XID fields: */ + llist_for_each_entry(xid_field, xid_fields, list) { + + if (xid_field->type != GPRS_LLC_XID_T_L3_PAR) { + /* FIXME: Check the incoming XID parameters for + * for validity. Currently we just blindly + * accept all XID fields by just echoing them. + * There is a remaining risk of malfunction + * when a phone submits values which defer from + * the default! */ + LOGP(DLLC, LOGL_NOTICE, + "Echoing XID-Field: XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + osmo_hexdump_nospc(xid_field->data, + xid_field->data_len)); + xid_field_response = + gprs_llc_dup_xid_field + (lle->llme, xid_field); + llist_add(&xid_field_response->list, + xid_fields_response); + } + } + + rc = gprs_llc_compile_xid(bytes_response, + bytes_response_maxlen, + xid_fields_response); + gprs_llc_free_xid(xid_fields_response); + gprs_llc_free_xid(xid_fields); + } + + return rc; +} + +/* Dispatch XID indications and responses comming from the Phone */ +static void rx_llc_xid(struct gprs_llc_lle *lle, + struct gprs_llc_hdr_parsed *gph) +{ + uint8_t response[1024]; + int response_len; + + /* FIXME: 8.5.3.3: check if XID is invalid */ + if (gph->is_cmd) { + LOGP(DLLC, LOGL_NOTICE, + "Received XID indication from phone.\n"); + + struct msgb *resp; + uint8_t *xid; + resp = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + + response_len = + gprs_llc_process_xid_ind(gph->data, gph->data_len, + response, sizeof(response), + lle); + xid = msgb_put(resp, response_len); + memcpy(xid, response, response_len); + + gprs_llc_tx_xid(lle, resp, 0); + } else { + LOGP(DLLC, LOGL_NOTICE, + "Received XID confirmation from phone.\n"); + gprs_llc_process_xid_conf(gph->data, gph->data_len, lle); + /* FIXME: if we had sent a XID reset, send + * LLGMM-RESET.conf to GMM */ + } +} + + +/* Set of LL-XID negotiation (See also: TS 101 351, Section 7.2.2.4) */ +int gprs_ll_xid_req(struct gprs_llc_lle *lle, + struct gprs_llc_xid_field *l3_xid_field) +{ + /* Note: This functions is calle from gprs_sndcp.c */ + + uint8_t xid_bytes[1024];; + int xid_bytes_len; + uint8_t *xid; + struct msgb *msg; + + /* Generate XID */ + xid_bytes_len = + gprs_llc_generate_xid(xid_bytes, sizeof(xid_bytes), + l3_xid_field, lle->llme); + + /* Only perform XID sending if the XID message contains something */ + if (xid_bytes_len > 0) { + /* Transmit XID bytes */ + msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); + LOGP(DLLC, LOGL_NOTICE, "Sending XID request to phone...\n"); + gprs_llc_tx_xid(lle, msg, 1); + } else { + LOGP(DLLC, LOGL_ERROR, + "XID-Message generation failed, XID not sent!\n"); + return -EINVAL; + } + + return 0; +} +/* END XID RELATED */ + + + /* Entry function from upper level (LLC), asking us to transmit a BSSGP PDU * to a remote MS (identified by TLLI) at a BTS identified by its BVCI and NSEI */ @@ -51,7 +322,7 @@ memset(&dup, 0, sizeof(dup)); /* before we have received some identity from the MS, we might * not yet have a MMC context (e.g. XID negotiation of primarly - * LLC connection fro GMM sapi). */ + * LLC connection from GMM sapi). */ if (mmctx) { dup.imsi = mmctx->imsi; dup.drx_parms = mmctx->drx_parms; @@ -251,6 +522,7 @@ static void llme_free(struct gprs_llc_llme *llme) { + llme->xid = gprs_llc_free_xid(llme->xid); llist_del(&llme->list); talloc_free(llme); } @@ -464,54 +736,6 @@ /* Send BSSGP-DL-UNITDATA.req */ return _bssgp_tx_dl_ud(msg, mmctx); -} - -/* According to 6.4.1.6 / Figure 11 */ -static int msgb_put_xid_par(struct msgb *msg, uint8_t type, uint8_t length, uint8_t *data) -{ - uint8_t header_len = 1; - uint8_t *cur; - - /* type is a 5-bit field... */ - if (type > 0x1f) - return -EINVAL; - - if (length > 3) - header_len = 2; - - cur = msgb_put(msg, length + header_len); - - /* build the header without or with XL bit */ - if (length <= 3) { - *cur++ = (type << 2) | (length & 3); - } else { - *cur++ = 0x80 | (type << 2) | (length >> 6); - *cur++ = (length << 2); - } - - /* copy over the payload of the parameter*/ - memcpy(cur, data, length); - - return length + header_len; -} - -static void rx_llc_xid(struct gprs_llc_lle *lle, - struct gprs_llc_hdr_parsed *gph) -{ - /* FIXME: 8.5.3.3: check if XID is invalid */ - if (gph->is_cmd) { - /* FIXME: implement XID negotiation using SNDCP */ - struct msgb *resp; - uint8_t *xid; - resp = msgb_alloc_headroom(4096, 1024, "LLC_XID"); - xid = msgb_put(resp, gph->data_len); - memcpy(xid, gph->data, gph->data_len); - gprs_llc_tx_xid(lle, resp, 0); - } else { - /* FIXME: if we had sent a XID reset, send - * LLGMM-RESET.conf to GMM */ - /* FIXME: implement XID negotiation using SNDCP */ - } } static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph, @@ -784,17 +1008,24 @@ { struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); struct gprs_llc_lle *lle = &llme->lle[1]; + uint8_t xid_bytes[1024]; + int xid_bytes_len; + uint8_t *xid; + LOGP(DLLC, LOGL_NOTICE, "LLGM Reset\n"); if (RAND_bytes((uint8_t *) &llme->iov_ui, 4) != 1) { LOGP(DLLC, LOGL_NOTICE, "RAND_bytes failed for LLC XID reset, " "falling back to rand()\n"); llme->iov_ui = rand(); } - /* First XID component must be RESET */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL); - /* randomly select new IOV-UI */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &llme->iov_ui); + /* Generate XID message */ + xid_bytes_len = gprs_llc_generate_xid_for_gmm_reset(xid_bytes, + sizeof(xid_bytes),llme->iov_ui,llme); + if(xid_bytes_len < 0) + return -EINVAL; + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); /* Reset some of the LLC parameters. See GSM 04.64, 8.5.3.1 */ lle->vu_recv = 0; @@ -810,17 +1041,24 @@ struct gprs_llc_llme *llme) { struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + uint8_t xid_bytes[1024]; + int xid_bytes_len; + uint8_t *xid; + LOGP(DLLC, LOGL_NOTICE, "LLGM Reset\n"); if (RAND_bytes((uint8_t *) &llme->iov_ui, 4) != 1) { LOGP(DLLC, LOGL_NOTICE, "RAND_bytes failed for LLC XID reset, " "falling back to rand()\n"); llme->iov_ui = rand(); } - /* First XID component must be RESET */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL); - /* randomly select new IOV-UI */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &llme->iov_ui); + /* Generate XID message */ + xid_bytes_len = gprs_llc_generate_xid_for_gmm_reset(xid_bytes, + sizeof(xid_bytes),llme->iov_ui,llme); + if(xid_bytes_len < 0) + return -EINVAL; + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); /* FIXME: Start T200, wait for XID response */ diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index b6036c7..74af159 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -30,6 +30,7 @@ $(top_builddir)/src/gprs/gprs_gb_parse.o \ $(top_builddir)/src/gprs/oap.o \ $(top_builddir)/src/gprs/oap_messages.o \ + $(top_builddir)/src/gprs/gprs_llc_xid.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ -- To view, visit https://gerrit.osmocom.org/652 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I65b9d625e72d3d61c99abdc7041773701d694d52 Gerrit-PatchSet: 10 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Wed Aug 10 15:54:57 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Wed, 10 Aug 2016 15:54:57 +0000 Subject: [PATCH] openbsc[master]: Adding LLC-XID encoder / decoder In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/638 to look at the new patch set (#6). Adding LLC-XID encoder / decoder The lle-xid encoder/decoder is needed to encode and decode llc xid parameter messages. We need this to exchange sndcp-parameters (SNDCP-XID) and also simple parameters such as encryption IOVs Change-Id: Ia06e4cb08bf9b48c2a4682606d1b1a91d19a9d37 --- M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_llc_xid.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_llc_xid.c M openbsc/tests/Makefile.am M openbsc/tests/testsuite.at A openbsc/tests/xid/Makefile.am A openbsc/tests/xid/xid_test.c A openbsc/tests/xid/xid_test.ok 10 files changed, 547 insertions(+), 3 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/38/638/6 diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 0980413..fbf2930 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -229,6 +229,7 @@ tests/oap/Makefile tests/gtphub/Makefile tests/mm_auth/Makefile + tests/xid/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index c272b14..11f650d 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,7 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h + gtphub.h gprs_llc_xid.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_llc_xid.h b/openbsc/include/openbsc/gprs_llc_xid.h new file mode 100644 index 0000000..544528d --- /dev/null +++ b/openbsc/include/openbsc/gprs_llc_xid.h @@ -0,0 +1,64 @@ +/* GPRS LLC XID field encoding/decoding as per 3GPP TS 44.064 */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_LLC_XID_H +#define _GPRS_LLC_XID_H + +#include +#include + +/* 3GPP TS 44.064 6.4.1.6 Exchange Identification (XID) + command/response parameter field */ +struct gprs_llc_xid_field { + struct llist_head list; + uint8_t type; /* See also Table 6: LLC layer parameter + negotiation */ + uint8_t *data; /* Payload data (memory is owned by the + * creator of the struct) */ + unsigned int data_len; /* Payload length */ +}; + +/* Transform a list with XID fields into a XID message (dst) */ +int gprs_llc_compile_xid(uint8_t *dst, int dst_maxlen, + const struct llist_head *xid_fields); + +/* Transform a XID message (dst) into a list of XID fields */ +struct llist_head *gprs_llc_parse_xid(const void *ctx, const uint8_t *src, + int src_len); + +/* Free XID-list with including all its XID-Fields */ +struct llist_head *gprs_llc_free_xid(struct llist_head *xid_fields); + +/* Create a duplicate of an XID-Field */ +struct gprs_llc_xid_field *gprs_llc_dup_xid_field(const void *ctx, const struct + gprs_llc_xid_field + *xid_field); + +/* Copy an llist with xid fields */ +struct llist_head *gprs_llc_copy_xid(const void *ctx, + const struct llist_head *xid_fields); + +/* Dump a list with XID fields (Debug) */ +void gprs_llc_dump_xid_fields(const struct llist_head *xid_fields, + unsigned int logl); + +#endif diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 6dc7e16..8cbdd91 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -28,7 +28,7 @@ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ - oap.c oap_messages.c + oap.c oap_messages.c gprs_llc_xid.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/gprs_llc_xid.c b/openbsc/src/gprs/gprs_llc_xid.c new file mode 100644 index 0000000..651534b --- /dev/null +++ b/openbsc/src/gprs/gprs_llc_xid.c @@ -0,0 +1,283 @@ +/* GPRS LLC XID field encoding/decoding as per 3GPP TS 44.064 */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Parse XID parameter field */ +static int decode_xid_field(struct gprs_llc_xid_field *xid_field, + const uint8_t *src, uint8_t src_len) +{ + uint8_t xl; + uint8_t type; + uint8_t len; + int src_counter = 0; + + OSMO_ASSERT(xid_field); + OSMO_ASSERT(src); + + /* Exit immediately if it is clear that no + * parseable data is present */ + if (src_len < 1 || !src) + return -EINVAL; + + /* Extract header info */ + xl = (*src >> 7) & 1; + type = (*src >> 2) & 0x1F; + + /* Extract length field */ + len = (*src) & 0x3; + src++; + src_counter++; + if (xl) { + if (src_len < 2) + return -EINVAL; + len = (len << 6) & 0xC0; + len |= ((*src) >> 2) & 0x3F; + src++; + src_counter++; + } + + /* Fill out struct */ + xid_field->type = type; + xid_field->data_len = len; + if (len > 0) { + if (src_len < src_counter + len) + return -EINVAL; + xid_field->data = + talloc_zero_size(xid_field, xid_field->data_len); + memcpy(xid_field->data, src, xid_field->data_len); + } else + xid_field->data = NULL; + + /* Return consumed length */ + return src_counter + len; +} + +/* Encode XID parameter field */ +static int encode_xid_field(uint8_t *dst, int dst_maxlen, + const struct gprs_llc_xid_field *xid_field) +{ + int xl = 0; + + OSMO_ASSERT(xid_field); + OSMO_ASSERT(dst); + + /* When the length does not fit into 2 bits, + * we need extended length fields */ + if (xid_field->data_len > 3) + xl = 1; + + /* Exit immediately if it is clear that no + * encoding result can be stored */ + if (dst_maxlen < xid_field->data_len + 1 + xl) + return -EINVAL; + + /* There are only 5 bits reserved for the type, exit on exceed */ + if (xid_field->type > 31) + return -EINVAL; + + /* Encode header */ + memset(dst, 0, dst_maxlen); + if (xl) + dst[0] |= 0x80; + dst[0] |= (((xid_field->type) & 0x1F) << 2); + + if (xl) { + dst[0] |= (((xid_field->data_len) >> 6) & 0x03); + dst[1] = ((xid_field->data_len) << 2) & 0xFC; + } else + dst[0] |= ((xid_field->data_len) & 0x03); + + /* Append payload data */ + if (xid_field->data && xid_field->data_len) + memcpy(dst + 1 + xl, xid_field->data, xid_field->data_len); + + /* Return generated length */ + return xid_field->data_len + 1 + xl; +} + +/* Transform a list with XID fields into a XID message (dst) */ +int gprs_llc_compile_xid(uint8_t *dst, int dst_maxlen, + const struct llist_head *xid_fields) +{ + struct gprs_llc_xid_field *xid_field; + int rc; + int byte_counter = 0; + + OSMO_ASSERT(xid_fields); + OSMO_ASSERT(dst); + + llist_for_each_entry_reverse(xid_field, xid_fields, list) { + /* Encode XID-Field */ + rc = encode_xid_field(dst, dst_maxlen, xid_field); + if (rc < 0) + return -EINVAL; + + /* Advance pointer and lower maxlen for the + * next encoding round */ + dst += rc; + byte_counter += rc; + dst_maxlen -= rc; + } + + /* Return generated length */ + return byte_counter; +} + +/* Transform a XID message (dst) into a list of XID fields */ +struct llist_head *gprs_llc_parse_xid(const void *ctx, const uint8_t *src, + int src_len) +{ + struct gprs_llc_xid_field *xid_field; + struct llist_head *xid_fields; + + int rc; + int max_loops = src_len; + + OSMO_ASSERT(src); + + xid_fields = talloc_zero(ctx, struct llist_head); + INIT_LLIST_HEAD(xid_fields); + + while (1) { + /* Bail in case decode_xid_field() constantly returns zero */ + if (max_loops <= 0) { + talloc_free(xid_fields); + return NULL; + } + + /* Decode XID field */ + xid_field = talloc_zero(xid_fields, struct gprs_llc_xid_field); + rc = decode_xid_field(xid_field, src, src_len); + + /* Immediately stop on error */ + if (rc < 0) { + talloc_free(xid_fields); + return NULL; + } + + /* Add parsed XID field to list */ + llist_add(&xid_field->list, xid_fields); + + /* Advance pointer and lower dst_len for the next + * decoding round */ + src += rc; + src_len -= rc; + + /* We are (scuccessfully) done when no further byes are left */ + if (src_len == 0) + return xid_fields; + + max_loops--; + } +} + +/* Free XID-list with including all its XID-Fields */ +struct llist_head *gprs_llc_free_xid(struct llist_head *xid_fields) +{ + if (xid_fields != NULL) + talloc_free(xid_fields); + return NULL; +} + +/* Create a duplicate of an XID-Field */ +struct gprs_llc_xid_field *gprs_llc_dup_xid_field(const void *ctx, const struct + gprs_llc_xid_field + *xid_field) +{ + struct gprs_llc_xid_field *duplicate_of_xid_field; + + OSMO_ASSERT(xid_field); + + /* Create a copy of the XID field in memory */ + duplicate_of_xid_field = talloc_zero(ctx, struct gprs_llc_xid_field); + memcpy(duplicate_of_xid_field, xid_field, + sizeof(struct gprs_llc_xid_field)); + duplicate_of_xid_field->data = + talloc_zero_size(duplicate_of_xid_field, xid_field->data_len); + memcpy(duplicate_of_xid_field->data, xid_field->data, + xid_field->data_len); + + /* Unlink duplicate from source list */ + INIT_LLIST_HEAD(&duplicate_of_xid_field->list); + + return duplicate_of_xid_field; +} + +/* Copy an llist with xid fields */ +struct llist_head *gprs_llc_copy_xid(const void *ctx, + const struct llist_head *xid_fields) +{ + struct gprs_llc_xid_field *xid_field; + struct llist_head *xid_fields_copy; + + OSMO_ASSERT(xid_fields); + + xid_fields_copy = talloc_zero(ctx, struct llist_head); + INIT_LLIST_HEAD(xid_fields_copy); + + /* Create duplicates and add them to the target list */ + llist_for_each_entry(xid_field, xid_fields, list) { + llist_add(&gprs_llc_dup_xid_field(ctx, xid_field)->list, + xid_fields_copy); + } + + return xid_fields_copy; +} + +/* Dump a list with XID fields (Debug) */ +void gprs_llc_dump_xid_fields(const struct llist_head *xid_fields, + unsigned int logl) +{ + struct gprs_llc_xid_field *xid_field; + + OSMO_ASSERT(xid_fields); + + llist_for_each_entry(xid_field, xid_fields, list) { + if (xid_field->data_len) { + OSMO_ASSERT(xid_field->data); + LOGP(DSNDCP, logl, + "XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + osmo_hexdump_nospc(xid_field->data, + xid_field->data_len)); + } else { + LOGP(DSNDCP, logl, + "XID: type=%i, data_len=%i, data=NULL\n", + xid_field->type, xid_field->data_len); + } + } +} diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index 09298a3..ba5ca28 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index dab9568..6470ab9 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -124,3 +124,8 @@ AT_CHECK([$abs_top_builddir/tests/mm_auth/mm_auth_test], [], [expout], [ignore]) AT_CLEANUP +AT_SETUP([xid]) +AT_KEYWORDS([xid]) +cat $abs_srcdir/xid/xid_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/xid/xid_test], [], [expout], [ignore]) +AT_CLEANUP diff --git a/openbsc/tests/xid/Makefile.am b/openbsc/tests/xid/Makefile.am new file mode 100644 index 0000000..9b64965 --- /dev/null +++ b/openbsc/tests/xid/Makefile.am @@ -0,0 +1,21 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) + +EXTRA_DIST = xid_test.ok + +noinst_PROGRAMS = xid_test + +xid_test_SOURCES = xid_test.c + +xid_test_LDADD = \ + $(top_builddir)/src/gprs/gprs_llc_xid.o \ + $(top_builddir)/src/libcommon/libcommon.a \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOGB_LIBS) \ + $(LIBCARES_LIBS) \ + $(LIBCRYPTO_LIBS) \ + -lgtp -lrt -lm + + diff --git a/openbsc/tests/xid/xid_test.c b/openbsc/tests/xid/xid_test.c new file mode 100644 index 0000000..d699059 --- /dev/null +++ b/openbsc/tests/xid/xid_test.c @@ -0,0 +1,158 @@ +/* Test LLC-XID Encoding/Decoding */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include + +#include +#include + +#include + +#include +#include + +/* Test XID encoding */ +static void test_xid_encode(const void *ctx) +{ + struct gprs_llc_xid_field xid_field_1; + struct gprs_llc_xid_field xid_field_2; + struct gprs_llc_xid_field xid_field_3; + struct gprs_llc_xid_field xid_field_4; + LLIST_HEAD(xid_fields); + uint8_t xid[255]; + uint8_t xid_expected[] = + { 0x10, 0x8c, 0x14, 0x43, 0x43, 0x43, 0x43, 0x43, 0x0b, 0x42, 0x42, + 0x42, 0x05, 0x41 }; + int rc; + + printf("Testing LLC XID-Encoder\n"); + + /* Setup some simple XID data */ + xid_field_1.type = 1; + xid_field_2.type = 2; + xid_field_3.type = 3; + xid_field_4.type = 4; + + xid_field_1.data = (uint8_t *) "A"; + xid_field_2.data = (uint8_t *) "BBB"; + xid_field_3.data = (uint8_t *) "CCCCC"; + xid_field_4.data = NULL; + + xid_field_1.data_len = 1; + xid_field_2.data_len = 3; + xid_field_3.data_len = 5; + xid_field_4.data_len = 0; + + llist_add(&xid_field_4.list, &xid_fields); + llist_add(&xid_field_3.list, &xid_fields); + llist_add(&xid_field_2.list, &xid_fields); + llist_add(&xid_field_1.list, &xid_fields); + + printf("Data to encode:\n"); + gprs_llc_dump_xid_fields(&xid_fields, DSNDCP); + + /* Encode data */ + rc = gprs_llc_compile_xid(xid, sizeof(xid), &xid_fields); + OSMO_ASSERT(rc == 14); + printf("Encoded: %s (%i bytes)\n", osmo_hexdump_nospc(xid, rc), rc); + printf("Expected: %s (%i bytes)\n", + osmo_hexdump_nospc(xid_expected, sizeof(xid_expected)), + (int)sizeof(xid_expected)); + + OSMO_ASSERT(memcmp(xid_expected, xid, sizeof(xid_expected)) == 0); + + printf("\n"); +} + +/* Test XID decoding */ +static void test_xid_decode(const void *ctx) +{ + struct llist_head *xid_fields; + int rc; + + printf("Testing LLC XID-Decoder/Encoder\n"); + + /* Example of a real world LLC-XID message */ + uint8_t xid[] = + { 0x01, 0x00, 0x16, 0x05, 0xf0, 0x1a, 0x05, 0xf0, 0xac, 0xd8, 0x00, + 0x01, 0x00, 0x02, 0x31, 0x82, 0x02, 0x27, 0x89, 0xff, 0xe0, 0x00, 0x0f, + 0x00, 0xa8, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x01, 0x02, + 0x00, 0x03, 0x01, 0x03, 0x00, 0x04, 0x01, 0x04, 0x00, 0x05, 0x01, 0x05, + 0x00, 0x06, 0x00, 0x07, 0x01, 0x07, 0x00, 0x08, 0x01, 0x08, 0x80, 0x00, + 0x04, 0x12, 0x00, 0x40, 0x07 }; + + uint8_t xid_r[512]; + + /* Decode and display XID fields */ + xid_fields = gprs_llc_parse_xid(ctx, xid, sizeof(xid)); + OSMO_ASSERT(xid_fields); + + printf("Decoded:\n"); + gprs_llc_dump_xid_fields(xid_fields, DSNDCP); + + + /* Encode xid-fields again */ + rc = gprs_llc_compile_xid(xid_r, sizeof(xid_r), xid_fields); + printf("Result length=%i\n",rc); + printf("Encoded: %s\n", osmo_hexdump_nospc(xid, sizeof(xid))); + printf("Rencoded: %s\n", osmo_hexdump_nospc(xid_r, rc)); + + OSMO_ASSERT(rc == 64); + OSMO_ASSERT(memcmp(xid, xid_r, sizeof(xid)) == 0); + + /* Free xid fields */ + gprs_llc_free_xid(xid_fields); + + printf("\n"); +} + +static struct log_info_cat gprs_categories[] = { + [DSNDCP] = { + .name = "DSNDCP", + .description = + "GPRS Sub-Network Dependent Control Protocol (SNDCP)", + .enabled = 1,.loglevel = LOGL_DEBUG, + } +}; + +static struct log_info info = { + .cat = gprs_categories, + .num_cat = ARRAY_SIZE(gprs_categories), +}; + +int main(int argc, char **argv) +{ + void *xid_ctx; + + osmo_init_logging(&info); + + xid_ctx = talloc_named_const(NULL, 0, "xid_ctx"); + + test_xid_decode(xid_ctx); + test_xid_encode(xid_ctx); + printf("Done\n"); + + talloc_report_full(xid_ctx, stderr); + OSMO_ASSERT(talloc_total_blocks(xid_ctx) == 1); + return 0; +} diff --git a/openbsc/tests/xid/xid_test.ok b/openbsc/tests/xid/xid_test.ok new file mode 100644 index 0000000..4cf825c --- /dev/null +++ b/openbsc/tests/xid/xid_test.ok @@ -0,0 +1,12 @@ +Testing LLC XID-Decoder/Encoder +Decoded: +Result length=64 +Encoded: 01001605f01a05f0acd8000100023182022789ffe0000f00a8000000010101000201020003010300040104000501050006000701070008010880000412004007 +Rencoded: 01001605f01a05f0acd8000100023182022789ffe0000f00a8000000010101000201020003010300040104000501050006000701070008010880000412004007 + +Testing LLC XID-Encoder +Data to encode: +Encoded: 108c1443434343430b4242420541 (14 bytes) +Expected: 108c1443434343430b4242420541 (14 bytes) + +Done -- To view, visit https://gerrit.osmocom.org/638 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia06e4cb08bf9b48c2a4682606d1b1a91d19a9d37 Gerrit-PatchSet: 6 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Wed Aug 10 15:55:42 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 10 Aug 2016 15:55:42 +0000 Subject: osmo-bts[master]: sysmo: fix dyn TS: Revert "Activate PTCCH UL" [in sysmobts] In-Reply-To: References: Message-ID: Patch Set 1: > According to fw docs the only channel combination with PTCCH > support is GsmL1_LogChComb_XIII so it's incompatible with dyn > channels - see src/osmo-bts-sysmo/oml.c This has nothing to do with dyn channels. A "dyn channel" is a concept that never reaches the firmware/phy level. If a dyn channel is set to PDCH mode, the TS is configured *exactly* like a plain PDCH. I.e. it *is* configured as GsmL1_LogChComb_XIII. The point why I'm talking about dyn TS is because a PDCH failure messes up the higher level. But otherwise, this issue is about *plain* PDCH. Let's drop dyn TS from the technical discussion entirely. Please fix the SAPI activation for *plain* PDCH, which will as a side effect fix the dyn TS state. My point here is that by including PTCCH UL in pdtch_sapis[], you have enabled a feature that is not yet mature and is actually breaking another feature, for no known benefit. I would like to take back the immature feature for the benefit of the working one. A possible fix for PTCCH UL might be at these places: osmo-pcu/src/osmo-bts-sysmo/sysmo_l1_if.c:143: case GsmL1_Sapi_Ptcch: osmo-pcu/src/osmo-bts-sysmo/sysmo_l1_if.c-144- // FIXME osmo-pcu/src/osmo-bts-sysmo/sysmo_l1_if.c:207: case GsmL1_Sapi_Ptcch: osmo-pcu/src/osmo-bts-sysmo/sysmo_l1_if.c-208- // FIXME osmo-pcu/src/pcu_l1_if.cpp:295: case PCU_IF_SAPI_PTCCH: osmo-pcu/src/pcu_l1_if.cpp-296- /* FIXME */ But the point remains that enabling PTCCH UL makes no sense right now. -- To view, visit https://gerrit.osmocom.org/671 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia59d95c75a8a5d3bd596f55cd1dc0906a6a95f7f Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 10 16:07:27 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Wed, 10 Aug 2016 16:07:27 +0000 Subject: [PATCH] openbsc[master]: Adding LLC-XID encoder / decoder In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/638 to look at the new patch set (#7). Adding LLC-XID encoder / decoder The lle-xid encoder/decoder is needed to encode and decode llc xid parameter messages. We need this to exchange sndcp-parameters (SNDCP-XID) and also simple parameters such as encryption IOVs Change-Id: Ia06e4cb08bf9b48c2a4682606d1b1a91d19a9d37 --- M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_llc_xid.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_llc_xid.c M openbsc/tests/Makefile.am M openbsc/tests/testsuite.at A openbsc/tests/xid/Makefile.am A openbsc/tests/xid/xid_test.c A openbsc/tests/xid/xid_test.ok 10 files changed, 547 insertions(+), 3 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/38/638/7 diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 0980413..fbf2930 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -229,6 +229,7 @@ tests/oap/Makefile tests/gtphub/Makefile tests/mm_auth/Makefile + tests/xid/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index c272b14..11f650d 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,7 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h + gtphub.h gprs_llc_xid.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_llc_xid.h b/openbsc/include/openbsc/gprs_llc_xid.h new file mode 100644 index 0000000..f0074e0 --- /dev/null +++ b/openbsc/include/openbsc/gprs_llc_xid.h @@ -0,0 +1,64 @@ +/* GPRS LLC XID field encoding/decoding as per 3GPP TS 44.064 */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_LLC_XID_H +#define _GPRS_LLC_XID_H + +#include +#include + +/* 3GPP TS 44.064 6.4.1.6 Exchange Identification (XID) + command/response parameter field */ +struct gprs_llc_xid_field { + struct llist_head list; + uint8_t type; /* See also Table 6: LLC layer parameter + negotiation */ + uint8_t *data; /* Payload data (memory is owned by the + * creator of the struct) */ + unsigned int data_len; /* Payload length */ +}; + +/* Transform a list with XID fields into a XID message (dst) */ +int gprs_llc_compile_xid(uint8_t *dst, int dst_maxlen, + const struct llist_head *xid_fields); + +/* Transform a XID message (dst) into a list of XID fields */ +struct llist_head *gprs_llc_parse_xid(const void *ctx, const uint8_t *src, + int src_len); + +/* Free XID-list with including all its XID-Fields */ +struct llist_head *gprs_llc_free_xid(struct llist_head *xid_fields); + +/* Create a duplicate of an XID-Field */ +struct gprs_llc_xid_field *gprs_llc_dup_xid_field(const void *ctx, const struct + gprs_llc_xid_field + *xid_field); + +/* Copy an llist with xid fields */ +struct llist_head *gprs_llc_copy_xid(const void *ctx, + const struct llist_head *xid_fields); + +/* Dump a list with XID fields (Debug) */ +void gprs_llc_dump_xid_fields(const struct llist_head *xid_fields, + unsigned int logl); + +#endif diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 6dc7e16..8cbdd91 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -28,7 +28,7 @@ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ - oap.c oap_messages.c + oap.c oap_messages.c gprs_llc_xid.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/gprs_llc_xid.c b/openbsc/src/gprs/gprs_llc_xid.c new file mode 100644 index 0000000..651534b --- /dev/null +++ b/openbsc/src/gprs/gprs_llc_xid.c @@ -0,0 +1,283 @@ +/* GPRS LLC XID field encoding/decoding as per 3GPP TS 44.064 */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Parse XID parameter field */ +static int decode_xid_field(struct gprs_llc_xid_field *xid_field, + const uint8_t *src, uint8_t src_len) +{ + uint8_t xl; + uint8_t type; + uint8_t len; + int src_counter = 0; + + OSMO_ASSERT(xid_field); + OSMO_ASSERT(src); + + /* Exit immediately if it is clear that no + * parseable data is present */ + if (src_len < 1 || !src) + return -EINVAL; + + /* Extract header info */ + xl = (*src >> 7) & 1; + type = (*src >> 2) & 0x1F; + + /* Extract length field */ + len = (*src) & 0x3; + src++; + src_counter++; + if (xl) { + if (src_len < 2) + return -EINVAL; + len = (len << 6) & 0xC0; + len |= ((*src) >> 2) & 0x3F; + src++; + src_counter++; + } + + /* Fill out struct */ + xid_field->type = type; + xid_field->data_len = len; + if (len > 0) { + if (src_len < src_counter + len) + return -EINVAL; + xid_field->data = + talloc_zero_size(xid_field, xid_field->data_len); + memcpy(xid_field->data, src, xid_field->data_len); + } else + xid_field->data = NULL; + + /* Return consumed length */ + return src_counter + len; +} + +/* Encode XID parameter field */ +static int encode_xid_field(uint8_t *dst, int dst_maxlen, + const struct gprs_llc_xid_field *xid_field) +{ + int xl = 0; + + OSMO_ASSERT(xid_field); + OSMO_ASSERT(dst); + + /* When the length does not fit into 2 bits, + * we need extended length fields */ + if (xid_field->data_len > 3) + xl = 1; + + /* Exit immediately if it is clear that no + * encoding result can be stored */ + if (dst_maxlen < xid_field->data_len + 1 + xl) + return -EINVAL; + + /* There are only 5 bits reserved for the type, exit on exceed */ + if (xid_field->type > 31) + return -EINVAL; + + /* Encode header */ + memset(dst, 0, dst_maxlen); + if (xl) + dst[0] |= 0x80; + dst[0] |= (((xid_field->type) & 0x1F) << 2); + + if (xl) { + dst[0] |= (((xid_field->data_len) >> 6) & 0x03); + dst[1] = ((xid_field->data_len) << 2) & 0xFC; + } else + dst[0] |= ((xid_field->data_len) & 0x03); + + /* Append payload data */ + if (xid_field->data && xid_field->data_len) + memcpy(dst + 1 + xl, xid_field->data, xid_field->data_len); + + /* Return generated length */ + return xid_field->data_len + 1 + xl; +} + +/* Transform a list with XID fields into a XID message (dst) */ +int gprs_llc_compile_xid(uint8_t *dst, int dst_maxlen, + const struct llist_head *xid_fields) +{ + struct gprs_llc_xid_field *xid_field; + int rc; + int byte_counter = 0; + + OSMO_ASSERT(xid_fields); + OSMO_ASSERT(dst); + + llist_for_each_entry_reverse(xid_field, xid_fields, list) { + /* Encode XID-Field */ + rc = encode_xid_field(dst, dst_maxlen, xid_field); + if (rc < 0) + return -EINVAL; + + /* Advance pointer and lower maxlen for the + * next encoding round */ + dst += rc; + byte_counter += rc; + dst_maxlen -= rc; + } + + /* Return generated length */ + return byte_counter; +} + +/* Transform a XID message (dst) into a list of XID fields */ +struct llist_head *gprs_llc_parse_xid(const void *ctx, const uint8_t *src, + int src_len) +{ + struct gprs_llc_xid_field *xid_field; + struct llist_head *xid_fields; + + int rc; + int max_loops = src_len; + + OSMO_ASSERT(src); + + xid_fields = talloc_zero(ctx, struct llist_head); + INIT_LLIST_HEAD(xid_fields); + + while (1) { + /* Bail in case decode_xid_field() constantly returns zero */ + if (max_loops <= 0) { + talloc_free(xid_fields); + return NULL; + } + + /* Decode XID field */ + xid_field = talloc_zero(xid_fields, struct gprs_llc_xid_field); + rc = decode_xid_field(xid_field, src, src_len); + + /* Immediately stop on error */ + if (rc < 0) { + talloc_free(xid_fields); + return NULL; + } + + /* Add parsed XID field to list */ + llist_add(&xid_field->list, xid_fields); + + /* Advance pointer and lower dst_len for the next + * decoding round */ + src += rc; + src_len -= rc; + + /* We are (scuccessfully) done when no further byes are left */ + if (src_len == 0) + return xid_fields; + + max_loops--; + } +} + +/* Free XID-list with including all its XID-Fields */ +struct llist_head *gprs_llc_free_xid(struct llist_head *xid_fields) +{ + if (xid_fields != NULL) + talloc_free(xid_fields); + return NULL; +} + +/* Create a duplicate of an XID-Field */ +struct gprs_llc_xid_field *gprs_llc_dup_xid_field(const void *ctx, const struct + gprs_llc_xid_field + *xid_field) +{ + struct gprs_llc_xid_field *duplicate_of_xid_field; + + OSMO_ASSERT(xid_field); + + /* Create a copy of the XID field in memory */ + duplicate_of_xid_field = talloc_zero(ctx, struct gprs_llc_xid_field); + memcpy(duplicate_of_xid_field, xid_field, + sizeof(struct gprs_llc_xid_field)); + duplicate_of_xid_field->data = + talloc_zero_size(duplicate_of_xid_field, xid_field->data_len); + memcpy(duplicate_of_xid_field->data, xid_field->data, + xid_field->data_len); + + /* Unlink duplicate from source list */ + INIT_LLIST_HEAD(&duplicate_of_xid_field->list); + + return duplicate_of_xid_field; +} + +/* Copy an llist with xid fields */ +struct llist_head *gprs_llc_copy_xid(const void *ctx, + const struct llist_head *xid_fields) +{ + struct gprs_llc_xid_field *xid_field; + struct llist_head *xid_fields_copy; + + OSMO_ASSERT(xid_fields); + + xid_fields_copy = talloc_zero(ctx, struct llist_head); + INIT_LLIST_HEAD(xid_fields_copy); + + /* Create duplicates and add them to the target list */ + llist_for_each_entry(xid_field, xid_fields, list) { + llist_add(&gprs_llc_dup_xid_field(ctx, xid_field)->list, + xid_fields_copy); + } + + return xid_fields_copy; +} + +/* Dump a list with XID fields (Debug) */ +void gprs_llc_dump_xid_fields(const struct llist_head *xid_fields, + unsigned int logl) +{ + struct gprs_llc_xid_field *xid_field; + + OSMO_ASSERT(xid_fields); + + llist_for_each_entry(xid_field, xid_fields, list) { + if (xid_field->data_len) { + OSMO_ASSERT(xid_field->data); + LOGP(DSNDCP, logl, + "XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + osmo_hexdump_nospc(xid_field->data, + xid_field->data_len)); + } else { + LOGP(DSNDCP, logl, + "XID: type=%i, data_len=%i, data=NULL\n", + xid_field->type, xid_field->data_len); + } + } +} diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index 09298a3..ba5ca28 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index dab9568..6470ab9 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -124,3 +124,8 @@ AT_CHECK([$abs_top_builddir/tests/mm_auth/mm_auth_test], [], [expout], [ignore]) AT_CLEANUP +AT_SETUP([xid]) +AT_KEYWORDS([xid]) +cat $abs_srcdir/xid/xid_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/xid/xid_test], [], [expout], [ignore]) +AT_CLEANUP diff --git a/openbsc/tests/xid/Makefile.am b/openbsc/tests/xid/Makefile.am new file mode 100644 index 0000000..9b64965 --- /dev/null +++ b/openbsc/tests/xid/Makefile.am @@ -0,0 +1,21 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) + +EXTRA_DIST = xid_test.ok + +noinst_PROGRAMS = xid_test + +xid_test_SOURCES = xid_test.c + +xid_test_LDADD = \ + $(top_builddir)/src/gprs/gprs_llc_xid.o \ + $(top_builddir)/src/libcommon/libcommon.a \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOGB_LIBS) \ + $(LIBCARES_LIBS) \ + $(LIBCRYPTO_LIBS) \ + -lgtp -lrt -lm + + diff --git a/openbsc/tests/xid/xid_test.c b/openbsc/tests/xid/xid_test.c new file mode 100644 index 0000000..d699059 --- /dev/null +++ b/openbsc/tests/xid/xid_test.c @@ -0,0 +1,158 @@ +/* Test LLC-XID Encoding/Decoding */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include + +#include +#include + +#include + +#include +#include + +/* Test XID encoding */ +static void test_xid_encode(const void *ctx) +{ + struct gprs_llc_xid_field xid_field_1; + struct gprs_llc_xid_field xid_field_2; + struct gprs_llc_xid_field xid_field_3; + struct gprs_llc_xid_field xid_field_4; + LLIST_HEAD(xid_fields); + uint8_t xid[255]; + uint8_t xid_expected[] = + { 0x10, 0x8c, 0x14, 0x43, 0x43, 0x43, 0x43, 0x43, 0x0b, 0x42, 0x42, + 0x42, 0x05, 0x41 }; + int rc; + + printf("Testing LLC XID-Encoder\n"); + + /* Setup some simple XID data */ + xid_field_1.type = 1; + xid_field_2.type = 2; + xid_field_3.type = 3; + xid_field_4.type = 4; + + xid_field_1.data = (uint8_t *) "A"; + xid_field_2.data = (uint8_t *) "BBB"; + xid_field_3.data = (uint8_t *) "CCCCC"; + xid_field_4.data = NULL; + + xid_field_1.data_len = 1; + xid_field_2.data_len = 3; + xid_field_3.data_len = 5; + xid_field_4.data_len = 0; + + llist_add(&xid_field_4.list, &xid_fields); + llist_add(&xid_field_3.list, &xid_fields); + llist_add(&xid_field_2.list, &xid_fields); + llist_add(&xid_field_1.list, &xid_fields); + + printf("Data to encode:\n"); + gprs_llc_dump_xid_fields(&xid_fields, DSNDCP); + + /* Encode data */ + rc = gprs_llc_compile_xid(xid, sizeof(xid), &xid_fields); + OSMO_ASSERT(rc == 14); + printf("Encoded: %s (%i bytes)\n", osmo_hexdump_nospc(xid, rc), rc); + printf("Expected: %s (%i bytes)\n", + osmo_hexdump_nospc(xid_expected, sizeof(xid_expected)), + (int)sizeof(xid_expected)); + + OSMO_ASSERT(memcmp(xid_expected, xid, sizeof(xid_expected)) == 0); + + printf("\n"); +} + +/* Test XID decoding */ +static void test_xid_decode(const void *ctx) +{ + struct llist_head *xid_fields; + int rc; + + printf("Testing LLC XID-Decoder/Encoder\n"); + + /* Example of a real world LLC-XID message */ + uint8_t xid[] = + { 0x01, 0x00, 0x16, 0x05, 0xf0, 0x1a, 0x05, 0xf0, 0xac, 0xd8, 0x00, + 0x01, 0x00, 0x02, 0x31, 0x82, 0x02, 0x27, 0x89, 0xff, 0xe0, 0x00, 0x0f, + 0x00, 0xa8, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x01, 0x02, + 0x00, 0x03, 0x01, 0x03, 0x00, 0x04, 0x01, 0x04, 0x00, 0x05, 0x01, 0x05, + 0x00, 0x06, 0x00, 0x07, 0x01, 0x07, 0x00, 0x08, 0x01, 0x08, 0x80, 0x00, + 0x04, 0x12, 0x00, 0x40, 0x07 }; + + uint8_t xid_r[512]; + + /* Decode and display XID fields */ + xid_fields = gprs_llc_parse_xid(ctx, xid, sizeof(xid)); + OSMO_ASSERT(xid_fields); + + printf("Decoded:\n"); + gprs_llc_dump_xid_fields(xid_fields, DSNDCP); + + + /* Encode xid-fields again */ + rc = gprs_llc_compile_xid(xid_r, sizeof(xid_r), xid_fields); + printf("Result length=%i\n",rc); + printf("Encoded: %s\n", osmo_hexdump_nospc(xid, sizeof(xid))); + printf("Rencoded: %s\n", osmo_hexdump_nospc(xid_r, rc)); + + OSMO_ASSERT(rc == 64); + OSMO_ASSERT(memcmp(xid, xid_r, sizeof(xid)) == 0); + + /* Free xid fields */ + gprs_llc_free_xid(xid_fields); + + printf("\n"); +} + +static struct log_info_cat gprs_categories[] = { + [DSNDCP] = { + .name = "DSNDCP", + .description = + "GPRS Sub-Network Dependent Control Protocol (SNDCP)", + .enabled = 1,.loglevel = LOGL_DEBUG, + } +}; + +static struct log_info info = { + .cat = gprs_categories, + .num_cat = ARRAY_SIZE(gprs_categories), +}; + +int main(int argc, char **argv) +{ + void *xid_ctx; + + osmo_init_logging(&info); + + xid_ctx = talloc_named_const(NULL, 0, "xid_ctx"); + + test_xid_decode(xid_ctx); + test_xid_encode(xid_ctx); + printf("Done\n"); + + talloc_report_full(xid_ctx, stderr); + OSMO_ASSERT(talloc_total_blocks(xid_ctx) == 1); + return 0; +} diff --git a/openbsc/tests/xid/xid_test.ok b/openbsc/tests/xid/xid_test.ok new file mode 100644 index 0000000..4cf825c --- /dev/null +++ b/openbsc/tests/xid/xid_test.ok @@ -0,0 +1,12 @@ +Testing LLC XID-Decoder/Encoder +Decoded: +Result length=64 +Encoded: 01001605f01a05f0acd8000100023182022789ffe0000f00a8000000010101000201020003010300040104000501050006000701070008010880000412004007 +Rencoded: 01001605f01a05f0acd8000100023182022789ffe0000f00a8000000010101000201020003010300040104000501050006000701070008010880000412004007 + +Testing LLC XID-Encoder +Data to encode: +Encoded: 108c1443434343430b4242420541 (14 bytes) +Expected: 108c1443434343430b4242420541 (14 bytes) + +Done -- To view, visit https://gerrit.osmocom.org/638 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia06e4cb08bf9b48c2a4682606d1b1a91d19a9d37 Gerrit-PatchSet: 7 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Wed Aug 10 16:18:12 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Wed, 10 Aug 2016 16:18:12 +0000 Subject: [PATCH] osmo-bts[master]: Log channel combination name instead of number Message-ID: Review at https://gerrit.osmocom.org/685 Log channel combination name instead of number Change-Id: Ife11cfdb0f83d56ed61e66286a79b7c3a000cce5 --- M src/osmo-bts-sysmo/femtobts.h M src/osmo-bts-sysmo/oml.c 2 files changed, 4 insertions(+), 3 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/85/685/1 diff --git a/src/osmo-bts-sysmo/femtobts.h b/src/osmo-bts-sysmo/femtobts.h index 8be198f..9163ebb 100644 --- a/src/osmo-bts-sysmo/femtobts.h +++ b/src/osmo-bts-sysmo/femtobts.h @@ -83,7 +83,7 @@ const struct value_string femtobts_tracef_docs[29]; const struct value_string femtobts_tch_pl_names[15]; - +const struct value_string femtobts_chcomb_names[8]; const struct value_string femtobts_clksrc_names[10]; const struct value_string femtobts_dir_names[6]; diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c index e9a4794..86e2bee 100644 --- a/src/osmo-bts-sysmo/oml.c +++ b/src/osmo-bts-sysmo/oml.c @@ -504,9 +504,10 @@ cr->u8Tn = ts->nr; cr->logChComb = pchan_to_logChComb[pchan]; - DEBUGP(DL1C, "%s pchan=%s ts_connect_as(%s) logChComb=%d\n", + DEBUGP(DL1C, "%s pchan=%s ts_connect_as(%s) logChComb=%s\n", gsm_lchan_name(ts->lchan), gsm_pchan_name(ts->pchan), - gsm_pchan_name(pchan), cr->logChComb); + gsm_pchan_name(pchan), get_value_string(femtobts_chcomb_names, + cr->logChComb)); return l1if_gsm_req_compl(fl1h, msg, cb, NULL); } -- To view, visit https://gerrit.osmocom.org/685 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ife11cfdb0f83d56ed61e66286a79b7c3a000cce5 Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Max From gerrit-no-reply at lists.osmocom.org Wed Aug 10 16:43:53 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Wed, 10 Aug 2016 16:43:53 +0000 Subject: osmo-bts[master]: sysmo: fix dyn TS: Revert "Activate PTCCH UL" [in sysmobts] In-Reply-To: References: Message-ID: Patch Set 2: Let's continue discussion in http://projects.osmocom.org/issues/1796 -- To view, visit https://gerrit.osmocom.org/671 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia59d95c75a8a5d3bd596f55cd1dc0906a6a95f7f Gerrit-PatchSet: 2 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 10 17:15:10 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 10 Aug 2016 17:15:10 +0000 Subject: openbsc[master]: Adding SNDCP-XID encoder / decoder In-Reply-To: References: Message-ID: Patch Set 8: Code-Review-1 (16 comments) https://gerrit.osmocom.org/#/c/641/8//COMMIT_MSG Commit Message: Line 7: Adding SNDCP-XID encoder / decoder "Add SNDCP-XID encoder / decoder and unit test" https://gerrit.osmocom.org/#/c/641/8/openbsc/src/gprs/gprs_sndcp_xid.c File openbsc/src/gprs/gprs_sndcp_xid.c: Line 1635: return NULL; missing free of comp_fields in case of error Line 1641: return NULL; Though this also looks like a missing free of comp_fields in case of error, it actually isn't, because gprs_sndcp_decode_xid() does the talloc_free on comp_fields. While this is technically correct, I would prefer if you would always free comp_fields in this function instead of delegating to each and every error case of called functions. So, let the other return error, and here have e.g.: gprs_sndcp_parse_xid() { rc = gprs_sndcp_foo(...); if (rc) goto error_free_comp_fields rc = gprs_sndcp_bar(...); if (rc) goto error_free_comp_fields [...] return comp_fields; error_free_comp_fields: talloc_free(comp_fields); return NULL; } If you grep for goto, you will find numerous instances of this kind of error handling ... and this is the *only* way we use goto :) https://www.xkcd.com/292/ Line 1646: return NULL; same Line 1652: return NULL; same Line 1660: { personally, I would just call talloc_free(comp_fields) and drop this function. The callers generally can expect comp_fields to never be null. Line 1868: LOGP(DSNDCP, logl, "\n"); really log a blank line? :) https://gerrit.osmocom.org/#/c/641/8/openbsc/tests/sgsn/Makefile.am File openbsc/tests/sgsn/Makefile.am: Line 34: $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ sgsn-test is not using this, no need to add anything Line 42: -lgtp -lrt -lm this is not needed either https://gerrit.osmocom.org/#/c/641/8/openbsc/tests/testsuite.at File openbsc/tests/testsuite.at: Line 136: AT_CHECK([$abs_top_builddir/tests/xid_sndcp/sndcp_xid_test], [], [expout], [ignore]) ah, so you decided against checking stderr. Line 138: rather not add a blank line in the end https://gerrit.osmocom.org/#/c/641/8/openbsc/tests/xid_sndcp/Makefile.am File openbsc/tests/xid_sndcp/Makefile.am: Line 20: I know it's nitpicking, but generally we're pretty tight on whitespace in osmocom code ... drop the blank lines at EOF. https://gerrit.osmocom.org/#/c/641/8/openbsc/tests/xid_sndcp/sndcp_xid_test.c File openbsc/tests/xid_sndcp/sndcp_xid_test.c: Line 54: gprs_sndcp_dump_comp_fields(comp_fields, DSNDCP); would be nice to check this dump in experr? Line 60: printf("Rencoded: %s\n", osmo_hexdump_nospc(xid_r, rc)); "Reencoded" / "Re-encoded"? Line 240: gprs_sndcp_dump_comp_fields(comp_fields_dec, DSNDCP); again check this in experr? Line 276: } you need to add a stub for bssgp_prim_cb like in sgsn_test.c: /* stubs */ struct osmo_prim_hdr; int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) { abort(); } -- To view, visit https://gerrit.osmocom.org/641 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e Gerrit-PatchSet: 8 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Wed Aug 10 17:15:57 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 10 Aug 2016 17:15:57 +0000 Subject: openbsc[master]: Adding LLC-XID encoder / decoder In-Reply-To: References: Message-ID: Patch Set 7: Code-Review-1 (6 comments) https://gerrit.osmocom.org/#/c/638/7//COMMIT_MSG Commit Message: Line 7: Adding LLC-XID encoder / decoder "Add [...] and unit test" https://gerrit.osmocom.org/#/c/638/7/openbsc/include/openbsc/gprs_llc_xid.h File openbsc/include/openbsc/gprs_llc_xid.h: Line 53: gprs_llc_xid_field I'd prefer if you kept each argument within one line, as in, each line ends with a comma or a ')'. Instead remove some indenting if you need to for 80 chars width. https://gerrit.osmocom.org/#/c/638/7/openbsc/tests/xid/xid_test.c File openbsc/tests/xid/xid_test.c: Line 111: gprs_llc_dump_xid_fields(xid_fields, DSNDCP); check output in experr? Line 113: (whitespace) Line 119: (whitespace) Line 159 you need to add a stub for bssgp_prim_cb like in sgsn_test.c: /* stubs */ struct osmo_prim_hdr; int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) { abort(); } -- To view, visit https://gerrit.osmocom.org/638 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia06e4cb08bf9b48c2a4682606d1b1a91d19a9d37 Gerrit-PatchSet: 7 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Wed Aug 10 17:16:23 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 10 Aug 2016 17:16:23 +0000 Subject: [MERGED] osmo-bts[master]: sysmo, lc15: ts_connect_as(): log error also for pchan_as == ... In-Reply-To: References: Message-ID: Neels Hofmeyr has submitted this change and it was merged. Change subject: sysmo,lc15: ts_connect_as(): log error also for pchan_as == TCH/F_PDCH ...................................................................... sysmo,lc15: ts_connect_as(): log error also for pchan_as == TCH/F_PDCH Change-Id: I76c868a1e70af16268a6fa42dc736cf0b288ecdb --- M src/osmo-bts-litecell15/oml.c M src/osmo-bts-sysmo/oml.c 2 files changed, 4 insertions(+), 2 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/src/osmo-bts-litecell15/oml.c b/src/osmo-bts-litecell15/oml.c index 8b1f195..5ce510a 100644 --- a/src/osmo-bts-litecell15/oml.c +++ b/src/osmo-bts-litecell15/oml.c @@ -488,7 +488,8 @@ struct lc15l1_hdl *fl1h = trx_lc15l1_hdl(ts->trx); GsmL1_MphConnectReq_t *cr; - if (pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) { + if (pchan == GSM_PCHAN_TCH_F_PDCH + || pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) { LOGP(DL1C, LOGL_ERROR, "%s Requested TS connect as %s," " expected a specific pchan instead\n", diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c index e9a4794..9beba43 100644 --- a/src/osmo-bts-sysmo/oml.c +++ b/src/osmo-bts-sysmo/oml.c @@ -491,7 +491,8 @@ struct femtol1_hdl *fl1h = trx_femtol1_hdl(ts->trx); GsmL1_MphConnectReq_t *cr; - if (pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) { + if (pchan == GSM_PCHAN_TCH_F_PDCH + || pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) { LOGP(DL1C, LOGL_ERROR, "%s Requested TS connect as %s," " expected a specific pchan instead\n", -- To view, visit https://gerrit.osmocom.org/674 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I76c868a1e70af16268a6fa42dc736cf0b288ecdb Gerrit-PatchSet: 2 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Wed Aug 10 17:16:24 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 10 Aug 2016 17:16:24 +0000 Subject: [MERGED] osmo-bts[master]: dyn TS: measurement.c: replace fixme with comment In-Reply-To: References: Message-ID: Neels Hofmeyr has submitted this change and it was merged. Change subject: dyn TS: measurement.c: replace fixme with comment ...................................................................... dyn TS: measurement.c: replace fixme with comment Change-Id: I04668f6f01a48157a98c6326a9ee48982a09ee62 --- M src/common/measurement.c 1 file changed, 1 insertion(+), 1 deletion(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/src/common/measurement.c b/src/common/measurement.c index b0906d4..d0b84d5 100644 --- a/src/common/measurement.c +++ b/src/common/measurement.c @@ -210,8 +210,8 @@ [GSM_PCHAN_TCH_H] = 2, [GSM_PCHAN_SDCCH8_SACCH8C] = 8, [GSM_PCHAN_SDCCH8_SACCH8C_CBCH] = 8, - /* FIXME: what about dynamic TCH_F_TCH_H ? */ [GSM_PCHAN_TCH_F_PDCH] = 1, + /* dynamic pchan are handled outside of this array */ }; static int ts_meas_check_compute(struct gsm_bts_trx_ts *ts, uint32_t fn) -- To view, visit https://gerrit.osmocom.org/673 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I04668f6f01a48157a98c6326a9ee48982a09ee62 Gerrit-PatchSet: 2 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Wed Aug 10 17:16:24 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 10 Aug 2016 17:16:24 +0000 Subject: [MERGED] osmo-bts[master]: dyn TS: complete for TRX In-Reply-To: References: Message-ID: Neels Hofmeyr has submitted this change and it was merged. Change subject: dyn TS: complete for TRX ...................................................................... dyn TS: complete for TRX Apply similar fixes as for TCH/F_PDCH also for TCH/F_TCH/H_PDCH: Detect dyn TS in PDCH mode in ts_is_pdch(). In trx_set_ts(), enhance the "if (TCH_F_PDCH)" to a switch statement including both dynamic channel types. Adjust the comment to include both kinds. Change-Id: I6669739cd08780cd9ffb9451cdae9f6b9704c4fe --- M src/common/l1sap.c M src/osmo-bts-trx/l1_if.c 2 files changed, 22 insertions(+), 8 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 304f718..6498103 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -299,7 +299,10 @@ return ts->pchan == GSM_PCHAN_PDCH || (ts->pchan == GSM_PCHAN_TCH_F_PDCH && (ts->flags & TS_F_PDCH_ACTIVE) - && !(ts->flags & TS_F_PDCH_PENDING_MASK)); + && !(ts->flags & TS_F_PDCH_PENDING_MASK)) + || (ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH + && ts->dyn.pchan_want == ts->dyn.pchan_is + && ts->dyn.pchan_is == GSM_PCHAN_PDCH); } static int to_gsmtap(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) diff --git a/src/osmo-bts-trx/l1_if.c b/src/osmo-bts-trx/l1_if.c index 4d6dc3f..b89a359 100644 --- a/src/osmo-bts-trx/l1_if.c +++ b/src/osmo-bts-trx/l1_if.c @@ -398,9 +398,10 @@ if (!(l1h->config.slotmask & (1 << tn))) return NM_NACK_RES_NOTAVAIL; - /* set physical channel. For dynamic TCH/F_PDCH, the caller should have + /* set physical channel. For dynamic timeslots, the caller should have * decided on a more specific PCHAN type already. */ OSMO_ASSERT(pchan != GSM_PCHAN_TCH_F_PDCH); + OSMO_ASSERT(pchan != GSM_PCHAN_TCH_F_TCH_H_PDCH); rc = trx_sched_set_pchan(&l1h->l1s, tn, pchan); if (rc) return NM_NACK_RES_NOTAVAIL; @@ -426,15 +427,25 @@ static uint8_t trx_set_ts(struct gsm_bts_trx_ts *ts) { - enum gsm_phys_chan_config pchan = ts->pchan; + enum gsm_phys_chan_config pchan; - /* For dynamic TCH/F_PDCH, pick the pchan type that should currently be - * active according to TS flags. This should only be called during - * init, PDCH transitions will call trx_set_ts_as_pchan() directly. */ - OSMO_ASSERT((ts->flags & TS_F_PDCH_PENDING_MASK) == 0); - if (pchan == GSM_PCHAN_TCH_F_PDCH) + /* For dynamic timeslots, pick the pchan type that should currently be + * active. This should only be called during init, PDCH transitions + * will call trx_set_ts_as_pchan() directly. */ + switch (ts->pchan) { + case GSM_PCHAN_TCH_F_PDCH: + OSMO_ASSERT((ts->flags & TS_F_PDCH_PENDING_MASK) == 0); pchan = (ts->flags & TS_F_PDCH_ACTIVE)? GSM_PCHAN_PDCH : GSM_PCHAN_TCH_F; + break; + case GSM_PCHAN_TCH_F_TCH_H_PDCH: + OSMO_ASSERT(ts->dyn.pchan_is == ts->dyn.pchan_want); + pchan = ts->dyn.pchan_is; + break; + default: + pchan = ts->pchan; + break; + } return trx_set_ts_as_pchan(ts, pchan); } -- To view, visit https://gerrit.osmocom.org/672 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I6669739cd08780cd9ffb9451cdae9f6b9704c4fe Gerrit-PatchSet: 2 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Wed Aug 10 17:18:45 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 10 Aug 2016 17:18:45 +0000 Subject: openbsc[master]: move ts_sublots() to gsm_data_shared.c, it will be used by o... In-Reply-To: References: Message-ID: Patch Set 1: patch 675 (plus two more) depend on this patch, so a review would be appreciated :) -- To view, visit https://gerrit.osmocom.org/669 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I8ba06d7dd6e0ceab3d8d18bb565354d6ed461f7e Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 11 05:46:38 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 11 Aug 2016 05:46:38 +0000 Subject: openbsc[master]: gsm_ts2chan_nr(): use constants instead of magic numbers In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+1 -- To view, visit https://gerrit.osmocom.org/625 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I0392d179f98842d75eee586161e0aa014337f9ab Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 11 05:49:02 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 11 Aug 2016 05:49:02 +0000 Subject: osmo-pcu[master]: Add data structure to handle SPB for EGPRS DL In-Reply-To: References: Message-ID: Patch Set 2: Code-Review+1 -- To view, visit https://gerrit.osmocom.org/654 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I57673e53a9da2affa7e8aaa6551ac4b271c3d525 Gerrit-PatchSet: 2 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 11 05:54:58 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 11 Aug 2016 05:54:58 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 10: (2 comments) https://gerrit.osmocom.org/#/c/655/10/src/pcu_vty.c File src/pcu_vty.c: PS10, Line 133: why the extra space at the end of the line? we never use this anywhere else when writing config files, as far as i know. https://gerrit.osmocom.org/#/c/655/10/src/rlc.cpp File src/rlc.cpp: PS10, Line 427: 3 where is the '3' defined here? How does it relate to the comment above? i.e. where should the reader know from that '3' indicates "second segment of block"? I don't know the GPRS related specs, but if it is some kind of enumeration, an actual enum or #define might be useful. -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 10 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 11 05:58:42 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 11 Aug 2016 05:58:42 +0000 Subject: osmo-bts[master]: Update parameters in osmo-bts-sysmo for 11bit RACH In-Reply-To: References: Message-ID: Patch Set 5: Code-Review-1 (1 comment) https://gerrit.osmocom.org/#/c/434/5/src/osmo-bts-sysmo/l1_if.c File src/osmo-bts-sysmo/l1_if.c: Line 987: case GsmL1_BurstType_Access_0 : we don't indendt the 'case' within a 'switch', please see all the existing code for reference. -- To view, visit https://gerrit.osmocom.org/434 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I93831ddfb3f31b637e6a576f23a9bb4557758582 Gerrit-PatchSet: 5 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: bhargava_abhyankar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 11 06:01:52 2016 From: gerrit-no-reply at lists.osmocom.org (prasadkg) Date: Thu, 11 Aug 2016 06:01:52 +0000 Subject: [PATCH] osmo-pcu[master]: Add test case for testing PUAN In-Reply-To: References: Message-ID: Hello Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/414 to look at the new patch set (#2). Add test case for testing PUAN This test case is for testing generation of EGPRS PUAN. Corresponding log files .ok and .err are modified. Change-Id: I18e6d4a9e90fd6453fe14187beab27dfeae8dbe9 --- M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 3 files changed, 451 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/14/414/2 diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..e280694 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -1069,6 +1069,142 @@ return ul_tbf; } +static gprs_rlcmac_ul_tbf *establish_ul_tbf_two_phase_puan(BTS *the_bts, + uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, + uint8_t ms_class, uint8_t egprs_ms_class) +{ + GprsMs *ms; + uint32_t rach_fn = *fn - 51; + uint32_t sba_fn = *fn + 52; + uint8_t trx_no = 0; + int tfi = 0; + gprs_rlcmac_ul_tbf *ul_tbf; + struct gprs_rlcmac_pdch *pdch; + gprs_rlcmac_bts *bts; + RlcMacUplink_t ulreq = {0}; + struct pcu_l1_meas meas; + + meas.set_rssi(31); + bts = the_bts->bts_data(); + + /* needed to set last_rts_fn in the PDCH object */ + request_dl_rlc_block(bts, trx_no, ts_no, fn); + + /* simulate RACH, this sends an Immediate Assignment + Uplink on the AGCH */ + the_bts->rcv_rach(0x73, rach_fn, qta); + + /* get next free TFI */ + tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1); + + /* fake a resource request */ + ulreq.u.MESSAGE_TYPE = MT_PACKET_RESOURCE_REQUEST; + ulreq.u.Packet_Resource_Request.PayloadType = GPRS_RLCMAC_CONTROL_BLOCK; + ulreq.u.Packet_Resource_Request.ID.UnionType = 1; /* != 0 */ + ulreq.u.Packet_Resource_Request.ID.u.TLLI = tlli; + ulreq.u.Packet_Resource_Request.Exist_MS_Radio_Access_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + Count_MS_RA_capability_value = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Exist_Multislot_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + Exist_GPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + GPRS_multislot_class = ms_class; + if (egprs_ms_class) { + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + Exist_EGPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + EGPRS_multislot_class = ms_class; + } + + send_ul_mac_block(the_bts, trx_no, ts_no, &ulreq, sba_fn); + + /* check the TBF */ + ul_tbf = the_bts->ul_tbf_by_tfi(tfi, trx_no, ts_no); + OSMO_ASSERT(ul_tbf != NULL); + OSMO_ASSERT(ul_tbf->ta() == qta / 4); + + /* send packet uplink assignment */ + *fn = sba_fn; + request_dl_rlc_block(ul_tbf, fn); + + /* send real acknowledgement */ + send_control_ack(ul_tbf); + + check_tbf(ul_tbf); + + /* send fake data with cv=0*/ + struct gprs_rlc_ul_header_egprs_3 *hdr3 = NULL; + uint8_t data[49] = {0}; + + hdr3 = (struct gprs_rlc_ul_header_egprs_3 *)data; + + /*header_construction */ + memset(data, 0x2b, sizeof(data)); + + for (int i = 0 ; i < 20; i++) { + hdr3->r = 0; + hdr3->si = 0; + hdr3->cv = 10; + hdr3->tfi_hi = (tfi >> 3) & 0x3; + hdr3->tfi_lo = tfi & 0x7; + hdr3->bsn1_hi = ((i*2)&0x1f); + hdr3->bsn1_lo = ((i*2)/32); + hdr3->cps_hi = 0; + hdr3->cps_lo = 0; + hdr3->spb = 0; + hdr3->rsb = 0; + hdr3->pi = 0; + hdr3->spare = 0; + hdr3->dummy = 1; + data[4] = 0x0; + data[5] = 0x0; + data[6] = 0x2b; + data[7] = 0x2b; + pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no]; + pdch->rcv_block(&data[0], sizeof(data), *fn, &meas); + } + memset(data, 0x2b, sizeof(data)); + hdr3 = (struct gprs_rlc_ul_header_egprs_3 *)data; + hdr3->r = 0; + hdr3->si = 0; + hdr3->cv = 0; + hdr3->tfi_hi = (tfi >> 3) & 0x3; + hdr3->tfi_lo = tfi & 0x7; + hdr3->bsn1_hi = 0; + hdr3->bsn1_lo = 2; + hdr3->cps_hi = 0; + hdr3->cps_lo = 0; + hdr3->spb = 0; + hdr3->rsb = 0; + hdr3->pi = 0; + hdr3->spare = 0; + hdr3->dummy = 1; + data[4] = 0x0; + data[5] = 0x2b; + data[6] = 0x2b; + data[7] = 0x2b; + pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no]; + pdch->rcv_block(&data[0], sizeof(data), *fn, &meas); + + request_dl_rlc_block(ul_tbf, fn); + + check_tbf(ul_tbf); + OSMO_ASSERT(ul_tbf->ul_ack_state == GPRS_RLCMAC_UL_ACK_NONE); + + ms = the_bts->ms_by_tlli(tlli); + OSMO_ASSERT(ms != NULL); + OSMO_ASSERT(ms->ta() == qta/4); + OSMO_ASSERT(ms->ul_tbf() == ul_tbf); + + return ul_tbf; +} + static gprs_rlcmac_ul_tbf *establish_ul_tbf_two_phase(BTS *the_bts, uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, uint8_t ms_class, uint8_t egprs_ms_class) @@ -1226,6 +1362,40 @@ printf("=== end %s ===\n", __func__); } +static void test_tbf_egprs_two_phase_puan(void) +{ + BTS the_bts; + int ts_no = 7; + uint32_t fn = 2654218; + uint16_t qta = 31; + uint32_t tlli = 0xf1223344; + const char *imsi = "0011223344"; + uint8_t ms_class = 1; + uint8_t egprs_ms_class = 1; + gprs_rlcmac_ul_tbf *ul_tbf; + GprsMs *ms; + uint8_t test_data[256]; + + printf("=== start %s ===\n", __func__); + + memset(test_data, 1, sizeof(test_data)); + + setup_bts(&the_bts, ts_no, 4); + the_bts.bts_data()->initial_mcs_dl = 9; + the_bts.bts_data()->initial_mcs_ul = 9; + the_bts.bts_data()->egprs_enabled = 1; + + ul_tbf = establish_ul_tbf_two_phase_puan(&the_bts, ts_no, tlli, &fn, + qta, ms_class, egprs_ms_class); + + ms = ul_tbf->ms(); + fprintf(stderr, "Got '%s', TA=%d\n", ul_tbf->name(), ul_tbf->ta()); + fprintf(stderr, "Got MS: TLLI = 0x%08x, TA = %d\n", ms->tlli(), ms->ta()); + + send_dl_data(&the_bts, tlli, imsi, test_data, sizeof(test_data)); + + printf("=== end %s ===\n", __func__); +} static void test_tbf_two_phase() { BTS the_bts; @@ -2071,7 +2241,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); - + test_tbf_egprs_two_phase_puan(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); return EXIT_SUCCESS; diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..e5c0a78 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -5780,3 +5780,281 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654218 block=8 data=47 94 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +MS requests UL TBF on RACH, so we provide one: +MS requests single block allocation +RX: [PCU <- BTS] RACH qbit-ta=31 ra=0x73, Fn=2654167 (17,25,9), SBFn=2654270 +TX: Immediate Assignment Uplink (AGCH) + - TRX=0 (0) TS=7 TA=7 TSC=0 TFI=-1 USF=7 +Sending data request: trx=0 ts=0 sapi=2 arfcn=0 fn=0 block=0 data=2d 06 3f 10 0f 00 00 73 8b 29 07 00 c0 0c 5a 43 2b 2b 2b 2b 2b 2b 2b +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +MS requests UL TBF in packet resource request of single block, so we provide one: +MS supports EGPRS multislot class 1. +********** TBF starts here ********** +Allocating UL TBF: MS_CLASS=1/1 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 1 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 1 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign uplink TS=7 TFI=0 USF=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 00 +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=ASSIGN EGPRS) starting timer 3169. +Modifying MS object, UL TLLI: 0x00000000 -> 0xf1223344, not yet confirmed +Modifying MS object, TLLI = 0xf1223344, TA 0 -> 7 +Change control TS to 7 until assinment is complete. +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS)s start Packet Uplink Assignment (PACCH) ++++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++ +------------------------- TX : Packet Uplink Assignment ------------------------- +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS): Scheduling polling at FN 2654283 TS 7 +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS) changes state from ASSIGN to WAIT ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Scheduled UL Assignment polling on FN=2654283, TS=7 +Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) (TRX=0, TS=7) +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654270 block=8 data=4f 28 5e 24 46 68 90 88 0a 39 00 00 88 00 08 2b 2b 2b 2b 2b 2b 2b 2b +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Packet Control Ack +TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) changes state from WAIT ASSIGN to FLOW +Got RLC block, coding scheme: MCS-4, length: 49 (49)) + UL data: 28 00 00 80 00 00 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got MCS-4 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=385 +UL DATA TFI=0 received (V(Q)=0 .. V(R)=0) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-4 RLC data block: CV=10, BSN=0, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 0 storing in window (0..63) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=44, data=00 80 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 +- Raising V(R) to 1 +- Taking block 0 out, raising V(Q) to 1 +- Assembling frames: (len=44) +-- Frame 1 starts at offset 0, length=44, is_complete=0 +- No gaps in received block, last block: BSN=0 CV=10 +Got RLC block, coding scheme: MCS-4, length: 49 (49)) + UL data: 28 10 00 80 00 00 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got MCS-4 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=385 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=1) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-4 RLC data block: CV=10, BSN=2, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 2 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=44, data=00 80 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 +- Raising V(R) to 3 +Got RLC block, coding scheme: MCS-4, length: 49 (49)) + UL data: 28 20 00 80 00 00 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got MCS-4 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=385 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=3) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-4 RLC data block: CV=10, BSN=4, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 4 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=44, data=00 80 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 +- Raising V(R) to 5 +Got RLC block, coding scheme: MCS-4, length: 49 (49)) + UL data: 28 30 00 80 00 00 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got MCS-4 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=385 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=5) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-4 RLC data block: CV=10, BSN=6, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 6 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=44, data=00 80 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 +- Raising V(R) to 7 +Got RLC block, coding scheme: MCS-4, length: 49 (49)) + UL data: 28 40 00 80 00 00 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got MCS-4 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=385 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=7) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-4 RLC data block: CV=10, BSN=8, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 8 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=44, data=00 80 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 +- Raising V(R) to 9 +Got RLC block, coding scheme: MCS-4, length: 49 (49)) + UL data: 28 50 00 80 00 00 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got MCS-4 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=385 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=9) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-4 RLC data block: CV=10, BSN=10, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 10 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=44, data=00 80 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 +- Raising V(R) to 11 +Got RLC block, coding scheme: MCS-4, length: 49 (49)) + UL data: 28 60 00 80 00 00 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got MCS-4 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=385 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=11) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-4 RLC data block: CV=10, BSN=12, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 12 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=44, data=00 80 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 +- Raising V(R) to 13 +Got RLC block, coding scheme: MCS-4, length: 49 (49)) + UL data: 28 70 00 80 00 00 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got MCS-4 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=385 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=13) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-4 RLC data block: CV=10, BSN=14, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 14 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=44, data=00 80 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 +- Raising V(R) to 15 +Got RLC block, coding scheme: MCS-4, length: 49 (49)) + UL data: 28 80 00 80 00 00 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got MCS-4 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=385 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=15) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-4 RLC data block: CV=10, BSN=16, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 16 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=44, data=00 80 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 +- Raising V(R) to 17 +Got RLC block, coding scheme: MCS-4, length: 49 (49)) + UL data: 28 90 00 80 00 00 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got MCS-4 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=385 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=17) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-4 RLC data block: CV=10, BSN=18, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 18 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=44, data=00 80 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 +- Raising V(R) to 19 +Got RLC block, coding scheme: MCS-4, length: 49 (49)) + UL data: 28 a0 00 80 00 00 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got MCS-4 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=385 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=19) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-4 RLC data block: CV=10, BSN=20, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 20 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=44, data=00 80 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 +- Raising V(R) to 21 +Got RLC block, coding scheme: MCS-4, length: 49 (49)) + UL data: 28 b0 00 80 00 00 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got MCS-4 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=385 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=21) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-4 RLC data block: CV=10, BSN=22, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 22 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=44, data=00 80 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 +- Raising V(R) to 23 +Got RLC block, coding scheme: MCS-4, length: 49 (49)) + UL data: 28 c0 00 80 00 00 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got MCS-4 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=385 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=23) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-4 RLC data block: CV=10, BSN=24, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 24 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=44, data=00 80 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 +- Raising V(R) to 25 +Got RLC block, coding scheme: MCS-4, length: 49 (49)) + UL data: 28 d0 00 80 00 00 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got MCS-4 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=385 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=25) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-4 RLC data block: CV=10, BSN=26, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 26 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=44, data=00 80 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 +- Raising V(R) to 27 +Got RLC block, coding scheme: MCS-4, length: 49 (49)) + UL data: 28 e0 00 80 00 00 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got MCS-4 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=385 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=27) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-4 RLC data block: CV=10, BSN=28, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 28 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=44, data=00 80 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 +- Raising V(R) to 29 +Got RLC block, coding scheme: MCS-4, length: 49 (49)) + UL data: 28 f0 00 80 00 00 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got MCS-4 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=385 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=29) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-4 RLC data block: CV=10, BSN=30, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 30 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=44, data=00 80 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 +- Raising V(R) to 31 +Got RLC block, coding scheme: MCS-4, length: 49 (49)) + UL data: 28 00 01 80 00 00 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got MCS-4 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=385 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=31) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-4 RLC data block: CV=10, BSN=32, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 32 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=44, data=00 80 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 +- Raising V(R) to 33 +Got RLC block, coding scheme: MCS-4, length: 49 (49)) + UL data: 28 10 01 80 00 00 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got MCS-4 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=385 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=33) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-4 RLC data block: CV=10, BSN=34, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 34 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=44, data=00 80 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 +- Raising V(R) to 35 +Got RLC block, coding scheme: MCS-4, length: 49 (49)) + UL data: 28 20 01 80 00 00 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got MCS-4 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=385 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=35) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-4 RLC data block: CV=10, BSN=36, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 36 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=44, data=00 80 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 +- Raising V(R) to 37 +Got RLC block, coding scheme: MCS-4, length: 49 (49)) + UL data: 28 30 01 80 00 00 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got MCS-4 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=385 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=37) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-4 RLC data block: CV=10, BSN=38, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 38 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=44, data=00 80 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 +- Raising V(R) to 39 +- Scheduling Ack/Nack, because 20 frames received. +Got RLC block, coding scheme: MCS-4, length: 49 (49)) + UL data: 00 00 02 80 00 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got MCS-4 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=385 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=39) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-4 RLC data block: CV=0, BSN=64, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 64 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=44, data=80 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 +- Raising V(R) to 65 +Received RTS for PDCH: TRX=0 TS=7 FN=2654275 block_nr=9 scheduling USF=0 for required uplink resource of UL TFI=0 +Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) + - EGPRS URBB, len = 0, SSN = 2, ESN_CRBB = 1, SNS = 2048, WS = 64, V(Q) = 1, V(R) = 65, BOW, EOW +Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 23 3e 24 46 68 90 87 b0 04 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (TRX=0, TS=7) +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654275 block=9 data=40 24 01 23 3e 24 46 68 90 87 b0 04 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got 'TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS)', TA=7 +Got MS: TLLI = 0xf1223344, TA = 7 +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=1/1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign downlink TS=7 TFI=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0xf1223344, TBF = TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 80 +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +Modifying MS object, TLLI: 0xf1223344 confirmed +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) [DOWNLINK] START +Modifying MS object, TLLI = 0xf1223344, IMSI '' -> '0011223344' +Send dowlink assignment on PACCH, because TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) exists +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) starting timer 0. +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) append diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..3c38148 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,5 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_egprs_two_phase_puan === +=== end test_tbf_egprs_two_phase_puan === -- To view, visit https://gerrit.osmocom.org/414 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I18e6d4a9e90fd6453fe14187beab27dfeae8dbe9 Gerrit-PatchSet: 2 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: prasadkg Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: prasadkg From gerrit-no-reply at lists.osmocom.org Thu Aug 11 06:04:10 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 11 Aug 2016 06:04:10 +0000 Subject: libosmocore[master]: Add function to send TRAP over Control Interface In-Reply-To: References: Message-ID: Patch Set 1: (1 comment) https://gerrit.osmocom.org/#/c/649/1/src/ctrl/control_if.c File src/ctrl/control_if.c: Line 126: int ctrl_cmd_send_trap(struct ctrl_handle *ctrl, char *name, char *value) > why mutable? Who owns name and value? I think the problem is that 'struct ctrl_cmd' doesn't define its name and value as 'const char *', but rather as 'char *'. I'm not sure of all parts using the code would be happy with const-ifying it? -- To view, visit https://gerrit.osmocom.org/649 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ic0b8d88c4f5c4d42c3f8fb754f8eabf049c9e388 Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 11 06:04:33 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 11 Aug 2016 06:04:33 +0000 Subject: openbsc[master]: chan_alloc.c: use ts_subslots() instead of subslots_per_pchan[] In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+1 -- To view, visit https://gerrit.osmocom.org/668 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Icbea7dbd78abf6144e5291f531a97f96507d8cbf Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 11 06:04:47 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 11 Aug 2016 06:04:47 +0000 Subject: openbsc[master]: dyn TS: bts_chan_load: use correct nr of subslots for dyn ts In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+1 -- To view, visit https://gerrit.osmocom.org/667 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I659acebca82dfb3e305433471be64e9d27439af8 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 11 06:05:08 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 11 Aug 2016 06:05:08 +0000 Subject: openbsc[master]: Add python functions to get/set ctrl variables In-Reply-To: References: Message-ID: Patch Set 2: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/658 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I08705963c277bd93a011193dd7451a626d606c21 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 11 06:05:21 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 11 Aug 2016 06:05:21 +0000 Subject: openbsc[master]: Use random operation id In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/657 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I32236c067360526f4e7ee4bbdba64c5137de696d Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 11 06:05:36 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 11 Aug 2016 06:05:36 +0000 Subject: openbsc[master]: Add web proxy for control interface In-Reply-To: References: Message-ID: Patch Set 4: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/659 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I87d40c80061f8b3d02d656ab8cadabbfb871b461 Gerrit-PatchSet: 4 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 11 06:05:39 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 11 Aug 2016 06:05:39 +0000 Subject: [MERGED] openbsc[master]: Add web proxy for control interface In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: Add web proxy for control interface ...................................................................... Add web proxy for control interface Add web application exposing Control Interface over web. All of SET, GET and TRAP are fully supported. Notice: TRAP is converted into 'Server-sent events' according to RFC 6202, see also https://www.w3.org/TR/eventsource/ - this requires corresponding client. Due to use of special prefix modified version of python eventsource-client is necessary ATM. Change-Id: I87d40c80061f8b3d02d656ab8cadabbfb871b461 Related: OS#1646 --- A openbsc/contrib/ctrl2sse.py 1 file changed, 147 insertions(+), 0 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/openbsc/contrib/ctrl2sse.py b/openbsc/contrib/ctrl2sse.py new file mode 100755 index 0000000..8b630ec --- /dev/null +++ b/openbsc/contrib/ctrl2sse.py @@ -0,0 +1,147 @@ +#!/usr/bin/python2 + +mod_license = ''' +/* + * Copyright (C) 2016 sysmocom s.f.m.c. GmbH + * + * All Rights Reserved + * + * 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +''' + +import sys, argparse, random, logging, tornado.ioloop, tornado.web, tornado.tcpclient, tornado.httpclient, eventsource, bsc_control +from eventsource import listener, request + +''' +N. B: this is not an example of building proper REST API or building secure web application. +It's only purpose is to illustrate conversion of Osmocom's Control Interface to web-friendly API. +Exposing this to Internet while connected to production network might lead to all sorts of mischief and mayhem +from NSA' TAO breaking into your network to zombie apocalypse. Do NOT do that. +''' + +token = None +stream = None +url = None + +''' +Returns json according to following schema - see http://json-schema.org/documentation.html for details: +{ + "title": "Ctrl Schema", + "type": "object", + "properties": { + "variable": { + "type": "string" + }, + "varlue": { + "type": "string" + } + }, + "required": ["interface", "variable", "value"] +} +Example validation from command-line: +json validate --schema-file=schema.json --document-file=data.json +The interface is represented as string because it might look different for IPv4 vs v6. +''' + +def read_header(data): + t_length = bsc_control.ipa_ctrl_header(data) + if (t_length): + stream.read_bytes(t_length - 1, callback = read_trap) + else: + print >> sys.stderr, "protocol error: length missing in %s!" % data + + at tornado.gen.coroutine +def read_trap(data): + (t, z, v, p) = data.split() + if (t != 'TRAP' or int(z) != 0): + print >> sys.stderr, "protocol error: TRAP != %s or 0! = %d" % (t, int(z)) + else: + yield tornado.httpclient.AsyncHTTPClient().fetch(tornado.httpclient.HTTPRequest(url = "%s/%s/%s" % (url, "ping", token), + method = 'POST', + headers = {'Content-Type': 'application/json'}, + body = tornado.escape.json_encode({ 'variable' : v, 'value' : p }))) + stream.read_bytes(4, callback = read_header) + + at tornado.gen.coroutine +def trap_setup(host, port, target_host, target_port, tk): + global stream + global url + global token + token = tk + url = "http://%s:%s/sse" % (host, port) + stream = yield tornado.tcpclient.TCPClient().connect(target_host, target_port) + stream.read_bytes(4, callback = read_header) + +def get_v(s, v): + return { 'variable' : v, 'value' : bsc_control.get_var(s, tornado.escape.native_str(v)) } + +class CtrlHandler(tornado.web.RequestHandler): + def initialize(self): + self.skt = bsc_control.connect(self.settings['ctrl_host'], self.settings['ctrl_port']) + + def get(self, v): + self.write(get_v(self.skt, v)) + + def post(self): + self.write(get_v(self.skt, self.get_argument("variable"))) + +class SetCtrl(CtrlHandler): + def get(self, var, val): + bsc_control.set_var(self.skt, tornado.escape.native_str(var), tornado.escape.native_str(val)) + super(SetCtrl, self).get(tornado.escape.native_str(var)) + + def post(self): + bsc_control.set_var(self.skt, tornado.escape.native_str(self.get_argument("variable")), tornado.escape.native_str(self.get_argument("value"))) + super(SetCtrl, self).post() + +class Slash(tornado.web.RequestHandler): + def get(self): + self.write('%sUsing Tornado framework v%s' + '
' + '' + '' + '
' + '
' + '' + '' + '' + '
' + '' % ("Osmocom Control Interface Proxy", tornado.version)) + +if __name__ == '__main__': + p = argparse.ArgumentParser(description='Osmocom Control Interface proxy.') + p.add_argument('-c', '--control-port', type = int, default = 4252, help = "Target Control Interface port") + p.add_argument('-a', '--control-host', default = 'localhost', help = "Target Control Interface adress") + p.add_argument('-b', '--host', default = 'localhost', help = "Adress to bind proxy's web interface") + p.add_argument('-p', '--port', type = int, default = 6969, help = "Port to bind proxy's web interface") + p.add_argument('-d', '--debug', action='store_true', help = "Activate debugging (default off)") + p.add_argument('-t', '--token', default = 'osmocom', help = "Token to be used by SSE client in URL e. g. http://127.0.0.1:8888/poll/osmocom where 'osmocom' is default token value") + p.add_argument('-k', '--keepalive', type = int, default = 5000, help = "Timeout betwwen keepalive messages, in milliseconds, defaults to 5000") + args = p.parse_args() + random.seed() + tornado.netutil.Resolver.configure('tornado.netutil.ThreadedResolver') # Use non-blocking resolver + logging.basicConfig() + application = tornado.web.Application([ + (r"/", Slash), + (r"/get", CtrlHandler), + (r"/get/(.*)", CtrlHandler), + (r"/set", SetCtrl), + (r"/set/(.*)/(.*)", SetCtrl), + (r"/sse/(.*)/(.*)", listener.EventSourceHandler, dict(event_class = listener.JSONIdEvent, keepalive = args.keepalive)), + ], debug = args.debug, ctrl_host = args.control_host, ctrl_port = args.control_port) + application.listen(address = args.host, port = args.port) + trap_setup(args.host, args.port, application.settings['ctrl_host'], application.settings['ctrl_port'], args.token) + tornado.ioloop.IOLoop.instance().start() -- To view, visit https://gerrit.osmocom.org/659 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I87d40c80061f8b3d02d656ab8cadabbfb871b461 Gerrit-PatchSet: 5 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max From gerrit-no-reply at lists.osmocom.org Thu Aug 11 06:05:39 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 11 Aug 2016 06:05:39 +0000 Subject: [MERGED] openbsc[master]: Use random operation id In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: Use random operation id ...................................................................... Use random operation id According to documentation for Control Interface Protocol is "A numeric identifier, uniquely identifying this particular operation", hence it's best to be illustrated with random integer - use it as default. Fix override of id with previously used python-specific objects' id. Change-Id: I32236c067360526f4e7ee4bbdba64c5137de696d Related: OS#1646 --- M openbsc/contrib/bsc_control.py 1 file changed, 10 insertions(+), 8 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/openbsc/contrib/bsc_control.py b/openbsc/contrib/bsc_control.py index 26a421d..4fc8b4d 100755 --- a/openbsc/contrib/bsc_control.py +++ b/openbsc/contrib/bsc_control.py @@ -1,6 +1,6 @@ #!/usr/bin/python -import sys,os +import sys,os, random from optparse import OptionParser import socket import struct @@ -36,15 +36,17 @@ data = prefix_ipa_ctrl_header(data) sck.send(data) -def do_set(var, value, id, sck): - setmsg = "SET %s %s %s" %(options.id, var, value) +def do_set(var, value, op_id, sck): + setmsg = "SET %s %s %s" %(op_id, var, value) send(sck, setmsg) -def do_get(var, id, sck): - getmsg = "GET %s %s" %(options.id, var) +def do_get(var, op_id, sck): + getmsg = "GET %s %s" %(op_id, var) send(sck, getmsg) if __name__ == '__main__': + random.seed() + parser = OptionParser("Usage: %prog [options] var [value]") parser.add_option("-d", "--host", dest="host", help="connect to HOST", metavar="HOST") @@ -54,7 +56,7 @@ dest="cmd_get", help="perform GET operation") parser.add_option("-s", "--set", action="store_true", dest="cmd_set", help="perform SET operation") - parser.add_option("-i", "--id", dest="id", default="1", + parser.add_option("-i", "--id", dest="op_id", default=random.randint(1, sys.maxint), help="set id manually", metavar="ID") parser.add_option("-v", "--verbose", action="store_true", dest="verbose", help="be verbose", default=False) @@ -79,12 +81,12 @@ if options.cmd_set: if len(args) < 2: parser.error("Set requires var and value arguments") - do_set(args[0], ' '.join(args[1:]), options.id, sock) + do_set(args[0], ' '.join(args[1:]), options.op_id, sock) if options.cmd_get: if len(args) != 1: parser.error("Get requires the var argument") - do_get(args[0], options.id, sock) + do_get(args[0], options.op_id, sock) data = sock.recv(1024) while (len(data)>0): -- To view, visit https://gerrit.osmocom.org/657 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I32236c067360526f4e7ee4bbdba64c5137de696d Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Thu Aug 11 06:05:39 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 11 Aug 2016 06:05:39 +0000 Subject: [MERGED] openbsc[master]: Add python functions to get/set ctrl variables In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: Add python functions to get/set ctrl variables ...................................................................... Add python functions to get/set ctrl variables Add get_var and set_var functions which handle requested variable while checking for proper response and id. Split header handling into separate function. Change-Id: I08705963c277bd93a011193dd7451a626d606c21 Related: OS#1646 --- M openbsc/contrib/bsc_control.py 1 file changed, 27 insertions(+), 4 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/openbsc/contrib/bsc_control.py b/openbsc/contrib/bsc_control.py index 4fc8b4d..de0c2a9 100755 --- a/openbsc/contrib/bsc_control.py +++ b/openbsc/contrib/bsc_control.py @@ -10,15 +10,18 @@ def prefix_ipa_ctrl_header(data): return struct.pack(">HBB", len(data)+1, 0xee, 0) + data +def ipa_ctrl_header(header): + (plen, ipa_proto, osmo_proto) = struct.unpack(">HBB", header) + return None if (ipa_proto != 0xee or osmo_proto != 0) else plen + def remove_ipa_ctrl_header(data): if (len(data) < 4): raise BaseException("Answer too short!") - (plen, ipa_proto, osmo_proto) = struct.unpack(">HBB", data[:4]) + plen = ipa_ctrl_header(data[:4]) + if (None == plen): + raise BaseException("Wrong protocol in answer!") if (plen + 3 > len(data)): print "Warning: Wrong payload length (expected %i, got %i)" % (plen, len(data) - 3) - if (ipa_proto != 0xee or osmo_proto != 0): - raise BaseException("Wrong protocol in answer!") - return data[4:plen+3], data[plen+3:] def connect(host, port): @@ -44,6 +47,26 @@ getmsg = "GET %s %s" %(op_id, var) send(sck, getmsg) +def do_set_get(sck, var, value = None): + r = random.randint(1, sys.maxint) + if (value != None): + s = 'SET_REPLY' + do_set(var, value, r, sck) + else: + s = 'GET_REPLY' + do_get(var, r, sck) + (answer, data) = remove_ipa_ctrl_header(sck.recv(4096)) + x = answer.split() + if (s == x[0] and str(r) == x[1] and var == x[2]): + return None if ('SET_REPLY' == s and value != x[3]) else x[3] + return None + +def set_var(sck, var, val): + return do_set_get(sck, var, val) + +def get_var(sck, var): + return do_set_get(sck, var) + if __name__ == '__main__': random.seed() -- To view, visit https://gerrit.osmocom.org/658 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I08705963c277bd93a011193dd7451a626d606c21 Gerrit-PatchSet: 3 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Thu Aug 11 06:07:56 2016 From: gerrit-no-reply at lists.osmocom.org (prasadkg) Date: Thu, 11 Aug 2016 06:07:56 +0000 Subject: [PATCH] osmo-pcu[master]: Fix issues in URBB generation in EGPRS PUAN In-Reply-To: References: Message-ID: Hello Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/412 to look at the new patch set (#2). Fix issues in URBB generation in EGPRS PUAN Below issue in uncompresed bitmap generation is addressed 1. Corrected the number of bits that is included in URBB 2. If length is not present, 0s are coded as remaining bits Along with this, code is restructured to enable addition of compression support Change-Id: Ie5c25b6ee30f2f1b613e923c234b03a6ffe12ae2 --- M src/encoding.cpp M tests/tbf/TbfTest.err 2 files changed, 44 insertions(+), 35 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/12/412/2 diff --git a/src/encoding.cpp b/src/encoding.cpp index 63049ac..f372424 100644 --- a/src/encoding.cpp +++ b/src/encoding.cpp @@ -541,18 +541,21 @@ }; static void write_packet_ack_nack_desc_egprs( - struct gprs_rlcmac_bts *bts, bitvec * dest, unsigned& wp, + struct gprs_rlcmac_bts *bts, bitvec *dest, unsigned& wp, gprs_rlc_ul_window *window, bool is_final) { int urbb_len = 0; - int crbb_len = 0; int len; bool bow = true; bool eow = true; int ssn = window->mod_sns(window->v_q() + 1); int num_blocks = window->mod_sns(window->v_r() - window->v_q()); int esn_crbb = window->mod_sns(ssn - 1); - int rest_bits = dest->data_len * 8 - wp; + /* Bit 0 at the end is mandatory Table 11.2.28.1 in 44.060 */ + int rest_bits = dest->data_len * 8 - wp - 1; + int is_compressed = 0; + bool len_coded = true; + uint8_t i; if (num_blocks > 0) /* V(Q) is NACK and omitted -> SSN = V(Q) + 1 */ @@ -560,32 +563,31 @@ if (num_blocks > window->ws()) num_blocks = window->ws(); + /* TODO Compression support */ + if (is_compressed == 0) { + /* Union bit takes 1 bit */ + /* Other fields in descr for uncompresed bitmap takes 15 bits*/ - if (num_blocks > rest_bits) { - eow = false; - urbb_len = rest_bits; - /* TODO: use compression, start encoding bits and stop when the - * space is exhausted. Use the first combination that encodes - * all bits. If there is none, use the combination that encodes - * the largest number of bits (e.g. by setting num_blocks to the - * max and repeating the construction). - */ - } else if (num_blocks > rest_bits - 9) { - /* union bit and length field take 9 bits */ - eow = false; - urbb_len = rest_bits - 9; - /* TODO: use compression (see above) */ + if (num_blocks > rest_bits - 15 - 1) { + eow = false; + urbb_len = rest_bits - 15 - 1; + len_coded = false; + } else if (num_blocks == rest_bits - 15 - 1) { + urbb_len = rest_bits - 15 - 1; + len_coded = false; + /* Union bit takes 1 bit length field takes 8 bits*/ + } else if (num_blocks > rest_bits - 15 - 9) { + eow = false; + urbb_len = rest_bits - 15 - 9; + } else + urbb_len = num_blocks; + len = urbb_len + 15; + } else { + /* TODO Compressed bitmap */ } - if (urbb_len + crbb_len == rest_bits) - len = -1; - else if (crbb_len == 0) - len = urbb_len + 15; - else - len = urbb_len + crbb_len + 23; - /* EGPRS Ack/Nack Description IE */ - if (len < 0) { + if (len_coded == false) { bitvec_write_field(dest, wp, 0, 1); // 0: don't have length } else { bitvec_write_field(dest, wp, 1, 1); // 1: have length @@ -596,21 +598,28 @@ bitvec_write_field(dest, wp, bow, 1); // BEGINNING_OF_WINDOW bitvec_write_field(dest, wp, eow, 1); // END_OF_WINDOW bitvec_write_field(dest, wp, ssn, 11); // STARTING_SEQUENCE_NUMBER - bitvec_write_field(dest, wp, 0, 1); // 0: don't have CRBB - - /* TODO: Add CRBB support */ - + if (is_compressed) { + /* TODO Add CRBB support */ + } else + bitvec_write_field(dest, wp, 0, 1); // CRBB_Exist LOGP(DRLCMACUL, LOGL_DEBUG, - " - EGPRS URBB, len = %d, SSN = %d, ESN_CRBB = %d, " + "EGPRS URBB, urbb len = %d, SSN = %d, ESN_CRBB = %d, " + "len present = %s,desc len = %d, " "SNS = %d, WS = %d, V(Q) = %d, V(R) = %d%s%s\n", - urbb_len, ssn, esn_crbb, + urbb_len, ssn, esn_crbb, len_coded ? "yes" : "No", len, window->sns(), window->ws(), window->v_q(), window->v_r(), bow ? ", BOW" : "", eow ? ", EOW" : ""); - for (int i = urbb_len; i > 0; i--) { + + for (i = urbb_len; i > 0; i--) { /* Set bit at the appropriate position (see 3GPP TS 04.60 12.3.1) */ bool is_ack = window->m_v_n.is_received(esn_crbb + i); bitvec_write_field(dest, wp, is_ack, 1); } + /* If len is not coded, set remaining bits as 0 */ + if (len_coded == false) { + for (i = wp; i < dest->data_len*8; i++) + bitvec_write_field(dest, wp, 0, 1); + } } static void write_packet_uplink_ack_egprs( diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index e5c0a78..cd56402 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -6028,10 +6028,10 @@ - Raising V(R) to 65 Received RTS for PDCH: TRX=0 TS=7 FN=2654275 block_nr=9 scheduling USF=0 for required uplink resource of UL TFI=0 Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) - - EGPRS URBB, len = 0, SSN = 2, ESN_CRBB = 1, SNS = 2048, WS = 64, V(Q) = 1, V(R) = 65, BOW, EOW -Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 23 3e 24 46 68 90 87 b0 04 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +EGPRS URBB, urbb len = 63, SSN = 2, ESN_CRBB = 1, len present = yes,desc len = 78, SNS = 2048, WS = 64, V(Q) = 1, V(R) = 65, BOW, EOW +Uplink Ack/Nack bit count 161, max 184, message = 40 24 01 23 3e 24 46 68 90 a7 30 04 80 00 00 2a aa aa aa aa 2b 2b 2b Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (TRX=0, TS=7) -Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654275 block=9 data=40 24 01 23 3e 24 46 68 90 87 b0 04 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654275 block=9 data=40 24 01 23 3e 24 46 68 90 a7 30 04 80 00 00 2a aa aa aa aa 2b 2b 2b Got 'TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS)', TA=7 Got MS: TLLI = 0xf1223344, TA = 7 ********** TBF starts here ********** -- To view, visit https://gerrit.osmocom.org/412 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ie5c25b6ee30f2f1b613e923c234b03a6ffe12ae2 Gerrit-PatchSet: 2 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: prasadkg Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: prasadkg From gerrit-no-reply at lists.osmocom.org Thu Aug 11 06:08:40 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 11 Aug 2016 06:08:40 +0000 Subject: osmo-pcu[master]: Change interface in osmo-pcu for 11 bit RACH In-Reply-To: References: Message-ID: Patch Set 3: Code-Review+1 -- To view, visit https://gerrit.osmocom.org/429 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I265c2d92d36d6cbcbeee60cdd8407dafe1da06a4 Gerrit-PatchSet: 3 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: bhargava_abhyankar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 11 06:11:26 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 11 Aug 2016 06:11:26 +0000 Subject: [PATCH] osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/655 to look at the new patch set (#11). Modify EGPRS DL TBF flow to support SPB Modify the EGPRS DL TBF flow to support Split block during Retx. This patch will also Upgrade the test suite with test cases to validate the EGPRS Downlink SPB for Retransmission Scenarios like MCS6->MCS3, MCS4->MCS1, MCS5->MCS2, MCS9->MCS3 MCS7->MCS2, MCS8->MCS3 have been simulated and Integration tested in NuRAN 1.0 hardware thoroughly. Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 --- M src/gprs_coding_scheme.h M src/pcu_main.cpp M src/pcu_vty.c M src/rlc.cpp M src/rlc.h M src/tbf.h M src/tbf_dl.cpp M tests/edge/EdgeTest.cpp M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 11 files changed, 948 insertions(+), 77 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/55/655/11 diff --git a/src/gprs_coding_scheme.h b/src/gprs_coding_scheme.h index 60a8e79..3b15372 100644 --- a/src/gprs_coding_scheme.h +++ b/src/gprs_coding_scheme.h @@ -113,7 +113,8 @@ static const char *modeName(Mode mode); static Scheme get_retx_mcs(const GprsCodingScheme mcs, - const GprsCodingScheme retx_mcs); + const GprsCodingScheme retx_mcs, + const unsigned arq_type); static enum Scheme egprs_mcs_retx_tbl[MAX_NUM_ARQ] [MAX_NUM_MCS][MAX_NUM_MCS]; @@ -232,8 +233,9 @@ } inline GprsCodingScheme::Scheme GprsCodingScheme::get_retx_mcs( const GprsCodingScheme mcs, - const GprsCodingScheme demanded_mcs) + const GprsCodingScheme demanded_mcs, + const unsigned arq_type) { - return egprs_mcs_retx_tbl[EGPRS_ARQ2][mcs.to_num() - 1] + return egprs_mcs_retx_tbl[arq_type][mcs.to_num() - 1] [demanded_mcs.to_num() - 1]; } diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2d86cda..e34d534 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -210,6 +210,12 @@ bts->dl_tbf_idle_msec = 2000; bts->llc_idle_ack_csec = 10; + /* + * By default resegmentation is supported in DL + * can also be configured through VTY + */ + bts->dl_arq_type = EGPRS_ARQ1; + msgb_set_talloc_ctx(tall_pcu_ctx); osmo_init_logging(&gprs_log_info); diff --git a/src/pcu_vty.c b/src/pcu_vty.c index 58fea99..96b87a6 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -129,6 +129,9 @@ vty_out(vty, " window-size %d %d%s", bts->ws_base, bts->ws_pdch, VTY_NEWLINE); + if (bts->dl_arq_type) + vty_out(vty, " dl arq-type %d%s", bts->dl_arq_type, VTY_NEWLINE); + if (bts->force_llc_lifetime == 0xffff) vty_out(vty, " queue lifetime infinite%s", VTY_NEWLINE); else if (bts->force_llc_lifetime) @@ -477,6 +480,20 @@ bts->max_mcs_dl = 0; bts->max_mcs_ul = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_pcu_dl_arq_type, + cfg_pcu_dl_arq_cmd, + "dl arq-type (0|1)", + EGPRS_STR "DL ARQ options\n" + "enable DL SPB support\n" + "enable DL ARQ2 support") +{ + struct gprs_rlcmac_bts *bts = bts_main_data(); + uint8_t dl_arq_type = atoi(argv[0]); + + bts->dl_arq_type = dl_arq_type; return CMD_SUCCESS; } @@ -954,6 +971,7 @@ install_element(PCU_NODE, &cfg_pcu_no_cs_downgrade_thrsh_cmd); install_element(PCU_NODE, &cfg_pcu_cs_lqual_ranges_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_cmd); + install_element(PCU_NODE, &cfg_pcu_dl_arq_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_max_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_max_cmd); diff --git a/src/rlc.cpp b/src/rlc.cpp index 6770043..8da96f7 100644 --- a/src/rlc.cpp +++ b/src/rlc.cpp @@ -285,7 +285,8 @@ } static void gprs_rlc_data_header_init(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding, unsigned int header_bits) + GprsCodingScheme cs, bool with_padding, unsigned int header_bits, + const unsigned int spb) { unsigned int i; unsigned int padding_bits = with_padding ? cs.optionalPaddingBits() : 0; @@ -300,7 +301,7 @@ for (i = 0; i < rlc->num_data_blocks; i++) { gprs_rlc_data_block_info_init(&rlc->block_info[i], cs, - with_padding); + with_padding, spb); rlc->data_offs_bits[i] = header_bits + padding_bits + @@ -310,21 +311,25 @@ } void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsDL()); + cs.numDataHeaderBitsDL(), spb); } void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding) { + /* + * last parameter is sent as 0 since common function used + * for both DL and UL + */ return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsUL()); + cs.numDataHeaderBitsUL(), 0); } void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { unsigned int data_len = cs.maxDataBlockBytes(); if (with_padding) @@ -336,7 +341,7 @@ rdbi->e = 1; rdbi->cv = 15; rdbi->pi = 0; - rdbi->spb = 0; + rdbi->spb = spb; } unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, @@ -411,8 +416,17 @@ enum egprs_puncturing_values gprs_get_punct_scheme( enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current) + const GprsCodingScheme &cs_current, + const unsigned int spb) { + + /* + * If it is second segment of the block + * dont change the puncturing scheme + */ + if (spb == 3) + return punct; + /* TS 44.060 9.3.2.1.1 */ if ((GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS9) && (GprsCodingScheme::Scheme(cs_current) == GprsCodingScheme::MCS6)) { diff --git a/src/rlc.h b/src/rlc.h index 539b30b..66faf6f 100644 --- a/src/rlc.h +++ b/src/rlc.h @@ -206,18 +206,19 @@ }; void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding); void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, enum egprs_puncturing_values punct, enum egprs_puncturing_values punct2, int with_padding); void gprs_rlc_mcs_cps_decode(unsigned int cps, GprsCodingScheme cs, int *punct, int *punct2, int *with_padding); enum egprs_puncturing_values gprs_get_punct_scheme(enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current_trans); + const GprsCodingScheme &cs_current_trans, + const unsigned int spb); void gprs_update_punct_scheme(enum egprs_puncturing_values *punct, const GprsCodingScheme &cs); /* diff --git a/src/tbf.h b/src/tbf.h index 1bd7878..969836b 100644 --- a/src/tbf.h +++ b/src/tbf.h @@ -421,6 +421,11 @@ int analyse_errors(char *show_rbb, uint8_t ssn, ana_result *res); void schedule_next_frame(); + enum egprs_rlc_dl_reseg_bsn_state egprs_dl_get_data_buffer + (int bsn, uint8_t **block_data); + unsigned int get_egprs_dl_spb_status(int bsn); + unsigned int get_egprs_dl_spb_value(int bsn); + struct osmo_timer_list m_llc_timer; }; diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp index 07a747a..0395ed0 100644 --- a/src/tbf_dl.cpp +++ b/src/tbf_dl.cpp @@ -375,21 +375,27 @@ return -1; if (is_egprs_enabled()) { + /* Table 8.1.1.2 and Table 8.1.1.1 of 44.060 */ m_rlc.block(bsn)->cs_current_trans = - GprsCodingScheme::get_retx_mcs( - m_rlc.block(bsn)->cs_last, ms()->current_cs_dl()); + GprsCodingScheme::get_retx_mcs( + m_rlc.block(bsn)->cs_init, + ms()->current_cs_dl(), + bts->bts_data()->dl_arq_type); LOGP(DRLCMACDL, LOGL_DEBUG, - "- current_cs_dl(%d) demanded_mcs(%d) cs_trans(%d)\n", + "- initial_cs_dl(%d) last_mcs(%d) demanded_mcs(%d)" + "cs_trans(%d) arq_type(%d) bsn(%d)\n", + m_rlc.block(bsn)->cs_init.to_num(), m_rlc.block(bsn)->cs_last.to_num(), ms()->current_cs_dl().to_num(), - m_rlc.block(bsn)->cs_current_trans.to_num()); + m_rlc.block(bsn)->cs_current_trans.to_num(), + bts->bts_data()->dl_arq_type, bsn); /* TODO: Need to remove this check when MCS-8 -> MCS-6 * transistion is handled. * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 */ - if (m_rlc.block(bsn)->cs_last == GprsCodingScheme::MCS8) + if (m_rlc.block(bsn)->cs_init == GprsCodingScheme::MCS8) m_rlc.block(bsn)->cs_current_trans = GprsCodingScheme::MCS8; } else @@ -523,6 +529,11 @@ data = rlc_data->prepare(block_data_len); rlc_data->cs_last = cs; rlc_data->cs_current_trans = cs; + + /* Initialise the variable related to DL SPB */ + rlc_data->spb_status.block_status_dl = EGPRS_RESEG_DL_DEFAULT; + rlc_data->cs_init = cs; + rlc_data->len = block_data_len; rdbi = &(rlc_data->block_info); @@ -616,6 +627,7 @@ unsigned num_bsns; enum egprs_puncturing_values punct[ARRAY_SIZE(rlc.block_info)]; bool need_padding = false; + unsigned int spb = 0; /* * TODO: This is an experimental work-around to put 2 BSN into @@ -626,6 +638,7 @@ * the current limit. */ cs = m_rlc.block(index)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(index)->cs_init; bsns[0] = index; num_bsns = 1; @@ -634,7 +647,19 @@ num_bsns += 1; } - if (num_bsns == 1) { + /* + * if the intial mcs is 8 and retransmission mcs is either 6 or 3 + * we have to include the padding of 6 octets in first segment + */ + if ((GprsCodingScheme::Scheme(cs_init) == GprsCodingScheme::MCS8) && + (GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS6 || + GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS3)) { + if ((get_egprs_dl_spb_status(index) == + EGPRS_RESEG_DL_DEFAULT) || + (get_egprs_dl_spb_status(index) == + EGPRS_RESEG_SECOND_SEG_SENT)) + need_padding = true; + } else if (num_bsns == 1) { /* TODO: remove the conditional when MCS-6 padding isn't * failing to be decoded by MEs anymore */ /* TODO: support of MCS-8 -> MCS-6 transition should be @@ -646,7 +671,14 @@ cs.decToSingleBlock(&need_padding); } - gprs_rlc_data_info_init_dl(&rlc, cs, need_padding); + spb = get_egprs_dl_spb_value(index); + + LOGP(DRLCMACDL, LOGL_DEBUG, "- need_padding %d spb_status %d spb %d" + "(BSN1 %d BSN2 %d)\n", + need_padding, + get_egprs_dl_spb_status(index), spb, index, index2); + + gprs_rlc_data_info_init_dl(&rlc, cs, need_padding, spb); rlc.usf = 7; /* will be set at scheduler */ rlc.pr = 0; /* FIXME: power reduction */ @@ -665,10 +697,9 @@ data_block_idx++) { int bsn; - GprsCodingScheme cs_enc; uint8_t *block_data; gprs_rlc_data_block_info *rdbi, *block_info; - enum egprs_puncturing_values punct_scheme; + enum egprs_rlc_dl_reseg_bsn_state reseg_status; /* Check if there are more blocks than BSNs */ if (data_block_idx < num_bsns) @@ -676,38 +707,43 @@ else bsn = bsns[0]; - cs_enc = m_rlc.block(bsn)->cs_current_trans; - /* get data and header from current block */ - block_data = m_rlc.block(bsn)->block; - /* Get current puncturing scheme from block */ - punct_scheme = gprs_get_punct_scheme( + + m_rlc.block(bsn)->next_ps = gprs_get_punct_scheme( m_rlc.block(bsn)->next_ps, - m_rlc.block(bsn)->cs_last, cs); + m_rlc.block(bsn)->cs_last, cs, spb); if (cs.isEgprs()) { - OSMO_ASSERT(punct_scheme >= EGPRS_PS_1); - OSMO_ASSERT(punct_scheme <= EGPRS_PS_3); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps >= EGPRS_PS_1); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps <= EGPRS_PS_3); } - punct[data_block_idx] = punct_scheme; + punct[data_block_idx] = m_rlc.block(bsn)->next_ps; rdbi = &rlc.block_info[data_block_idx]; block_info = &m_rlc.block(bsn)->block_info; - if(rdbi->data_len != m_rlc.block(bsn)->len) { - LOGP(DRLCMACDL, LOGL_ERROR, - "ERROR: Expected len = %d for %s instead of " - "%d in data unit %d (BSN %d, %s)\n", - rdbi->data_len, cs.name(), m_rlc.block(bsn)->len, - data_block_idx, bsn, cs_enc.name()); - OSMO_ASSERT(rdbi->data_len == m_rlc.block(bsn)->len); - } - - /* TODO: Need to handle 2 same bsns - * in header type 1 + /* + * get data and header from current block + * function returns the reseg status */ - gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, - cs); + reseg_status = egprs_dl_get_data_buffer(bsn, &block_data); + m_rlc.block(bsn)->spb_status.block_status_dl = reseg_status; + + /* + * If it is first segment of the split block set the state of + * bsn to nacked. If it is the first segment dont update the + * next ps value of bsn. since next segment also needs same cps + */ + if (spb == 2) + m_window.m_v_b.mark_nacked(bsn); + else { + /* + * TODO: Need to handle 2 same bsns + * in header type 1 + */ + gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, + cs); + } m_rlc.block(bsn)->cs_last = cs; rdbi->e = block_info->e; @@ -1169,3 +1205,119 @@ keep_time_frames = msecs_to_frames(bts_data()->dl_tbf_idle_msec); return frames_since_last_drain(fn) <= keep_time_frames; } + +/* + * This function returns the pointer to data which needs + * to be copied. Also updates the status of the block related to + * Split block handling in the RLC/MAC block. + */ +enum egprs_rlc_dl_reseg_bsn_state + gprs_rlcmac_dl_tbf::egprs_dl_get_data_buffer(int bsn, + uint8_t **block_data) +{ + gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state *block_status_dl = + &rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + *block_data = &rlc_data->block[0]; + + /* + * Table 10.3a.0.1 of 44.060 + * MCS6,9: second segment starts at 74/2 = 37 + * MCS5,7: second segment starts at 56/2 = 28 + * MCS8: second segment starts at 31 + * MCS4: second segment starts at 44/2 = 22 + */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + if (*block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + switch (GprsCodingScheme::Scheme(cs_init)) { + case GprsCodingScheme::MCS6 : + case GprsCodingScheme::MCS9 : + *block_data = &rlc_data->block[37]; + break; + case GprsCodingScheme::MCS7 : + case GprsCodingScheme::MCS5 : + *block_data = &rlc_data->block[28]; + break; + case GprsCodingScheme::MCS8 : + *block_data = &rlc_data->block[31]; + break; + case GprsCodingScheme::MCS4 : + *block_data = &rlc_data->block[22]; + break; + default: + LOGP(DRLCMACDL, LOGL_ERROR, "Software error: " + "--%s hit invalid condition. headerType(%d) " + " blockstatus(%d) cs(%s) PLEASE FIX!\n", name(), + cs_current_trans.headerTypeData(), + *block_status_dl, cs_init.name()); + break; + + } + return EGPRS_RESEG_SECOND_SEG_SENT; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } + } + return EGPRS_RESEG_DL_DEFAULT; +} + +/* + * This function returns the status of split block + * for RLC/MAC block. + */ +unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_status(const int bsn) +{ + const gprs_rlc_data *rlc_data = m_rlc.block(bsn); + + return rlc_data->spb_status.block_status_dl; +} + +/* + * This function returns the spb value to be sent OTA + * for RLC/MAC block. + */ +unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_value(const int bsn) +{ + struct gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state block_status_dl = + rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + + /* Table 10.4.8b.1 of 44.060 */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + /* + * if we are sending the second segment the spb should be 3 + * other wise it should be 2 + */ + if (block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + return 3; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return 2; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return 2; + } + } + /* Non SPB cases 0 is reurned */ + return 0; +} diff --git a/tests/edge/EdgeTest.cpp b/tests/edge/EdgeTest.cpp index 807102c..9081d4d 100644 --- a/tests/edge/EdgeTest.cpp +++ b/tests/edge/EdgeTest.cpp @@ -517,7 +517,7 @@ /* TS 44.060, B.1 */ cs = GprsCodingScheme::CS4; - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -570,7 +570,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -592,7 +592,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -630,7 +630,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -669,7 +669,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -694,7 +694,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -719,7 +719,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -740,7 +740,7 @@ OSMO_ASSERT(data[0] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -777,7 +777,7 @@ cs = GprsCodingScheme::MCS4; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -835,7 +835,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -872,7 +872,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -923,7 +923,7 @@ OSMO_ASSERT(data[3] == 0); /* Block 3 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -967,7 +967,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -993,7 +993,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1020,7 +1020,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1074,7 +1074,7 @@ block_idx++) { struct gprs_rlc_data_info rlc; - gprs_rlc_data_info_init_dl(&rlc, cs, false); + gprs_rlc_data_info_init_dl(&rlc, cs, false, 0); memset(bits, pattern, sizeof(bits)); Decoding::rlc_copy_to_aligned_buffer( @@ -1118,12 +1118,14 @@ struct gprs_rlc_data_info rlc; printf("=== start %s ===\n", __func__); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::CS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::CS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 24); OSMO_ASSERT(rlc.block_info[0].data_len == 20); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::MCS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::MCS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 33); OSMO_ASSERT(rlc.block_info[0].data_len == 22); diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..18cc5cb 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -1814,6 +1814,201 @@ } +static void egprs_spb_to_normal_validation(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + uint16_t bsn1, bsn2, bsn3; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + struct gprs_rlc_dl_header_egprs_2 *egprs2; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + if ((mcs == 6) && (demanded_mcs == 3)) { + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + bsn1 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) + || (egprs2->bsn1_lo); + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(bsn1 == 0); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + bsn2 = (egprs3->bsn1_hi << 9) || (egprs3->bsn1_mid << 1) || + (egprs3->bsn1_lo); + OSMO_ASSERT(bsn2 == bsn1); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Handle (MCS3, MCS3) -> MCS6 case */ + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + mcs)); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs2->cps == 0); + bsn3 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) || + (egprs2->bsn1_lo); + OSMO_ASSERT(bsn3 == bsn2); + + tbf_cleanup(dl_tbf); + } +} +static void establish_and_use_egprs_dl_tbf_for_spb(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + /* TODO: Need to support of MCS8 -> MCS6 ->MCS3 transistion + * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 + * dated 2016-02-07 23:45:40 (UTC) + */ + if (((mcs == 5) && (demanded_mcs == 2)) || + ((mcs == 6) && (demanded_mcs == 3)) || + ((mcs == 4) && (demanded_mcs == 1))) { + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + tbf_cleanup(dl_tbf); + } +} + static void establish_and_use_egprs_dl_tbf_for_retx(BTS *the_bts, int mcs, int demanded_mcs) { @@ -1972,6 +2167,9 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; + /* First parameter is current MCS, second one is demanded_mcs */ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 6); @@ -1981,6 +2179,38 @@ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 9); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 7, 5); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 9, 6); + + printf("=== end %s ===\n", __func__); +} + +static void test_tbf_egprs_spb_dl(void) +{ + BTS the_bts; + gprs_rlcmac_bts *bts; + uint8_t ts_no = 4; + int i, j; + + printf("=== start %s ===\n", __func__); + + bts = the_bts.bts_data(); + bts->cs_downgrade_threshold = 0; + setup_bts(&the_bts, ts_no); + bts->dl_tbf_idle_msec = 200; + bts->egprs_enabled = 1; + + /* ARQ I resegmentation support */ + bts->dl_arq_type = EGPRS_ARQ1; + + /* + * First parameter is current MCS, second one is demanded_mcs + * currently only MCS5->MCS2, MCS6->3, MCS4->MCS1 is tested in UT + * rest scenarios has been integration tested + */ + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 6, 3); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 5, 2); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 4, 1); + /* check MCS6->(MCS3+MCS3)->MCS6 case */ + egprs_spb_to_normal_validation(&the_bts, 6, 3); printf("=== end %s ===\n", __func__); } @@ -1999,6 +2229,8 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; for (i = 1; i <= 9; i++) establish_and_use_egprs_dl_tbf(&the_bts, i); @@ -2071,6 +2303,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_egprs_spb_dl(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..7b3f339 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -72,6 +72,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -81,6 +82,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -157,6 +159,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -166,6 +169,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -242,6 +246,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -251,6 +256,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -259,6 +265,7 @@ - Sending new block at BSN 2, CS=CS-1 -- Chunk with length 160 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=13 block=3 data=07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b @@ -267,6 +274,7 @@ - Sending new block at BSN 3, CS=CS-1 -- Chunk with length 140 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=17 block=4 data=07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @@ -275,6 +283,7 @@ - Sending new block at BSN 4, CS=CS-1 -- Chunk with length 120 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=21 block=5 data=07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 @@ -283,6 +292,7 @@ - Sending new block at BSN 5, CS=CS-1 -- Chunk with length 100 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=26 block=6 data=07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 @@ -291,6 +301,7 @@ - Sending new block at BSN 6, CS=CS-1 -- Chunk with length 80 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=30 block=7 data=07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b @@ -299,6 +310,7 @@ - Sending new block at BSN 7, CS=CS-1 -- Chunk with length 60 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=34 block=8 data=07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f @@ -307,6 +319,7 @@ - Sending new block at BSN 8, CS=CS-1 -- Chunk with length 40 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=39 block=9 data=07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 @@ -315,6 +328,7 @@ - Sending new block at BSN 9, CS=CS-1 -- Chunk with length 20 would exactly fit into space (20): add length header with LI=0, to make frame extend to next block, and we are done data block (BSN 9, CS-1): 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=43 block=10 data=07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 @@ -326,6 +340,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=47 block=11 data=07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 @@ -334,6 +349,7 @@ - Sending new block at BSN 11, CS=CS-1 -- Chunk with length 182 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=52 block=0 data=07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 @@ -342,6 +358,7 @@ - Sending new block at BSN 12, CS=CS-1 -- Chunk with length 162 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=56 block=1 data=07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 @@ -350,6 +367,7 @@ - Sending new block at BSN 13, CS=CS-1 -- Chunk with length 142 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 13, CS-1): 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=60 block=2 data=07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d @@ -358,6 +376,7 @@ - Sending new block at BSN 14, CS=CS-1 -- Chunk with length 122 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=65 block=3 data=07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 @@ -366,6 +385,7 @@ - Sending new block at BSN 15, CS=CS-1 -- Chunk with length 102 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=69 block=4 data=07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 @@ -374,6 +394,7 @@ - Sending new block at BSN 16, CS=CS-1 -- Chunk with length 82 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=73 block=5 data=07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 @@ -382,6 +403,7 @@ - Sending new block at BSN 17, CS=CS-1 -- Chunk with length 62 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=78 block=6 data=07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d @@ -390,6 +412,7 @@ - Sending new block at BSN 18, CS=CS-1 -- Chunk with length 42 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=82 block=7 data=07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 @@ -398,6 +421,7 @@ - Sending new block at BSN 19, CS=CS-1 -- Chunk with length 22 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=86 block=8 data=07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 @@ -411,6 +435,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=16 data block (BSN 20, CS-1): 0a 41 c6 c7 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -449,6 +474,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 data block (BSN 21, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -468,6 +494,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 22, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FINISHED) @@ -1481,6 +1508,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 0, CS-1): 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 MSG = 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 @@ -1491,6 +1519,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 1, CS-1): 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 MSG = 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 @@ -1501,6 +1530,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FINISHED data block (BSN 2, CS-1): 4d 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling cannot be scheduled in this TS 7 (first control TS 4) @@ -1784,6 +1814,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=10 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 0, CS-4): 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654292 TS 7 @@ -1797,6 +1828,7 @@ TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) downlink (V(A)==0 .. V(S)==1) - Restarting at BSN 0, because all blocks have been transmitted. - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-4): 07 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 @@ -2365,6 +2397,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654279 block=10 data=00 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 @@ -2384,6 +2417,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -2406,6 +2440,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654288 block=0 data=00 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 @@ -2425,6 +2460,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654292 block=1 data=00 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2447,6 +2483,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654296 block=2 data=00 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c @@ -2466,6 +2503,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654301 block=3 data=00 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b @@ -2488,6 +2526,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 6, CS-1): 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654305 block=4 data=00 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 @@ -2507,6 +2546,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654309 block=5 data=00 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 @@ -2526,6 +2566,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654314 block=6 data=00 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 @@ -2548,6 +2589,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654318 block=7 data=00 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 @@ -2567,6 +2609,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654322 block=8 data=00 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2589,6 +2632,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654327 block=9 data=00 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c @@ -2608,6 +2652,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654331 block=10 data=00 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b @@ -2630,6 +2675,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 13, CS-1): 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654335 block=11 data=00 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 @@ -2649,6 +2695,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654340 block=0 data=00 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 @@ -2668,6 +2715,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654344 block=1 data=00 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 @@ -2690,6 +2738,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654348 block=2 data=00 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 @@ -2709,6 +2758,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654353 block=3 data=00 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2731,6 +2781,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654357 block=4 data=00 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c @@ -2750,6 +2801,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654361 block=5 data=00 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b @@ -2772,6 +2824,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 20, CS-1): 16 35 45 54 20 32 38 4c 4c 43 20 50 41 43 4b 45 54 20 32 39 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because 20 blocks sent. TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW): Scheduling polling at FN 2654379 TS 7 @@ -2795,6 +2848,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 21, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) msg block (BSN 21, CS-1): 07 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654370 block=7 data=00 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 @@ -2814,6 +2868,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 22, CS-1): 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) msg block (BSN 22, CS-1): 07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654374 block=8 data=07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 @@ -2836,6 +2891,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 23, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) msg block (BSN 23, CS-1): 07 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654379 block=9 data=00 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 @@ -2855,6 +2911,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 24, CS-1): 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) msg block (BSN 24, CS-1): 07 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654383 block=10 data=00 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2877,6 +2934,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 25, CS-1): 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 25 BSN2 -1) - Copying data unit 0 (BSN 25) msg block (BSN 25, CS-1): 07 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654387 block=11 data=00 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c @@ -2896,6 +2954,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 26, CS-1): 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 26 BSN2 -1) - Copying data unit 0 (BSN 26) msg block (BSN 26, CS-1): 07 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654392 block=0 data=00 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b @@ -2918,6 +2977,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 27, CS-1): 16 35 45 54 20 33 38 4c 4c 43 20 50 41 43 4b 45 54 20 33 39 +- need_padding 0 spb_status 0 spb 0(BSN1 27 BSN2 -1) - Copying data unit 0 (BSN 27) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) @@ -3028,6 +3088,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654405 block=3 data=00 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 @@ -3047,6 +3108,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654409 block=4 data=00 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 @@ -3066,6 +3128,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (16) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654413 block=5 data=00 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 @@ -3085,6 +3148,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (14) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654418 block=6 data=00 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 @@ -3104,6 +3168,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654422 block=7 data=00 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -3123,6 +3188,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654426 block=8 data=00 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 @@ -3142,6 +3208,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654431 block=9 data=00 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b @@ -3161,6 +3228,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654435 block=10 data=00 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 @@ -3180,6 +3248,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654439 block=11 data=00 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 @@ -3199,6 +3268,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654444 block=0 data=00 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c @@ -3218,6 +3288,7 @@ Complete DL frame for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=21 TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 10, CS-1): 4d 43 20 50 41 43 4b 45 54 20 30 39 20 28 54 42 46 20 32 29 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654461 TS 7 @@ -3698,6 +3769,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 0, MCS-1): 14 15 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3711,6 +3783,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3721,6 +3794,7 @@ - Sending new block at BSN 2, CS=MCS-1 -- Chunk with length 490 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3731,6 +3805,7 @@ - Sending new block at BSN 3, CS=MCS-1 -- Chunk with length 468 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3741,6 +3816,7 @@ - Sending new block at BSN 4, CS=MCS-1 -- Chunk with length 446 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3751,6 +3827,7 @@ - Sending new block at BSN 5, CS=MCS-1 -- Chunk with length 424 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3761,6 +3838,7 @@ - Sending new block at BSN 6, CS=MCS-1 -- Chunk with length 402 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3771,6 +3849,7 @@ - Sending new block at BSN 7, CS=MCS-1 -- Chunk with length 380 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3781,6 +3860,7 @@ - Sending new block at BSN 8, CS=MCS-1 -- Chunk with length 358 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3791,6 +3871,7 @@ - Sending new block at BSN 9, CS=MCS-1 -- Chunk with length 336 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3801,6 +3882,7 @@ - Sending new block at BSN 10, CS=MCS-1 -- Chunk with length 314 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3811,6 +3893,7 @@ - Sending new block at BSN 11, CS=MCS-1 -- Chunk with length 292 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3821,6 +3904,7 @@ - Sending new block at BSN 12, CS=MCS-1 -- Chunk with length 270 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3831,6 +3915,7 @@ - Sending new block at BSN 13, CS=MCS-1 -- Chunk with length 248 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3841,6 +3926,7 @@ - Sending new block at BSN 14, CS=MCS-1 -- Chunk with length 226 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3851,6 +3937,7 @@ - Sending new block at BSN 15, CS=MCS-1 -- Chunk with length 204 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3861,6 +3948,7 @@ - Sending new block at BSN 16, CS=MCS-1 -- Chunk with length 182 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3871,6 +3959,7 @@ - Sending new block at BSN 17, CS=MCS-1 -- Chunk with length 160 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3881,6 +3970,7 @@ - Sending new block at BSN 18, CS=MCS-1 -- Chunk with length 138 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3891,6 +3981,7 @@ - Sending new block at BSN 19, CS=MCS-1 -- Chunk with length 116 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 19, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3901,6 +3992,7 @@ - Sending new block at BSN 20, CS=MCS-1 -- Chunk with length 94 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 20, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3911,6 +4003,7 @@ - Sending new block at BSN 21, CS=MCS-1 -- Chunk with length 72 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 21, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3921,6 +4014,7 @@ - Sending new block at BSN 22, CS=MCS-1 -- Chunk with length 50 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 22, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3931,6 +4025,7 @@ - Sending new block at BSN 23, CS=MCS-1 -- Chunk with length 28 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 23, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3946,6 +4041,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 24, MCS-1): 0c 1d 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4006,6 +4102,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=16 data block (BSN 0, MCS-2): 14 21 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4019,6 +4116,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4029,6 +4127,7 @@ - Sending new block at BSN 2, CS=MCS-2 -- Chunk with length 484 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4039,6 +4138,7 @@ - Sending new block at BSN 3, CS=MCS-2 -- Chunk with length 456 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4049,6 +4149,7 @@ - Sending new block at BSN 4, CS=MCS-2 -- Chunk with length 428 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4059,6 +4160,7 @@ - Sending new block at BSN 5, CS=MCS-2 -- Chunk with length 400 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4069,6 +4171,7 @@ - Sending new block at BSN 6, CS=MCS-2 -- Chunk with length 372 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4079,6 +4182,7 @@ - Sending new block at BSN 7, CS=MCS-2 -- Chunk with length 344 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4089,6 +4193,7 @@ - Sending new block at BSN 8, CS=MCS-2 -- Chunk with length 316 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4099,6 +4204,7 @@ - Sending new block at BSN 9, CS=MCS-2 -- Chunk with length 288 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4109,6 +4215,7 @@ - Sending new block at BSN 10, CS=MCS-2 -- Chunk with length 260 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4119,6 +4226,7 @@ - Sending new block at BSN 11, CS=MCS-2 -- Chunk with length 232 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4129,6 +4237,7 @@ - Sending new block at BSN 12, CS=MCS-2 -- Chunk with length 204 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4139,6 +4248,7 @@ - Sending new block at BSN 13, CS=MCS-2 -- Chunk with length 176 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4149,6 +4259,7 @@ - Sending new block at BSN 14, CS=MCS-2 -- Chunk with length 148 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4159,6 +4270,7 @@ - Sending new block at BSN 15, CS=MCS-2 -- Chunk with length 120 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4169,6 +4281,7 @@ - Sending new block at BSN 16, CS=MCS-2 -- Chunk with length 92 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4179,6 +4292,7 @@ - Sending new block at BSN 17, CS=MCS-2 -- Chunk with length 64 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4189,6 +4303,7 @@ - Sending new block at BSN 18, CS=MCS-2 -- Chunk with length 36 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4204,6 +4319,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=18 data block (BSN 19, MCS-2): 10 25 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4264,6 +4380,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=25 data block (BSN 0, MCS-3): 14 33 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4277,6 +4394,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4287,6 +4405,7 @@ - Sending new block at BSN 2, CS=MCS-3 -- Chunk with length 475 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4297,6 +4416,7 @@ - Sending new block at BSN 3, CS=MCS-3 -- Chunk with length 438 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4307,6 +4427,7 @@ - Sending new block at BSN 4, CS=MCS-3 -- Chunk with length 401 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4317,6 +4438,7 @@ - Sending new block at BSN 5, CS=MCS-3 -- Chunk with length 364 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4327,6 +4449,7 @@ - Sending new block at BSN 6, CS=MCS-3 -- Chunk with length 327 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4337,6 +4460,7 @@ - Sending new block at BSN 7, CS=MCS-3 -- Chunk with length 290 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4347,6 +4471,7 @@ - Sending new block at BSN 8, CS=MCS-3 -- Chunk with length 253 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4357,6 +4482,7 @@ - Sending new block at BSN 9, CS=MCS-3 -- Chunk with length 216 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4367,6 +4493,7 @@ - Sending new block at BSN 10, CS=MCS-3 -- Chunk with length 179 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4377,6 +4504,7 @@ - Sending new block at BSN 11, CS=MCS-3 -- Chunk with length 142 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4387,6 +4515,7 @@ - Sending new block at BSN 12, CS=MCS-3 -- Chunk with length 105 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4397,6 +4526,7 @@ - Sending new block at BSN 13, CS=MCS-3 -- Chunk with length 68 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4410,6 +4540,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-3): 3f 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4425,6 +4556,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=34 data block (BSN 15, MCS-3): 02 45 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4485,6 +4617,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=32 data block (BSN 0, MCS-4): 14 41 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4498,6 +4631,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4508,6 +4642,7 @@ - Sending new block at BSN 2, CS=MCS-4 -- Chunk with length 468 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4518,6 +4653,7 @@ - Sending new block at BSN 3, CS=MCS-4 -- Chunk with length 424 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4528,6 +4664,7 @@ - Sending new block at BSN 4, CS=MCS-4 -- Chunk with length 380 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4538,6 +4675,7 @@ - Sending new block at BSN 5, CS=MCS-4 -- Chunk with length 336 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4548,6 +4686,7 @@ - Sending new block at BSN 6, CS=MCS-4 -- Chunk with length 292 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4558,6 +4697,7 @@ - Sending new block at BSN 7, CS=MCS-4 -- Chunk with length 248 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4568,6 +4708,7 @@ - Sending new block at BSN 8, CS=MCS-4 -- Chunk with length 204 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4578,6 +4719,7 @@ - Sending new block at BSN 9, CS=MCS-4 -- Chunk with length 160 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4588,6 +4730,7 @@ - Sending new block at BSN 10, CS=MCS-4 -- Chunk with length 116 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4598,6 +4741,7 @@ - Sending new block at BSN 11, CS=MCS-4 -- Chunk with length 72 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4613,6 +4757,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 12, MCS-4): 38 1d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4673,6 +4818,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-5): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4686,6 +4832,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4696,6 +4843,7 @@ - Sending new block at BSN 2, CS=MCS-5 -- Chunk with length 456 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4706,6 +4854,7 @@ - Sending new block at BSN 3, CS=MCS-5 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4716,6 +4865,7 @@ - Sending new block at BSN 4, CS=MCS-5 -- Chunk with length 344 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4726,6 +4876,7 @@ - Sending new block at BSN 5, CS=MCS-5 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4736,6 +4887,7 @@ - Sending new block at BSN 6, CS=MCS-5 -- Chunk with length 232 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4746,6 +4898,7 @@ - Sending new block at BSN 7, CS=MCS-5 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4756,6 +4909,7 @@ - Sending new block at BSN 8, CS=MCS-5 -- Chunk with length 120 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4766,6 +4920,7 @@ - Sending new block at BSN 9, CS=MCS-5 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4781,6 +4936,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-5): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4841,6 +4997,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-6): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4854,6 +5011,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4864,6 +5022,7 @@ - Sending new block at BSN 2, CS=MCS-6 -- Chunk with length 438 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4874,6 +5033,7 @@ - Sending new block at BSN 3, CS=MCS-6 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4884,6 +5044,7 @@ - Sending new block at BSN 4, CS=MCS-6 -- Chunk with length 290 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4894,6 +5055,7 @@ - Sending new block at BSN 5, CS=MCS-6 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4904,6 +5066,7 @@ - Sending new block at BSN 6, CS=MCS-6 -- Chunk with length 142 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4917,6 +5080,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-6): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4932,6 +5096,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-6): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4993,6 +5158,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-7): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5002,12 +5168,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(7) last_mcs(5) demanded_mcs(7)cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-7 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5022,6 +5189,7 @@ - Sending new block at BSN 3, CS=MCS-7 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5036,6 +5204,7 @@ - Sending new block at BSN 5, CS=MCS-7 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5050,6 +5219,7 @@ - Sending new block at BSN 7, CS=MCS-7 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5064,6 +5234,7 @@ - Sending new block at BSN 9, CS=MCS-7 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 9) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5081,6 +5252,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-7): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5142,6 +5314,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=56 data block (BSN 0, MCS-8): 14 71 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5152,12 +5325,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(8) demanded_mcs(8) cs_trans(8) +- initial_cs_dl(8) last_mcs(8) demanded_mcs(8)cs_trans(8) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-8 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5172,6 +5346,7 @@ - Sending new block at BSN 3, CS=MCS-8 -- Chunk with length 376 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5186,6 +5361,7 @@ - Sending new block at BSN 5, CS=MCS-8 -- Chunk with length 240 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5200,6 +5376,7 @@ - Sending new block at BSN 7, CS=MCS-8 -- Chunk with length 104 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5217,6 +5394,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=30 data block (BSN 8, MCS-8): 48 3d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5279,6 +5457,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-9): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5288,12 +5467,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(9) last_mcs(6) demanded_mcs(9)cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-9 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5308,6 +5488,7 @@ - Sending new block at BSN 3, CS=MCS-9 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5322,6 +5503,7 @@ - Sending new block at BSN 5, CS=MCS-9 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5339,6 +5521,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-9): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5356,6 +5539,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-9): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5402,11 +5586,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(6)cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5450,11 +5636,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 96 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(1) demanded_mcs(1) cs_trans(1) +- initial_cs_dl(1) last_mcs(1) demanded_mcs(1)cs_trans(1) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 98 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5498,11 +5686,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-2): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 92 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(2) demanded_mcs(2) cs_trans(2) +- initial_cs_dl(2) last_mcs(2) demanded_mcs(2)cs_trans(2) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 94 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5546,6 +5736,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5557,6 +5748,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-5): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5564,10 +5756,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-5): 0f 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7)cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7)cs_trans(7) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-7): 07 00 00 02 c0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 @@ -5612,6 +5805,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5623,6 +5817,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-6): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5630,10 +5825,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-6): 0f 40 00 00 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9)cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9)cs_trans(9) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-9): 07 00 00 02 28 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 @@ -5686,6 +5882,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-7): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5694,13 +5891,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-7): 0f 00 00 02 a0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5)cs_trans(5) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5)cs_trans(5) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-5): 07 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5752,6 +5951,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-9): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5760,13 +5960,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-9): 0f 00 00 02 00 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6)cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6)cs_trans(6) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-6): 07 40 00 02 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5780,3 +5982,233 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-5 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(2)cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 d2 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(2) demanded_mcs(2)cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 f2 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-4 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (44) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-4): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-4): 07 00 00 80 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(4) demanded_mcs(1)cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 d6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(1) demanded_mcs(1)cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 f6 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(6)cs_trans(6) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 2 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..c38417d 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,9 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_egprs_spb_dl === +Testing retx for MCS 6 to reseg_mcs 3 +Testing retx for MCS 5 to reseg_mcs 2 +Testing retx for MCS 4 to reseg_mcs 1 +Testing retx for MCS 6 to reseg_mcs 3 +=== end test_tbf_egprs_spb_dl === -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 11 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Thu Aug 11 06:14:16 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 11 Aug 2016 06:14:16 +0000 Subject: [PATCH] osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/655 to look at the new patch set (#12). Modify EGPRS DL TBF flow to support SPB Modify the EGPRS DL TBF flow to support Split block during Retx. This patch will also Upgrade the test suite with test cases to validate the EGPRS Downlink SPB for Retransmission Scenarios like MCS6->MCS3, MCS4->MCS1, MCS5->MCS2, MCS9->MCS3 MCS7->MCS2, MCS8->MCS3 have been simulated and Integration tested in NuRAN 1.0 hardware thoroughly. Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 --- M src/gprs_coding_scheme.h M src/pcu_main.cpp M src/pcu_vty.c M src/rlc.cpp M src/rlc.h M src/tbf.h M src/tbf_dl.cpp M tests/edge/EdgeTest.cpp M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 11 files changed, 949 insertions(+), 77 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/55/655/12 diff --git a/src/gprs_coding_scheme.h b/src/gprs_coding_scheme.h index 60a8e79..3b15372 100644 --- a/src/gprs_coding_scheme.h +++ b/src/gprs_coding_scheme.h @@ -113,7 +113,8 @@ static const char *modeName(Mode mode); static Scheme get_retx_mcs(const GprsCodingScheme mcs, - const GprsCodingScheme retx_mcs); + const GprsCodingScheme retx_mcs, + const unsigned arq_type); static enum Scheme egprs_mcs_retx_tbl[MAX_NUM_ARQ] [MAX_NUM_MCS][MAX_NUM_MCS]; @@ -232,8 +233,9 @@ } inline GprsCodingScheme::Scheme GprsCodingScheme::get_retx_mcs( const GprsCodingScheme mcs, - const GprsCodingScheme demanded_mcs) + const GprsCodingScheme demanded_mcs, + const unsigned arq_type) { - return egprs_mcs_retx_tbl[EGPRS_ARQ2][mcs.to_num() - 1] + return egprs_mcs_retx_tbl[arq_type][mcs.to_num() - 1] [demanded_mcs.to_num() - 1]; } diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2d86cda..e34d534 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -210,6 +210,12 @@ bts->dl_tbf_idle_msec = 2000; bts->llc_idle_ack_csec = 10; + /* + * By default resegmentation is supported in DL + * can also be configured through VTY + */ + bts->dl_arq_type = EGPRS_ARQ1; + msgb_set_talloc_ctx(tall_pcu_ctx); osmo_init_logging(&gprs_log_info); diff --git a/src/pcu_vty.c b/src/pcu_vty.c index 58fea99..96b87a6 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -129,6 +129,9 @@ vty_out(vty, " window-size %d %d%s", bts->ws_base, bts->ws_pdch, VTY_NEWLINE); + if (bts->dl_arq_type) + vty_out(vty, " dl arq-type %d%s", bts->dl_arq_type, VTY_NEWLINE); + if (bts->force_llc_lifetime == 0xffff) vty_out(vty, " queue lifetime infinite%s", VTY_NEWLINE); else if (bts->force_llc_lifetime) @@ -477,6 +480,20 @@ bts->max_mcs_dl = 0; bts->max_mcs_ul = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_pcu_dl_arq_type, + cfg_pcu_dl_arq_cmd, + "dl arq-type (0|1)", + EGPRS_STR "DL ARQ options\n" + "enable DL SPB support\n" + "enable DL ARQ2 support") +{ + struct gprs_rlcmac_bts *bts = bts_main_data(); + uint8_t dl_arq_type = atoi(argv[0]); + + bts->dl_arq_type = dl_arq_type; return CMD_SUCCESS; } @@ -954,6 +971,7 @@ install_element(PCU_NODE, &cfg_pcu_no_cs_downgrade_thrsh_cmd); install_element(PCU_NODE, &cfg_pcu_cs_lqual_ranges_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_cmd); + install_element(PCU_NODE, &cfg_pcu_dl_arq_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_max_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_max_cmd); diff --git a/src/rlc.cpp b/src/rlc.cpp index 6770043..b6b8879 100644 --- a/src/rlc.cpp +++ b/src/rlc.cpp @@ -285,7 +285,8 @@ } static void gprs_rlc_data_header_init(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding, unsigned int header_bits) + GprsCodingScheme cs, bool with_padding, unsigned int header_bits, + const unsigned int spb) { unsigned int i; unsigned int padding_bits = with_padding ? cs.optionalPaddingBits() : 0; @@ -300,7 +301,7 @@ for (i = 0; i < rlc->num_data_blocks; i++) { gprs_rlc_data_block_info_init(&rlc->block_info[i], cs, - with_padding); + with_padding, spb); rlc->data_offs_bits[i] = header_bits + padding_bits + @@ -310,21 +311,25 @@ } void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsDL()); + cs.numDataHeaderBitsDL(), spb); } void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding) { + /* + * last parameter is sent as 0 since common function used + * for both DL and UL + */ return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsUL()); + cs.numDataHeaderBitsUL(), 0); } void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { unsigned int data_len = cs.maxDataBlockBytes(); if (with_padding) @@ -336,7 +341,7 @@ rdbi->e = 1; rdbi->cv = 15; rdbi->pi = 0; - rdbi->spb = 0; + rdbi->spb = spb; } unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, @@ -411,8 +416,18 @@ enum egprs_puncturing_values gprs_get_punct_scheme( enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current) + const GprsCodingScheme &cs_current, + const unsigned int spb) { + + /* + * 10.4.8b of TS 44.060 + * If it is second segment of the block + * dont change the puncturing scheme + */ + if (spb == 3) + return punct; + /* TS 44.060 9.3.2.1.1 */ if ((GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS9) && (GprsCodingScheme::Scheme(cs_current) == GprsCodingScheme::MCS6)) { diff --git a/src/rlc.h b/src/rlc.h index 539b30b..66faf6f 100644 --- a/src/rlc.h +++ b/src/rlc.h @@ -206,18 +206,19 @@ }; void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding); void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, enum egprs_puncturing_values punct, enum egprs_puncturing_values punct2, int with_padding); void gprs_rlc_mcs_cps_decode(unsigned int cps, GprsCodingScheme cs, int *punct, int *punct2, int *with_padding); enum egprs_puncturing_values gprs_get_punct_scheme(enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current_trans); + const GprsCodingScheme &cs_current_trans, + const unsigned int spb); void gprs_update_punct_scheme(enum egprs_puncturing_values *punct, const GprsCodingScheme &cs); /* diff --git a/src/tbf.h b/src/tbf.h index 1bd7878..969836b 100644 --- a/src/tbf.h +++ b/src/tbf.h @@ -421,6 +421,11 @@ int analyse_errors(char *show_rbb, uint8_t ssn, ana_result *res); void schedule_next_frame(); + enum egprs_rlc_dl_reseg_bsn_state egprs_dl_get_data_buffer + (int bsn, uint8_t **block_data); + unsigned int get_egprs_dl_spb_status(int bsn); + unsigned int get_egprs_dl_spb_value(int bsn); + struct osmo_timer_list m_llc_timer; }; diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp index 07a747a..0395ed0 100644 --- a/src/tbf_dl.cpp +++ b/src/tbf_dl.cpp @@ -375,21 +375,27 @@ return -1; if (is_egprs_enabled()) { + /* Table 8.1.1.2 and Table 8.1.1.1 of 44.060 */ m_rlc.block(bsn)->cs_current_trans = - GprsCodingScheme::get_retx_mcs( - m_rlc.block(bsn)->cs_last, ms()->current_cs_dl()); + GprsCodingScheme::get_retx_mcs( + m_rlc.block(bsn)->cs_init, + ms()->current_cs_dl(), + bts->bts_data()->dl_arq_type); LOGP(DRLCMACDL, LOGL_DEBUG, - "- current_cs_dl(%d) demanded_mcs(%d) cs_trans(%d)\n", + "- initial_cs_dl(%d) last_mcs(%d) demanded_mcs(%d)" + "cs_trans(%d) arq_type(%d) bsn(%d)\n", + m_rlc.block(bsn)->cs_init.to_num(), m_rlc.block(bsn)->cs_last.to_num(), ms()->current_cs_dl().to_num(), - m_rlc.block(bsn)->cs_current_trans.to_num()); + m_rlc.block(bsn)->cs_current_trans.to_num(), + bts->bts_data()->dl_arq_type, bsn); /* TODO: Need to remove this check when MCS-8 -> MCS-6 * transistion is handled. * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 */ - if (m_rlc.block(bsn)->cs_last == GprsCodingScheme::MCS8) + if (m_rlc.block(bsn)->cs_init == GprsCodingScheme::MCS8) m_rlc.block(bsn)->cs_current_trans = GprsCodingScheme::MCS8; } else @@ -523,6 +529,11 @@ data = rlc_data->prepare(block_data_len); rlc_data->cs_last = cs; rlc_data->cs_current_trans = cs; + + /* Initialise the variable related to DL SPB */ + rlc_data->spb_status.block_status_dl = EGPRS_RESEG_DL_DEFAULT; + rlc_data->cs_init = cs; + rlc_data->len = block_data_len; rdbi = &(rlc_data->block_info); @@ -616,6 +627,7 @@ unsigned num_bsns; enum egprs_puncturing_values punct[ARRAY_SIZE(rlc.block_info)]; bool need_padding = false; + unsigned int spb = 0; /* * TODO: This is an experimental work-around to put 2 BSN into @@ -626,6 +638,7 @@ * the current limit. */ cs = m_rlc.block(index)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(index)->cs_init; bsns[0] = index; num_bsns = 1; @@ -634,7 +647,19 @@ num_bsns += 1; } - if (num_bsns == 1) { + /* + * if the intial mcs is 8 and retransmission mcs is either 6 or 3 + * we have to include the padding of 6 octets in first segment + */ + if ((GprsCodingScheme::Scheme(cs_init) == GprsCodingScheme::MCS8) && + (GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS6 || + GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS3)) { + if ((get_egprs_dl_spb_status(index) == + EGPRS_RESEG_DL_DEFAULT) || + (get_egprs_dl_spb_status(index) == + EGPRS_RESEG_SECOND_SEG_SENT)) + need_padding = true; + } else if (num_bsns == 1) { /* TODO: remove the conditional when MCS-6 padding isn't * failing to be decoded by MEs anymore */ /* TODO: support of MCS-8 -> MCS-6 transition should be @@ -646,7 +671,14 @@ cs.decToSingleBlock(&need_padding); } - gprs_rlc_data_info_init_dl(&rlc, cs, need_padding); + spb = get_egprs_dl_spb_value(index); + + LOGP(DRLCMACDL, LOGL_DEBUG, "- need_padding %d spb_status %d spb %d" + "(BSN1 %d BSN2 %d)\n", + need_padding, + get_egprs_dl_spb_status(index), spb, index, index2); + + gprs_rlc_data_info_init_dl(&rlc, cs, need_padding, spb); rlc.usf = 7; /* will be set at scheduler */ rlc.pr = 0; /* FIXME: power reduction */ @@ -665,10 +697,9 @@ data_block_idx++) { int bsn; - GprsCodingScheme cs_enc; uint8_t *block_data; gprs_rlc_data_block_info *rdbi, *block_info; - enum egprs_puncturing_values punct_scheme; + enum egprs_rlc_dl_reseg_bsn_state reseg_status; /* Check if there are more blocks than BSNs */ if (data_block_idx < num_bsns) @@ -676,38 +707,43 @@ else bsn = bsns[0]; - cs_enc = m_rlc.block(bsn)->cs_current_trans; - /* get data and header from current block */ - block_data = m_rlc.block(bsn)->block; - /* Get current puncturing scheme from block */ - punct_scheme = gprs_get_punct_scheme( + + m_rlc.block(bsn)->next_ps = gprs_get_punct_scheme( m_rlc.block(bsn)->next_ps, - m_rlc.block(bsn)->cs_last, cs); + m_rlc.block(bsn)->cs_last, cs, spb); if (cs.isEgprs()) { - OSMO_ASSERT(punct_scheme >= EGPRS_PS_1); - OSMO_ASSERT(punct_scheme <= EGPRS_PS_3); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps >= EGPRS_PS_1); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps <= EGPRS_PS_3); } - punct[data_block_idx] = punct_scheme; + punct[data_block_idx] = m_rlc.block(bsn)->next_ps; rdbi = &rlc.block_info[data_block_idx]; block_info = &m_rlc.block(bsn)->block_info; - if(rdbi->data_len != m_rlc.block(bsn)->len) { - LOGP(DRLCMACDL, LOGL_ERROR, - "ERROR: Expected len = %d for %s instead of " - "%d in data unit %d (BSN %d, %s)\n", - rdbi->data_len, cs.name(), m_rlc.block(bsn)->len, - data_block_idx, bsn, cs_enc.name()); - OSMO_ASSERT(rdbi->data_len == m_rlc.block(bsn)->len); - } - - /* TODO: Need to handle 2 same bsns - * in header type 1 + /* + * get data and header from current block + * function returns the reseg status */ - gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, - cs); + reseg_status = egprs_dl_get_data_buffer(bsn, &block_data); + m_rlc.block(bsn)->spb_status.block_status_dl = reseg_status; + + /* + * If it is first segment of the split block set the state of + * bsn to nacked. If it is the first segment dont update the + * next ps value of bsn. since next segment also needs same cps + */ + if (spb == 2) + m_window.m_v_b.mark_nacked(bsn); + else { + /* + * TODO: Need to handle 2 same bsns + * in header type 1 + */ + gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, + cs); + } m_rlc.block(bsn)->cs_last = cs; rdbi->e = block_info->e; @@ -1169,3 +1205,119 @@ keep_time_frames = msecs_to_frames(bts_data()->dl_tbf_idle_msec); return frames_since_last_drain(fn) <= keep_time_frames; } + +/* + * This function returns the pointer to data which needs + * to be copied. Also updates the status of the block related to + * Split block handling in the RLC/MAC block. + */ +enum egprs_rlc_dl_reseg_bsn_state + gprs_rlcmac_dl_tbf::egprs_dl_get_data_buffer(int bsn, + uint8_t **block_data) +{ + gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state *block_status_dl = + &rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + *block_data = &rlc_data->block[0]; + + /* + * Table 10.3a.0.1 of 44.060 + * MCS6,9: second segment starts at 74/2 = 37 + * MCS5,7: second segment starts at 56/2 = 28 + * MCS8: second segment starts at 31 + * MCS4: second segment starts at 44/2 = 22 + */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + if (*block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + switch (GprsCodingScheme::Scheme(cs_init)) { + case GprsCodingScheme::MCS6 : + case GprsCodingScheme::MCS9 : + *block_data = &rlc_data->block[37]; + break; + case GprsCodingScheme::MCS7 : + case GprsCodingScheme::MCS5 : + *block_data = &rlc_data->block[28]; + break; + case GprsCodingScheme::MCS8 : + *block_data = &rlc_data->block[31]; + break; + case GprsCodingScheme::MCS4 : + *block_data = &rlc_data->block[22]; + break; + default: + LOGP(DRLCMACDL, LOGL_ERROR, "Software error: " + "--%s hit invalid condition. headerType(%d) " + " blockstatus(%d) cs(%s) PLEASE FIX!\n", name(), + cs_current_trans.headerTypeData(), + *block_status_dl, cs_init.name()); + break; + + } + return EGPRS_RESEG_SECOND_SEG_SENT; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } + } + return EGPRS_RESEG_DL_DEFAULT; +} + +/* + * This function returns the status of split block + * for RLC/MAC block. + */ +unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_status(const int bsn) +{ + const gprs_rlc_data *rlc_data = m_rlc.block(bsn); + + return rlc_data->spb_status.block_status_dl; +} + +/* + * This function returns the spb value to be sent OTA + * for RLC/MAC block. + */ +unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_value(const int bsn) +{ + struct gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state block_status_dl = + rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + + /* Table 10.4.8b.1 of 44.060 */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + /* + * if we are sending the second segment the spb should be 3 + * other wise it should be 2 + */ + if (block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + return 3; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return 2; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return 2; + } + } + /* Non SPB cases 0 is reurned */ + return 0; +} diff --git a/tests/edge/EdgeTest.cpp b/tests/edge/EdgeTest.cpp index 807102c..9081d4d 100644 --- a/tests/edge/EdgeTest.cpp +++ b/tests/edge/EdgeTest.cpp @@ -517,7 +517,7 @@ /* TS 44.060, B.1 */ cs = GprsCodingScheme::CS4; - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -570,7 +570,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -592,7 +592,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -630,7 +630,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -669,7 +669,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -694,7 +694,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -719,7 +719,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -740,7 +740,7 @@ OSMO_ASSERT(data[0] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -777,7 +777,7 @@ cs = GprsCodingScheme::MCS4; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -835,7 +835,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -872,7 +872,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -923,7 +923,7 @@ OSMO_ASSERT(data[3] == 0); /* Block 3 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -967,7 +967,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -993,7 +993,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1020,7 +1020,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1074,7 +1074,7 @@ block_idx++) { struct gprs_rlc_data_info rlc; - gprs_rlc_data_info_init_dl(&rlc, cs, false); + gprs_rlc_data_info_init_dl(&rlc, cs, false, 0); memset(bits, pattern, sizeof(bits)); Decoding::rlc_copy_to_aligned_buffer( @@ -1118,12 +1118,14 @@ struct gprs_rlc_data_info rlc; printf("=== start %s ===\n", __func__); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::CS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::CS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 24); OSMO_ASSERT(rlc.block_info[0].data_len == 20); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::MCS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::MCS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 33); OSMO_ASSERT(rlc.block_info[0].data_len == 22); diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..18cc5cb 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -1814,6 +1814,201 @@ } +static void egprs_spb_to_normal_validation(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + uint16_t bsn1, bsn2, bsn3; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + struct gprs_rlc_dl_header_egprs_2 *egprs2; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + if ((mcs == 6) && (demanded_mcs == 3)) { + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + bsn1 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) + || (egprs2->bsn1_lo); + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(bsn1 == 0); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + bsn2 = (egprs3->bsn1_hi << 9) || (egprs3->bsn1_mid << 1) || + (egprs3->bsn1_lo); + OSMO_ASSERT(bsn2 == bsn1); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Handle (MCS3, MCS3) -> MCS6 case */ + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + mcs)); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs2->cps == 0); + bsn3 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) || + (egprs2->bsn1_lo); + OSMO_ASSERT(bsn3 == bsn2); + + tbf_cleanup(dl_tbf); + } +} +static void establish_and_use_egprs_dl_tbf_for_spb(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + /* TODO: Need to support of MCS8 -> MCS6 ->MCS3 transistion + * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 + * dated 2016-02-07 23:45:40 (UTC) + */ + if (((mcs == 5) && (demanded_mcs == 2)) || + ((mcs == 6) && (demanded_mcs == 3)) || + ((mcs == 4) && (demanded_mcs == 1))) { + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + tbf_cleanup(dl_tbf); + } +} + static void establish_and_use_egprs_dl_tbf_for_retx(BTS *the_bts, int mcs, int demanded_mcs) { @@ -1972,6 +2167,9 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; + /* First parameter is current MCS, second one is demanded_mcs */ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 6); @@ -1981,6 +2179,38 @@ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 9); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 7, 5); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 9, 6); + + printf("=== end %s ===\n", __func__); +} + +static void test_tbf_egprs_spb_dl(void) +{ + BTS the_bts; + gprs_rlcmac_bts *bts; + uint8_t ts_no = 4; + int i, j; + + printf("=== start %s ===\n", __func__); + + bts = the_bts.bts_data(); + bts->cs_downgrade_threshold = 0; + setup_bts(&the_bts, ts_no); + bts->dl_tbf_idle_msec = 200; + bts->egprs_enabled = 1; + + /* ARQ I resegmentation support */ + bts->dl_arq_type = EGPRS_ARQ1; + + /* + * First parameter is current MCS, second one is demanded_mcs + * currently only MCS5->MCS2, MCS6->3, MCS4->MCS1 is tested in UT + * rest scenarios has been integration tested + */ + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 6, 3); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 5, 2); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 4, 1); + /* check MCS6->(MCS3+MCS3)->MCS6 case */ + egprs_spb_to_normal_validation(&the_bts, 6, 3); printf("=== end %s ===\n", __func__); } @@ -1999,6 +2229,8 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; for (i = 1; i <= 9; i++) establish_and_use_egprs_dl_tbf(&the_bts, i); @@ -2071,6 +2303,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_egprs_spb_dl(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..7b3f339 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -72,6 +72,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -81,6 +82,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -157,6 +159,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -166,6 +169,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -242,6 +246,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -251,6 +256,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -259,6 +265,7 @@ - Sending new block at BSN 2, CS=CS-1 -- Chunk with length 160 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=13 block=3 data=07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b @@ -267,6 +274,7 @@ - Sending new block at BSN 3, CS=CS-1 -- Chunk with length 140 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=17 block=4 data=07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @@ -275,6 +283,7 @@ - Sending new block at BSN 4, CS=CS-1 -- Chunk with length 120 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=21 block=5 data=07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 @@ -283,6 +292,7 @@ - Sending new block at BSN 5, CS=CS-1 -- Chunk with length 100 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=26 block=6 data=07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 @@ -291,6 +301,7 @@ - Sending new block at BSN 6, CS=CS-1 -- Chunk with length 80 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=30 block=7 data=07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b @@ -299,6 +310,7 @@ - Sending new block at BSN 7, CS=CS-1 -- Chunk with length 60 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=34 block=8 data=07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f @@ -307,6 +319,7 @@ - Sending new block at BSN 8, CS=CS-1 -- Chunk with length 40 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=39 block=9 data=07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 @@ -315,6 +328,7 @@ - Sending new block at BSN 9, CS=CS-1 -- Chunk with length 20 would exactly fit into space (20): add length header with LI=0, to make frame extend to next block, and we are done data block (BSN 9, CS-1): 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=43 block=10 data=07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 @@ -326,6 +340,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=47 block=11 data=07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 @@ -334,6 +349,7 @@ - Sending new block at BSN 11, CS=CS-1 -- Chunk with length 182 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=52 block=0 data=07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 @@ -342,6 +358,7 @@ - Sending new block at BSN 12, CS=CS-1 -- Chunk with length 162 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=56 block=1 data=07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 @@ -350,6 +367,7 @@ - Sending new block at BSN 13, CS=CS-1 -- Chunk with length 142 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 13, CS-1): 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=60 block=2 data=07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d @@ -358,6 +376,7 @@ - Sending new block at BSN 14, CS=CS-1 -- Chunk with length 122 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=65 block=3 data=07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 @@ -366,6 +385,7 @@ - Sending new block at BSN 15, CS=CS-1 -- Chunk with length 102 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=69 block=4 data=07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 @@ -374,6 +394,7 @@ - Sending new block at BSN 16, CS=CS-1 -- Chunk with length 82 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=73 block=5 data=07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 @@ -382,6 +403,7 @@ - Sending new block at BSN 17, CS=CS-1 -- Chunk with length 62 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=78 block=6 data=07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d @@ -390,6 +412,7 @@ - Sending new block at BSN 18, CS=CS-1 -- Chunk with length 42 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=82 block=7 data=07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 @@ -398,6 +421,7 @@ - Sending new block at BSN 19, CS=CS-1 -- Chunk with length 22 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=86 block=8 data=07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 @@ -411,6 +435,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=16 data block (BSN 20, CS-1): 0a 41 c6 c7 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -449,6 +474,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 data block (BSN 21, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -468,6 +494,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 22, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FINISHED) @@ -1481,6 +1508,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 0, CS-1): 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 MSG = 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 @@ -1491,6 +1519,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 1, CS-1): 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 MSG = 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 @@ -1501,6 +1530,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FINISHED data block (BSN 2, CS-1): 4d 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling cannot be scheduled in this TS 7 (first control TS 4) @@ -1784,6 +1814,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=10 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 0, CS-4): 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654292 TS 7 @@ -1797,6 +1828,7 @@ TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) downlink (V(A)==0 .. V(S)==1) - Restarting at BSN 0, because all blocks have been transmitted. - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-4): 07 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 @@ -2365,6 +2397,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654279 block=10 data=00 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 @@ -2384,6 +2417,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -2406,6 +2440,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654288 block=0 data=00 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 @@ -2425,6 +2460,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654292 block=1 data=00 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2447,6 +2483,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654296 block=2 data=00 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c @@ -2466,6 +2503,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654301 block=3 data=00 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b @@ -2488,6 +2526,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 6, CS-1): 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654305 block=4 data=00 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 @@ -2507,6 +2546,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654309 block=5 data=00 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 @@ -2526,6 +2566,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654314 block=6 data=00 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 @@ -2548,6 +2589,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654318 block=7 data=00 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 @@ -2567,6 +2609,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654322 block=8 data=00 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2589,6 +2632,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654327 block=9 data=00 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c @@ -2608,6 +2652,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654331 block=10 data=00 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b @@ -2630,6 +2675,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 13, CS-1): 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654335 block=11 data=00 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 @@ -2649,6 +2695,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654340 block=0 data=00 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 @@ -2668,6 +2715,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654344 block=1 data=00 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 @@ -2690,6 +2738,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654348 block=2 data=00 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 @@ -2709,6 +2758,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654353 block=3 data=00 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2731,6 +2781,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654357 block=4 data=00 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c @@ -2750,6 +2801,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654361 block=5 data=00 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b @@ -2772,6 +2824,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 20, CS-1): 16 35 45 54 20 32 38 4c 4c 43 20 50 41 43 4b 45 54 20 32 39 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because 20 blocks sent. TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW): Scheduling polling at FN 2654379 TS 7 @@ -2795,6 +2848,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 21, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) msg block (BSN 21, CS-1): 07 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654370 block=7 data=00 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 @@ -2814,6 +2868,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 22, CS-1): 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) msg block (BSN 22, CS-1): 07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654374 block=8 data=07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 @@ -2836,6 +2891,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 23, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) msg block (BSN 23, CS-1): 07 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654379 block=9 data=00 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 @@ -2855,6 +2911,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 24, CS-1): 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) msg block (BSN 24, CS-1): 07 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654383 block=10 data=00 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2877,6 +2934,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 25, CS-1): 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 25 BSN2 -1) - Copying data unit 0 (BSN 25) msg block (BSN 25, CS-1): 07 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654387 block=11 data=00 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c @@ -2896,6 +2954,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 26, CS-1): 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 26 BSN2 -1) - Copying data unit 0 (BSN 26) msg block (BSN 26, CS-1): 07 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654392 block=0 data=00 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b @@ -2918,6 +2977,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 27, CS-1): 16 35 45 54 20 33 38 4c 4c 43 20 50 41 43 4b 45 54 20 33 39 +- need_padding 0 spb_status 0 spb 0(BSN1 27 BSN2 -1) - Copying data unit 0 (BSN 27) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) @@ -3028,6 +3088,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654405 block=3 data=00 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 @@ -3047,6 +3108,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654409 block=4 data=00 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 @@ -3066,6 +3128,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (16) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654413 block=5 data=00 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 @@ -3085,6 +3148,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (14) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654418 block=6 data=00 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 @@ -3104,6 +3168,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654422 block=7 data=00 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -3123,6 +3188,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654426 block=8 data=00 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 @@ -3142,6 +3208,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654431 block=9 data=00 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b @@ -3161,6 +3228,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654435 block=10 data=00 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 @@ -3180,6 +3248,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654439 block=11 data=00 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 @@ -3199,6 +3268,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654444 block=0 data=00 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c @@ -3218,6 +3288,7 @@ Complete DL frame for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=21 TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 10, CS-1): 4d 43 20 50 41 43 4b 45 54 20 30 39 20 28 54 42 46 20 32 29 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654461 TS 7 @@ -3698,6 +3769,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 0, MCS-1): 14 15 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3711,6 +3783,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3721,6 +3794,7 @@ - Sending new block at BSN 2, CS=MCS-1 -- Chunk with length 490 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3731,6 +3805,7 @@ - Sending new block at BSN 3, CS=MCS-1 -- Chunk with length 468 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3741,6 +3816,7 @@ - Sending new block at BSN 4, CS=MCS-1 -- Chunk with length 446 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3751,6 +3827,7 @@ - Sending new block at BSN 5, CS=MCS-1 -- Chunk with length 424 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3761,6 +3838,7 @@ - Sending new block at BSN 6, CS=MCS-1 -- Chunk with length 402 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3771,6 +3849,7 @@ - Sending new block at BSN 7, CS=MCS-1 -- Chunk with length 380 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3781,6 +3860,7 @@ - Sending new block at BSN 8, CS=MCS-1 -- Chunk with length 358 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3791,6 +3871,7 @@ - Sending new block at BSN 9, CS=MCS-1 -- Chunk with length 336 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3801,6 +3882,7 @@ - Sending new block at BSN 10, CS=MCS-1 -- Chunk with length 314 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3811,6 +3893,7 @@ - Sending new block at BSN 11, CS=MCS-1 -- Chunk with length 292 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3821,6 +3904,7 @@ - Sending new block at BSN 12, CS=MCS-1 -- Chunk with length 270 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3831,6 +3915,7 @@ - Sending new block at BSN 13, CS=MCS-1 -- Chunk with length 248 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3841,6 +3926,7 @@ - Sending new block at BSN 14, CS=MCS-1 -- Chunk with length 226 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3851,6 +3937,7 @@ - Sending new block at BSN 15, CS=MCS-1 -- Chunk with length 204 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3861,6 +3948,7 @@ - Sending new block at BSN 16, CS=MCS-1 -- Chunk with length 182 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3871,6 +3959,7 @@ - Sending new block at BSN 17, CS=MCS-1 -- Chunk with length 160 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3881,6 +3970,7 @@ - Sending new block at BSN 18, CS=MCS-1 -- Chunk with length 138 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3891,6 +3981,7 @@ - Sending new block at BSN 19, CS=MCS-1 -- Chunk with length 116 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 19, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3901,6 +3992,7 @@ - Sending new block at BSN 20, CS=MCS-1 -- Chunk with length 94 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 20, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3911,6 +4003,7 @@ - Sending new block at BSN 21, CS=MCS-1 -- Chunk with length 72 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 21, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3921,6 +4014,7 @@ - Sending new block at BSN 22, CS=MCS-1 -- Chunk with length 50 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 22, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3931,6 +4025,7 @@ - Sending new block at BSN 23, CS=MCS-1 -- Chunk with length 28 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 23, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3946,6 +4041,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 24, MCS-1): 0c 1d 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4006,6 +4102,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=16 data block (BSN 0, MCS-2): 14 21 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4019,6 +4116,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4029,6 +4127,7 @@ - Sending new block at BSN 2, CS=MCS-2 -- Chunk with length 484 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4039,6 +4138,7 @@ - Sending new block at BSN 3, CS=MCS-2 -- Chunk with length 456 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4049,6 +4149,7 @@ - Sending new block at BSN 4, CS=MCS-2 -- Chunk with length 428 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4059,6 +4160,7 @@ - Sending new block at BSN 5, CS=MCS-2 -- Chunk with length 400 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4069,6 +4171,7 @@ - Sending new block at BSN 6, CS=MCS-2 -- Chunk with length 372 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4079,6 +4182,7 @@ - Sending new block at BSN 7, CS=MCS-2 -- Chunk with length 344 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4089,6 +4193,7 @@ - Sending new block at BSN 8, CS=MCS-2 -- Chunk with length 316 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4099,6 +4204,7 @@ - Sending new block at BSN 9, CS=MCS-2 -- Chunk with length 288 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4109,6 +4215,7 @@ - Sending new block at BSN 10, CS=MCS-2 -- Chunk with length 260 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4119,6 +4226,7 @@ - Sending new block at BSN 11, CS=MCS-2 -- Chunk with length 232 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4129,6 +4237,7 @@ - Sending new block at BSN 12, CS=MCS-2 -- Chunk with length 204 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4139,6 +4248,7 @@ - Sending new block at BSN 13, CS=MCS-2 -- Chunk with length 176 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4149,6 +4259,7 @@ - Sending new block at BSN 14, CS=MCS-2 -- Chunk with length 148 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4159,6 +4270,7 @@ - Sending new block at BSN 15, CS=MCS-2 -- Chunk with length 120 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4169,6 +4281,7 @@ - Sending new block at BSN 16, CS=MCS-2 -- Chunk with length 92 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4179,6 +4292,7 @@ - Sending new block at BSN 17, CS=MCS-2 -- Chunk with length 64 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4189,6 +4303,7 @@ - Sending new block at BSN 18, CS=MCS-2 -- Chunk with length 36 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4204,6 +4319,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=18 data block (BSN 19, MCS-2): 10 25 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4264,6 +4380,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=25 data block (BSN 0, MCS-3): 14 33 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4277,6 +4394,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4287,6 +4405,7 @@ - Sending new block at BSN 2, CS=MCS-3 -- Chunk with length 475 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4297,6 +4416,7 @@ - Sending new block at BSN 3, CS=MCS-3 -- Chunk with length 438 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4307,6 +4427,7 @@ - Sending new block at BSN 4, CS=MCS-3 -- Chunk with length 401 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4317,6 +4438,7 @@ - Sending new block at BSN 5, CS=MCS-3 -- Chunk with length 364 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4327,6 +4449,7 @@ - Sending new block at BSN 6, CS=MCS-3 -- Chunk with length 327 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4337,6 +4460,7 @@ - Sending new block at BSN 7, CS=MCS-3 -- Chunk with length 290 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4347,6 +4471,7 @@ - Sending new block at BSN 8, CS=MCS-3 -- Chunk with length 253 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4357,6 +4482,7 @@ - Sending new block at BSN 9, CS=MCS-3 -- Chunk with length 216 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4367,6 +4493,7 @@ - Sending new block at BSN 10, CS=MCS-3 -- Chunk with length 179 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4377,6 +4504,7 @@ - Sending new block at BSN 11, CS=MCS-3 -- Chunk with length 142 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4387,6 +4515,7 @@ - Sending new block at BSN 12, CS=MCS-3 -- Chunk with length 105 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4397,6 +4526,7 @@ - Sending new block at BSN 13, CS=MCS-3 -- Chunk with length 68 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4410,6 +4540,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-3): 3f 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4425,6 +4556,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=34 data block (BSN 15, MCS-3): 02 45 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4485,6 +4617,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=32 data block (BSN 0, MCS-4): 14 41 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4498,6 +4631,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4508,6 +4642,7 @@ - Sending new block at BSN 2, CS=MCS-4 -- Chunk with length 468 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4518,6 +4653,7 @@ - Sending new block at BSN 3, CS=MCS-4 -- Chunk with length 424 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4528,6 +4664,7 @@ - Sending new block at BSN 4, CS=MCS-4 -- Chunk with length 380 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4538,6 +4675,7 @@ - Sending new block at BSN 5, CS=MCS-4 -- Chunk with length 336 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4548,6 +4686,7 @@ - Sending new block at BSN 6, CS=MCS-4 -- Chunk with length 292 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4558,6 +4697,7 @@ - Sending new block at BSN 7, CS=MCS-4 -- Chunk with length 248 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4568,6 +4708,7 @@ - Sending new block at BSN 8, CS=MCS-4 -- Chunk with length 204 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4578,6 +4719,7 @@ - Sending new block at BSN 9, CS=MCS-4 -- Chunk with length 160 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4588,6 +4730,7 @@ - Sending new block at BSN 10, CS=MCS-4 -- Chunk with length 116 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4598,6 +4741,7 @@ - Sending new block at BSN 11, CS=MCS-4 -- Chunk with length 72 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4613,6 +4757,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 12, MCS-4): 38 1d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4673,6 +4818,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-5): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4686,6 +4832,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4696,6 +4843,7 @@ - Sending new block at BSN 2, CS=MCS-5 -- Chunk with length 456 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4706,6 +4854,7 @@ - Sending new block at BSN 3, CS=MCS-5 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4716,6 +4865,7 @@ - Sending new block at BSN 4, CS=MCS-5 -- Chunk with length 344 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4726,6 +4876,7 @@ - Sending new block at BSN 5, CS=MCS-5 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4736,6 +4887,7 @@ - Sending new block at BSN 6, CS=MCS-5 -- Chunk with length 232 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4746,6 +4898,7 @@ - Sending new block at BSN 7, CS=MCS-5 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4756,6 +4909,7 @@ - Sending new block at BSN 8, CS=MCS-5 -- Chunk with length 120 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4766,6 +4920,7 @@ - Sending new block at BSN 9, CS=MCS-5 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4781,6 +4936,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-5): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4841,6 +4997,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-6): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4854,6 +5011,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4864,6 +5022,7 @@ - Sending new block at BSN 2, CS=MCS-6 -- Chunk with length 438 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4874,6 +5033,7 @@ - Sending new block at BSN 3, CS=MCS-6 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4884,6 +5044,7 @@ - Sending new block at BSN 4, CS=MCS-6 -- Chunk with length 290 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4894,6 +5055,7 @@ - Sending new block at BSN 5, CS=MCS-6 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4904,6 +5066,7 @@ - Sending new block at BSN 6, CS=MCS-6 -- Chunk with length 142 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4917,6 +5080,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-6): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4932,6 +5096,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-6): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4993,6 +5158,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-7): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5002,12 +5168,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(7) last_mcs(5) demanded_mcs(7)cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-7 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5022,6 +5189,7 @@ - Sending new block at BSN 3, CS=MCS-7 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5036,6 +5204,7 @@ - Sending new block at BSN 5, CS=MCS-7 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5050,6 +5219,7 @@ - Sending new block at BSN 7, CS=MCS-7 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5064,6 +5234,7 @@ - Sending new block at BSN 9, CS=MCS-7 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 9) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5081,6 +5252,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-7): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5142,6 +5314,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=56 data block (BSN 0, MCS-8): 14 71 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5152,12 +5325,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(8) demanded_mcs(8) cs_trans(8) +- initial_cs_dl(8) last_mcs(8) demanded_mcs(8)cs_trans(8) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-8 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5172,6 +5346,7 @@ - Sending new block at BSN 3, CS=MCS-8 -- Chunk with length 376 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5186,6 +5361,7 @@ - Sending new block at BSN 5, CS=MCS-8 -- Chunk with length 240 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5200,6 +5376,7 @@ - Sending new block at BSN 7, CS=MCS-8 -- Chunk with length 104 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5217,6 +5394,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=30 data block (BSN 8, MCS-8): 48 3d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5279,6 +5457,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-9): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5288,12 +5467,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(9) last_mcs(6) demanded_mcs(9)cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-9 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5308,6 +5488,7 @@ - Sending new block at BSN 3, CS=MCS-9 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5322,6 +5503,7 @@ - Sending new block at BSN 5, CS=MCS-9 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5339,6 +5521,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-9): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5356,6 +5539,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-9): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5402,11 +5586,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(6)cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5450,11 +5636,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 96 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(1) demanded_mcs(1) cs_trans(1) +- initial_cs_dl(1) last_mcs(1) demanded_mcs(1)cs_trans(1) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 98 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5498,11 +5686,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-2): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 92 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(2) demanded_mcs(2) cs_trans(2) +- initial_cs_dl(2) last_mcs(2) demanded_mcs(2)cs_trans(2) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 94 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5546,6 +5736,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5557,6 +5748,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-5): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5564,10 +5756,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-5): 0f 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7)cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7)cs_trans(7) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-7): 07 00 00 02 c0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 @@ -5612,6 +5805,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5623,6 +5817,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-6): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5630,10 +5825,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-6): 0f 40 00 00 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9)cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9)cs_trans(9) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-9): 07 00 00 02 28 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 @@ -5686,6 +5882,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-7): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5694,13 +5891,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-7): 0f 00 00 02 a0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5)cs_trans(5) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5)cs_trans(5) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-5): 07 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5752,6 +5951,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-9): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5760,13 +5960,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-9): 0f 00 00 02 00 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6)cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6)cs_trans(6) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-6): 07 40 00 02 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5780,3 +5982,233 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-5 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(2)cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 d2 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(2) demanded_mcs(2)cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 f2 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-4 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (44) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-4): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-4): 07 00 00 80 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(4) demanded_mcs(1)cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 d6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(1) demanded_mcs(1)cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 f6 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(6)cs_trans(6) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 2 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..c38417d 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,9 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_egprs_spb_dl === +Testing retx for MCS 6 to reseg_mcs 3 +Testing retx for MCS 5 to reseg_mcs 2 +Testing retx for MCS 4 to reseg_mcs 1 +Testing retx for MCS 6 to reseg_mcs 3 +=== end test_tbf_egprs_spb_dl === -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 12 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Thu Aug 11 06:15:32 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 11 Aug 2016 06:15:32 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 12: (1 comment) https://gerrit.osmocom.org/#/c/655/10/src/rlc.cpp File src/rlc.cpp: PS10, Line 427: > where is the '3' defined here? How does it relate to the comment above? i.e 10.4.8b section of TS 44.060 explains the spb values. I will introduce the #define for the same. -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 12 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 11 06:16:07 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Thu, 11 Aug 2016 06:16:07 +0000 Subject: libosmocore[master]: Add function to send TRAP over Control Interface In-Reply-To: References: Message-ID: Patch Set 1: (1 comment) https://gerrit.osmocom.org/#/c/649/1/src/ctrl/control_if.c File src/ctrl/control_if.c: Line 126: int ctrl_cmd_send_trap(struct ctrl_handle *ctrl, char *name, char *value) > I think the problem is that 'struct ctrl_cmd' doesn't define its name and v With a quick test in libosmocore we can make id, variable, reply const. For reply we need to modify the unused(!!!) get_rate_ctr_group. General note: API is a lot harder than pushing the first idea into a library. I would like to see interfaces grow in an application and if useful and mature move to the library. -- To view, visit https://gerrit.osmocom.org/649 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ic0b8d88c4f5c4d42c3f8fb754f8eabf049c9e388 Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 11 06:17:39 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Thu, 11 Aug 2016 06:17:39 +0000 Subject: osmo-pcu[master]: jenkins.sh: ensure $MAKE is set In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/679 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I2da8acdfe3abf79f68db4d00d04a7d162f0123ce Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 11 06:18:31 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Thu, 11 Aug 2016 06:18:31 +0000 Subject: osmo-pcu[master]: jenkins.sh: change build matrix to $with_dsp and $with_vty In-Reply-To: References: Message-ID: Patch Set 2: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/682 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia120f918342dc9563814252258b73bfb267e5253 Gerrit-PatchSet: 2 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 11 06:18:50 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Thu, 11 Aug 2016 06:18:50 +0000 Subject: osmo-pcu[master]: jenkins.sh: more quotes, cosmetics, less dup In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/681 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: If148632c3f340a8a395fa432135e593fecc41e82 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 11 06:19:44 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Thu, 11 Aug 2016 06:19:44 +0000 Subject: osmo-pcu[master]: jenkins.sh: use absolute paths instead of 'cd ..' and $PWD In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 Okay, but is there a good reason for it? -- To view, visit https://gerrit.osmocom.org/680 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: If79d283fa0a559bb7ea319c513d09466eff523d1 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 11 06:22:29 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Thu, 11 Aug 2016 06:22:29 +0000 Subject: osmo-pcu[master]: NOT-FOR-MERGE/llc: fix NULL-pointer check gprs_llc_queue::si... In-Reply-To: References: Message-ID: Patch Set 1: lynxis: ping? -- To view, visit https://gerrit.osmocom.org/213 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I918a094e0dc59098a9eb00d152c9ae42d36b3a99 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: lynxis lazus Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 11 06:44:18 2016 From: gerrit-no-reply at lists.osmocom.org (pravin) Date: Thu, 11 Aug 2016 06:44:18 +0000 Subject: [PATCH] osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Hello Max, Neels Hofmeyr, Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/416 to look at the new patch set (#15). Add decoding of compressed bitmap in EPDAN Implemented tree based algorithm to decode compressed bitmap in EPDAN as described in section 9.1.10 of 3GPP 44.060. This algorithm intends to improve the performance over existing method. New Regression test is added under bitcomp directory. Test case is added to validate decompressed result of the bitmap Present in EPDAN. Test is done for multiple bitmaps of varying length. Invalid inputs are also part of the test vector. Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce --- M src/Makefile.am M src/decoding.cpp A src/egprs_rlc_compression.cpp A src/egprs_rlc_compression.h M src/pcu_main.cpp M tests/Makefile.am A tests/bitcomp/BitcompTest A tests/bitcomp/BitcompTest.cpp A tests/bitcomp/BitcompTest.ok M tests/testsuite.at 10 files changed, 603 insertions(+), 20 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/16/416/15 diff --git a/src/Makefile.am b/src/Makefile.am index 9bdec2f..9b047e7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -62,7 +62,8 @@ rlc.cpp \ osmobts_sock.cpp \ gprs_codel.c \ - gprs_coding_scheme.cpp + gprs_coding_scheme.cpp \ + egprs_rlc_compression.cpp bin_PROGRAMS = \ osmo-pcu @@ -94,7 +95,8 @@ pcu_utils.h \ cxx_linuxlist.h \ gprs_codel.h \ - gprs_coding_scheme.h + gprs_coding_scheme.h \ + egprs_rlc_compression.h osmo_pcu_SOURCES = pcu_main.cpp diff --git a/src/decoding.cpp b/src/decoding.cpp index 7c00ff7..2b00a07 100644 --- a/src/decoding.cpp +++ b/src/decoding.cpp @@ -20,6 +20,7 @@ #include #include #include +#include extern "C" { #include @@ -652,10 +653,10 @@ int num_blocks = 0; struct bitvec urbb; int i; + int rc; bool have_bitmap; int implicitly_acked_blocks; int ssn = desc->STARTING_SEQUENCE_NUMBER; - int rc; if (desc->FINAL_ACK_INDICATION) return handle_final_ack(bits, bsn_begin, bsn_end, window); @@ -695,24 +696,20 @@ if (crbb_len > 0) { int old_len = bits->cur_bit; - struct bitvec crbb; - crbb.data = (uint8_t *)desc->CRBB; - crbb.data_len = sizeof(desc->CRBB); - crbb.cur_bit = desc->CRBB_LENGTH; - - rc = osmo_t4_decode(&crbb, desc->CRBB_STARTING_COLOR_CODE, - bits); - + LOGP(DRLCMACDL, LOGL_DEBUG, "Compress bitmap exist," + "CRBB LEN =%d and Starting color code =%d", + desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE); + rc = decompress_crbb(desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE, + desc->CRBB, bits); if (rc < 0) { LOGP(DRLCMACUL, LOGL_NOTICE, - "Failed to decode CRBB: " - "length %d, data '%s'\n", - desc->CRBB_LENGTH, - osmo_hexdump(crbb.data, crbb.data_len)); + "Failed to decode CRBB: length %d, data '%s'\n", + desc->CRBB_LENGTH, osmo_hexdump( + desc->CRBB, (desc->CRBB_LENGTH + 7)/8)); /* We don't know the SSN offset for the URBB, - * return what we have so far and assume the - * bitmap has stopped here */ + * return what we have so far and assume the + * bitmap has stopped here */ goto aborted; } diff --git a/src/egprs_rlc_compression.cpp b/src/egprs_rlc_compression.cpp new file mode 100644 index 0000000..91021ae --- /dev/null +++ b/src/egprs_rlc_compression.cpp @@ -0,0 +1,308 @@ +/* egprs_rlc_compression.h +* Routines for EGPRS RLC bitmap compression handling +*/ +#include +#include +#include + +extern "C" { +#include +#include +#include +} + +egprs_compress *egprs_compress::s_instance = 0; +Node *egprs_compress::ones_list = NULL; +Node *egprs_compress::zeros_list = NULL; + +Node *egprs_compress::create_tree_node() +{ + Node *new_node; + + new_node = talloc_zero(tall_tree_ctx, Node); + new_node->left = NULL; + new_node->right = NULL; + new_node->run_length = -1; + return new_node; +} + +void egprs_compress::build_codeword(Node *root, const char *cdwd[]) +{ + Node *iter; + int len; + int i; + int idx; + + root->left = NULL; + root->right = NULL; + root->run_length = -1; + + for (idx = 0; idx < MAX_CDWDTBL_LEN; idx++) { + len = strlen((const char *)cdwd[idx]); + iter = root; + for (i = 0; i < len; i++) { + if (cdwd[idx][i] == '0') { + if (iter->left == NULL) + iter->left = create_tree_node(); + iter = iter->left; + } else if (cdwd[idx][i] == '1') { + if (iter->right == NULL) + iter->right = create_tree_node(); + iter = iter->right; + } + } + if (iter != NULL) { + if (idx < 64) + (iter->run_length) = idx; + else + (iter->run_length) = (idx - 63) * 64; + } + } +} + +const char *one_run_len_code_list[MAX_CDWDTBL_LEN] = { + "00110101", + "000111", + "0111", + "1000", + "1011", + "1100", + "1110", + "1111", + "10011", + "10100", + "00111", + "01000", + "001000", + "000011", + "110100", + "110101", + "101010", + "101011", + "0100111", + "0001100", + "0001000", + "0010111", + "0000011", + "0000100", + "0101000", + "0101011", + "0010011", + "0100100", + "0011000", + "00000010", + "00000011", + "00011010", + "00011011", + "00010010", + "00010011", + "00010100", + "00010101", + "00010110", + "00010111", + "00101000", + "00101001", + "00101010", + "00101011", + "00101100", + "00101101", + "00000100", + "00000101", + "00001010", + "00001011", + "01010010", + "01010011", + "01010100", + "01010101", + "00100100", + "00100101", + "01011000", + "01011001", + "01011010", + "01011011", + "01001010", + "01001011", + "00110010", + "00110011", + "00110100", + "11011", + "10010", + "010111", + "0110111", + "00110110", + "00110111", + "01100100", + "01100101", + "01101000", + "01100111", + "011001100", + "011001101", + "011010010", + "011010011", + "011010100" +}; + +const char *zero_run_len_code_list[MAX_CDWDTBL_LEN] = { + "0000110111", + "10", + "11", + "010", + "011", + "0011", + "0010", + "00011", + "000101", + "000100", + "0000100", + "0000101", + "0000111", + "00000100", + "00000111", + "000011000", + "0000010111", + "0000011000", + "0000001000", + "00001100111", + "00001101000", + "00001101100", + "00000110111", + "00000101000", + "00000010111", + "00000011000", + "000011001010", + "000011001011", + "000011001100", + "000011001101", + "000001101000", + "000001101001", + "000001101010", + "000001101011", + "000011010010", + "000011010011", + "000011010100", + "000011010101", + "000011010110", + "000011010111", + "000001101100", + "000001101101", + "000011011010", + "000011011011", + "000001010100", + "000001010101", + "000001010110", + "000001010111", + "000001100100", + "000001100101", + "000001010010", + "000001010011", + "000000100100", + "000000110111", + "000000111000", + "000000100111", + "000000101000", + "000001011000", + "000001011001", + "000000101011", + "000000101100", + "000001011010", + "000001100110", + "000001100111", + "0000001111", + "000011001000", + "000011001001", + "000001011011", + "000000110011", + "000000110100", + "000000110101", + "0000001101100", + "0000001101101", + "0000001001010", + "0000001001011", + "0000001001100", + "0000001001101", + "0000001110010", + "0000001110011" +}; + +/* search_runlen function will return the runlength for the codeword */ +static int search_runlen( + Node *root, /* root of Ones or Zeros tree */ + const uint8_t *bmbuf, /* Received compressed bitmap buf */ + uint8_t bit_pos, /* the start bit pos to read codeword */ + uint8_t *len_codewd, /* length of code word */ + uint16_t *rlen) /* run length value */ +{ + Node *iter; + uint8_t dir; + + iter = root; + *len_codewd = 0; + + while (iter->run_length == -1) { + if ((iter->left == NULL) && (iter->right == NULL)) + return -1; + /* get the bit value at the bitpos and put it in right most of dir */ + dir = ((bmbuf[BITS_TO_BYTES(bit_pos)-1] + >>(7-(MOD8(bit_pos)))) & 0x01); + (bit_pos)++; + (*len_codewd)++; + if (((dir&0x01) == 0) && (iter->left != NULL)) + iter = iter->left; + else if (((dir&0x01) == 1) && (iter->right != NULL)) + iter = iter->right; + else + return -1; + } + (*rlen) = (iter->run_length); + return 1; +} + +/*Function to decompress crbb*/ +int decompress_crbb( + int8_t compress_bmap_len, /* compressed bitmap length */ + uint8_t clr_code_bit, /* run length of Ones or Zeros */ + const uint8_t *orig_crbb_buf, /* received block crbb bitmap */ + bitvec * dest) /*uncompressed bitvector */ +{ + + uint8_t bit_pos = 0; + uint8_t data = 0x0; + node *list = NULL; + uint8_t nbits = 0; /* number of bits of codeword */ + uint16_t run_length = 0; + uint16_t cbmaplen = 0; /* compressed bitmap part after decompression */ + unsigned wp = dest->cur_bit; + int rc = 0; + egprs_compress *compress = egprs_compress::instance(); + + while (compress_bmap_len > 0) { + if (clr_code_bit == 1) { + data = 0xff; + list = compress->ones_list; + } else { + data = 0x00; + list = compress->zeros_list; + } + rc = search_runlen(list, orig_crbb_buf, + bit_pos, &nbits, &run_length); + if (rc == -1) + return -1; + /*If run length > 64, need makeup and terminating code*/ + if (run_length < 64) + clr_code_bit ? clr_code_bit = 0 : clr_code_bit = 1; + cbmaplen = cbmaplen + run_length; + /* put run length of Ones in uncompressed bitmap */ + while (run_length != 0) { + if (run_length > 8) { + bitvec_write_field(dest, wp, data, 8); + run_length = run_length - 8; + } else { + bitvec_write_field(dest, wp, data, run_length); + run_length = 0; + } + } + bit_pos = bit_pos + nbits; + compress_bmap_len = compress_bmap_len - nbits; + } + return 0; +} diff --git a/src/egprs_rlc_compression.h b/src/egprs_rlc_compression.h new file mode 100644 index 0000000..e37fe66 --- /dev/null +++ b/src/egprs_rlc_compression.h @@ -0,0 +1,73 @@ +/* egprs_rlc_compression.h + * Routines for EGPRS RLC bitmap compression handling + */ +#include +#include + +extern "C" { +#include +} + +#include +#include +#include + +#define MAX_CDWDTBL_LEN 79 /* total number of codewords */ +#define BITS_TO_BYTES(X) ((X ? (X/8):0)+1) +#define MOD8(X) (((X)+8) & (0x07)) + +typedef struct node { + struct node *left; + struct node *right; + int run_length; +} Node; + +extern const char *one_run_len_code_list[MAX_CDWDTBL_LEN]; +extern const char *zero_run_len_code_list[MAX_CDWDTBL_LEN]; + +int decompress_crbb(int8_t compress_bmap_len, uint8_t clr_code_bit, + const uint8_t *orig_buf, bitvec *dest); + +/* Creating singleton class + */ +class egprs_compress +{ + static egprs_compress *s_instance; + void *tall_tree_ctx; + + egprs_compress() + { + } + Node *create_tree_node(); + void build_codeword(Node *root, const char *cdwd[]); + void free_codeword(Node *root); + ~egprs_compress() + { + s_instance = NULL; + } +public: + static Node *ones_list; + static Node *zeros_list; + + int decode_tree_init(void *tall_pcu_ctx) + { + tall_tree_ctx = talloc_named_const(tall_pcu_ctx, 0, + "decode-tree context"); + if (!tall_tree_ctx) + return -ENOMEM; + ones_list = talloc(tall_tree_ctx, Node); + zeros_list = talloc(tall_tree_ctx, Node); + instance()->build_codeword( + ones_list, one_run_len_code_list); + instance()->build_codeword( + zeros_list, zero_run_len_code_list); + return 0; + } + static egprs_compress *instance() + { + if (!s_instance) + s_instance = new egprs_compress; + + return s_instance; + } +}; diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2d86cda..4f2853a 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -28,6 +28,7 @@ #include #include #include +#include extern "C" { #include "pcu_vty.h" #include @@ -168,7 +169,6 @@ if (!tall_pcu_ctx) return -ENOMEM; bv_tall_ctx = tall_pcu_ctx; - bts = bts_main_data(); bts->fc_interval = 1; bts->initial_cs_dl = bts->initial_cs_ul = 1; @@ -253,6 +253,11 @@ if (!bts->alloc_algorithm) bts->alloc_algorithm = alloc_algorithm_dynamic; + if (egprs_compress::instance()->decode_tree_init(tall_pcu_ctx) < 0 ){ + fprintf(stderr, "Error initializing tree\n"); + exit(1); + } + rc = pcu_l1if_open(); if (rc < 0) @@ -292,6 +297,5 @@ talloc_report_full(tall_pcu_ctx, stderr); talloc_free(tall_pcu_ctx); - return 0; } diff --git a/tests/Makefile.am b/tests/Makefile.am index 2a3415e..0f4feb1 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,7 +1,7 @@ AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGB_CFLAGS) $(LIBOSMOGSM_CFLAGS) -I$(top_srcdir)/src/ AM_LDFLAGS = -lrt -check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest llc/LlcTest codel/codel_test edge/EdgeTest +check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest llc/LlcTest codel/codel_test edge/EdgeTest bitcomp/BitcompTest noinst_PROGRAMS = emu/pcu_emu rlcmac_RLCMACTest_SOURCES = rlcmac/RLCMACTest.cpp @@ -20,6 +20,14 @@ tbf_TbfTest_SOURCES = tbf/TbfTest.cpp tbf_TbfTest_LDADD = \ + $(top_builddir)/src/libgprs.la \ + $(LIBOSMOGB_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(COMMON_LA) + +bitcomp_BitcompTest_SOURCES = bitcomp/BitcompTest.cpp +bitcomp_BitcompTest_LDADD = \ $(top_builddir)/src/libgprs.la \ $(LIBOSMOGB_LIBS) \ $(LIBOSMOGSM_LIBS) \ @@ -108,6 +116,7 @@ rlcmac/RLCMACTest.ok rlcmac/RLCMACTest.err \ alloc/AllocTest.ok alloc/AllocTest.err \ tbf/TbfTest.ok tbf/TbfTest.err \ + bitcomp/BitcompTest.ok \ types/TypesTest.ok types/TypesTest.err \ ms/MsTest.ok ms/MsTest.err \ llc/LlcTest.ok llc/LlcTest.err \ diff --git a/tests/bitcomp/BitcompTest b/tests/bitcomp/BitcompTest new file mode 100755 index 0000000..297e638 --- /dev/null +++ b/tests/bitcomp/BitcompTest Binary files differ diff --git a/tests/bitcomp/BitcompTest.cpp b/tests/bitcomp/BitcompTest.cpp new file mode 100644 index 0000000..ce8bc53 --- /dev/null +++ b/tests/bitcomp/BitcompTest.cpp @@ -0,0 +1,180 @@ +#include "egprs_rlc_compression.h" +#include "decoding.h" +#include "bts.h" +#include "tbf.h" +#include "gprs_debug.h" +#include "pcu_utils.h" +#include "gprs_bssgp_pcu.h" +#include "pcu_l1_if.h" + +extern "C" { +#include "pcu_vty.h" + +#include +#include +#include +#include +#include +#include +} + +#define NEW 1 +#define MASK(n) (0xFF << (8-n)) +#define MAX_CRBB_LEN 23 +#define MAX_URBB_LEN 40 +void *tall_pcu_ctx; + +struct test_data { + int8_t crbb_len; + uint8_t cc; + uint8_t crbb_data[MAX_CRBB_LEN]; /* compressed data */ + uint8_t ucmp_data[MAX_URBB_LEN]; /* uncompressed data */ + int ucmp_len; + int verify; +} test[] = { + {67, 1, + {0x02, 0x0c, 0xa0, 0x30, 0xcb, 0x1a, 0x0c, 0xe3, 0x6c}, + {0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x01, 0xff, 0xff, + 0xff, 0xf8, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, + 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xdb + }, + 194, 1 + }, + { 40, 1, + {0x53, 0x06, 0xc5, 0x40, 0x6d}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x03 + }, + 182, 1 + }, + { 8, 1, + {0x02}, + {0xff, 0xff, 0xff, 0xf8 + }, + 29, 1 + }, + { 103, 1, + {0x02, 0x0c, 0xe0, 0x41, 0xa0, 0x0c, 0x36, 0x0d, 0x03, + 0x71, 0xb0, 0x6e, 0x24 + }, + {0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xf8, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, + 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff + }, + 288, 1 + }, + /* Test vector from libosmocore test */ + { 35, 0, + {0xde, 0x88, 0x75, 0x65, 0x80}, + {0x37, 0x47, 0x81, 0xf0}, + 28, 1 + }, + { 18, 1, + {0xdd, 0x41, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00 + }, + 90, 1 + }, + /*Invalid inputs*/ + { 18, 1, + {0x1E, 0x70, 0xc0}, + {0x0}, + 0, 0 + }, + { 14, 1, + {0x00, 0x1E, 0x7c}, + {0x0}, + 0, 0 + }, + { 24, 0, + {0x00, 0x00, 0x00}, + {0x0}, + 0, 0 + } + }; + + +/* To verify the result with expected result */ +int check_result(bitvec bits, uint8_t *exp_data, int exp_len) +{ + if (bits.cur_bit != exp_len) + return 0; + size_t n = (exp_len / 8); + int rem = (exp_len % 8); + + if (memcmp(exp_data, bits.data, n) == 0) { + if (rem == 0) + return 1; + if ((bits.data[n] & MASK(rem)) == ((*(exp_data + n)) & MASK(rem))) + return 1; + else + return 0; + } else { + return 0; + } +} + +/* To test decoding of compressed bitmap by Tree based method + * and to verify the result with expected result + * for invalid input verfication is suppressed + */ +static void test_EPDAN_decode_tree(void) +{ + bitvec dest; + int init_flag = 1; + int itr; + uint8_t bits_data[RLC_EGPRS_MAX_WS/8]; + + printf("=== start %s ===\n", __func__); + + for (itr = 0 ; itr < (sizeof(test) / sizeof(test_data)) ; itr++) { + dest.data = bits_data; + dest.data_len = sizeof(bits_data); + dest.cur_bit = 0; + memset(dest.data, 0, sizeof(bits_data)); + decompress_crbb(test[itr].crbb_len, test[itr].cc, + test[itr].crbb_data, &dest + ); + + if (init_flag) + init_flag = 0; + if (test[itr].verify) { + if (check_result(dest, test[itr].ucmp_data, + test[itr].ucmp_len) == 0) { + LOGP(DRLCMACDL, LOGL_DEBUG, "Tree based", + "decoding :Error\n"); + OSMO_ASSERT(0); + } + } + } + + printf("=== end %s ===\n", __func__); +} + +int main(int argc, char **argv) +{ + tall_pcu_ctx = talloc_named_const(NULL, 1, "moiji-mobile TbfTest context"); + if (!tall_pcu_ctx) + abort(); + /*initialization_of_tree*/ + egprs_compress::instance()->decode_tree_init(tall_pcu_ctx); + test_EPDAN_decode_tree(); + if (getenv("TALLOC_REPORT_FULL")) + talloc_report_full(tall_pcu_ctx, stderr); + talloc_free(tall_pcu_ctx); + return EXIT_SUCCESS; +} + +/* + * stubs that should not be reached + */ +extern "C" { +void l1if_pdch_req() { abort(); } +void l1if_connect_pdch() { abort(); } +void l1if_close_pdch() { abort(); } +void l1if_open_pdch() { abort(); } +} + diff --git a/tests/bitcomp/BitcompTest.ok b/tests/bitcomp/BitcompTest.ok new file mode 100644 index 0000000..f7720fc --- /dev/null +++ b/tests/bitcomp/BitcompTest.ok @@ -0,0 +1,2 @@ +=== start test_EPDAN_decode_tree === +=== end test_EPDAN_decode_tree === diff --git a/tests/testsuite.at b/tests/testsuite.at index 1049b31..3ab39cc 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -23,6 +23,14 @@ AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/tbf/TbfTest], [0], [expout], [experr]) AT_CLEANUP + +AT_SETUP([bitcomp]) +AT_KEYWORDS([bitcomp]) +cat $abs_srcdir/bitcomp/BitcompTest.ok > expout +cat $abs_srcdir/bitcomp/BitcompTest.err > experr +AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/bitcomp/BitcompTest], [0], [expout], [experr]) +AT_CLEANUP + AT_SETUP([edge]) AT_KEYWORDS([edge]) cat $abs_srcdir/edge/EdgeTest.ok > expout -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 15 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: pravin From gerrit-no-reply at lists.osmocom.org Thu Aug 11 07:11:53 2016 From: gerrit-no-reply at lists.osmocom.org (pravin) Date: Thu, 11 Aug 2016 07:11:53 +0000 Subject: [PATCH] osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Hello Max, Neels Hofmeyr, Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/416 to look at the new patch set (#16). Add decoding of compressed bitmap in EPDAN Implemented tree based algorithm to decode compressed bitmap in EPDAN as described in section 9.1.10 of 3GPP 44.060. This algorithm intends to improve the performance over existing method. New Regression test is added under bitcomp directory. Test case is added to validate decompressed result of the bitmap Present in EPDAN. Test is done for multiple bitmaps of varying length. Invalid inputs are also part of the test vector. Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce --- M src/Makefile.am M src/decoding.cpp A src/egprs_rlc_compression.cpp A src/egprs_rlc_compression.h M src/pcu_main.cpp M tests/Makefile.am A tests/bitcomp/BitcompTest A tests/bitcomp/BitcompTest.cpp A tests/bitcomp/BitcompTest.ok M tests/testsuite.at 10 files changed, 608 insertions(+), 20 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/16/416/16 diff --git a/src/Makefile.am b/src/Makefile.am index 9bdec2f..9b047e7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -62,7 +62,8 @@ rlc.cpp \ osmobts_sock.cpp \ gprs_codel.c \ - gprs_coding_scheme.cpp + gprs_coding_scheme.cpp \ + egprs_rlc_compression.cpp bin_PROGRAMS = \ osmo-pcu @@ -94,7 +95,8 @@ pcu_utils.h \ cxx_linuxlist.h \ gprs_codel.h \ - gprs_coding_scheme.h + gprs_coding_scheme.h \ + egprs_rlc_compression.h osmo_pcu_SOURCES = pcu_main.cpp diff --git a/src/decoding.cpp b/src/decoding.cpp index 7c00ff7..2b00a07 100644 --- a/src/decoding.cpp +++ b/src/decoding.cpp @@ -20,6 +20,7 @@ #include #include #include +#include extern "C" { #include @@ -652,10 +653,10 @@ int num_blocks = 0; struct bitvec urbb; int i; + int rc; bool have_bitmap; int implicitly_acked_blocks; int ssn = desc->STARTING_SEQUENCE_NUMBER; - int rc; if (desc->FINAL_ACK_INDICATION) return handle_final_ack(bits, bsn_begin, bsn_end, window); @@ -695,24 +696,20 @@ if (crbb_len > 0) { int old_len = bits->cur_bit; - struct bitvec crbb; - crbb.data = (uint8_t *)desc->CRBB; - crbb.data_len = sizeof(desc->CRBB); - crbb.cur_bit = desc->CRBB_LENGTH; - - rc = osmo_t4_decode(&crbb, desc->CRBB_STARTING_COLOR_CODE, - bits); - + LOGP(DRLCMACDL, LOGL_DEBUG, "Compress bitmap exist," + "CRBB LEN =%d and Starting color code =%d", + desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE); + rc = decompress_crbb(desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE, + desc->CRBB, bits); if (rc < 0) { LOGP(DRLCMACUL, LOGL_NOTICE, - "Failed to decode CRBB: " - "length %d, data '%s'\n", - desc->CRBB_LENGTH, - osmo_hexdump(crbb.data, crbb.data_len)); + "Failed to decode CRBB: length %d, data '%s'\n", + desc->CRBB_LENGTH, osmo_hexdump( + desc->CRBB, (desc->CRBB_LENGTH + 7)/8)); /* We don't know the SSN offset for the URBB, - * return what we have so far and assume the - * bitmap has stopped here */ + * return what we have so far and assume the + * bitmap has stopped here */ goto aborted; } diff --git a/src/egprs_rlc_compression.cpp b/src/egprs_rlc_compression.cpp new file mode 100644 index 0000000..91021ae --- /dev/null +++ b/src/egprs_rlc_compression.cpp @@ -0,0 +1,308 @@ +/* egprs_rlc_compression.h +* Routines for EGPRS RLC bitmap compression handling +*/ +#include +#include +#include + +extern "C" { +#include +#include +#include +} + +egprs_compress *egprs_compress::s_instance = 0; +Node *egprs_compress::ones_list = NULL; +Node *egprs_compress::zeros_list = NULL; + +Node *egprs_compress::create_tree_node() +{ + Node *new_node; + + new_node = talloc_zero(tall_tree_ctx, Node); + new_node->left = NULL; + new_node->right = NULL; + new_node->run_length = -1; + return new_node; +} + +void egprs_compress::build_codeword(Node *root, const char *cdwd[]) +{ + Node *iter; + int len; + int i; + int idx; + + root->left = NULL; + root->right = NULL; + root->run_length = -1; + + for (idx = 0; idx < MAX_CDWDTBL_LEN; idx++) { + len = strlen((const char *)cdwd[idx]); + iter = root; + for (i = 0; i < len; i++) { + if (cdwd[idx][i] == '0') { + if (iter->left == NULL) + iter->left = create_tree_node(); + iter = iter->left; + } else if (cdwd[idx][i] == '1') { + if (iter->right == NULL) + iter->right = create_tree_node(); + iter = iter->right; + } + } + if (iter != NULL) { + if (idx < 64) + (iter->run_length) = idx; + else + (iter->run_length) = (idx - 63) * 64; + } + } +} + +const char *one_run_len_code_list[MAX_CDWDTBL_LEN] = { + "00110101", + "000111", + "0111", + "1000", + "1011", + "1100", + "1110", + "1111", + "10011", + "10100", + "00111", + "01000", + "001000", + "000011", + "110100", + "110101", + "101010", + "101011", + "0100111", + "0001100", + "0001000", + "0010111", + "0000011", + "0000100", + "0101000", + "0101011", + "0010011", + "0100100", + "0011000", + "00000010", + "00000011", + "00011010", + "00011011", + "00010010", + "00010011", + "00010100", + "00010101", + "00010110", + "00010111", + "00101000", + "00101001", + "00101010", + "00101011", + "00101100", + "00101101", + "00000100", + "00000101", + "00001010", + "00001011", + "01010010", + "01010011", + "01010100", + "01010101", + "00100100", + "00100101", + "01011000", + "01011001", + "01011010", + "01011011", + "01001010", + "01001011", + "00110010", + "00110011", + "00110100", + "11011", + "10010", + "010111", + "0110111", + "00110110", + "00110111", + "01100100", + "01100101", + "01101000", + "01100111", + "011001100", + "011001101", + "011010010", + "011010011", + "011010100" +}; + +const char *zero_run_len_code_list[MAX_CDWDTBL_LEN] = { + "0000110111", + "10", + "11", + "010", + "011", + "0011", + "0010", + "00011", + "000101", + "000100", + "0000100", + "0000101", + "0000111", + "00000100", + "00000111", + "000011000", + "0000010111", + "0000011000", + "0000001000", + "00001100111", + "00001101000", + "00001101100", + "00000110111", + "00000101000", + "00000010111", + "00000011000", + "000011001010", + "000011001011", + "000011001100", + "000011001101", + "000001101000", + "000001101001", + "000001101010", + "000001101011", + "000011010010", + "000011010011", + "000011010100", + "000011010101", + "000011010110", + "000011010111", + "000001101100", + "000001101101", + "000011011010", + "000011011011", + "000001010100", + "000001010101", + "000001010110", + "000001010111", + "000001100100", + "000001100101", + "000001010010", + "000001010011", + "000000100100", + "000000110111", + "000000111000", + "000000100111", + "000000101000", + "000001011000", + "000001011001", + "000000101011", + "000000101100", + "000001011010", + "000001100110", + "000001100111", + "0000001111", + "000011001000", + "000011001001", + "000001011011", + "000000110011", + "000000110100", + "000000110101", + "0000001101100", + "0000001101101", + "0000001001010", + "0000001001011", + "0000001001100", + "0000001001101", + "0000001110010", + "0000001110011" +}; + +/* search_runlen function will return the runlength for the codeword */ +static int search_runlen( + Node *root, /* root of Ones or Zeros tree */ + const uint8_t *bmbuf, /* Received compressed bitmap buf */ + uint8_t bit_pos, /* the start bit pos to read codeword */ + uint8_t *len_codewd, /* length of code word */ + uint16_t *rlen) /* run length value */ +{ + Node *iter; + uint8_t dir; + + iter = root; + *len_codewd = 0; + + while (iter->run_length == -1) { + if ((iter->left == NULL) && (iter->right == NULL)) + return -1; + /* get the bit value at the bitpos and put it in right most of dir */ + dir = ((bmbuf[BITS_TO_BYTES(bit_pos)-1] + >>(7-(MOD8(bit_pos)))) & 0x01); + (bit_pos)++; + (*len_codewd)++; + if (((dir&0x01) == 0) && (iter->left != NULL)) + iter = iter->left; + else if (((dir&0x01) == 1) && (iter->right != NULL)) + iter = iter->right; + else + return -1; + } + (*rlen) = (iter->run_length); + return 1; +} + +/*Function to decompress crbb*/ +int decompress_crbb( + int8_t compress_bmap_len, /* compressed bitmap length */ + uint8_t clr_code_bit, /* run length of Ones or Zeros */ + const uint8_t *orig_crbb_buf, /* received block crbb bitmap */ + bitvec * dest) /*uncompressed bitvector */ +{ + + uint8_t bit_pos = 0; + uint8_t data = 0x0; + node *list = NULL; + uint8_t nbits = 0; /* number of bits of codeword */ + uint16_t run_length = 0; + uint16_t cbmaplen = 0; /* compressed bitmap part after decompression */ + unsigned wp = dest->cur_bit; + int rc = 0; + egprs_compress *compress = egprs_compress::instance(); + + while (compress_bmap_len > 0) { + if (clr_code_bit == 1) { + data = 0xff; + list = compress->ones_list; + } else { + data = 0x00; + list = compress->zeros_list; + } + rc = search_runlen(list, orig_crbb_buf, + bit_pos, &nbits, &run_length); + if (rc == -1) + return -1; + /*If run length > 64, need makeup and terminating code*/ + if (run_length < 64) + clr_code_bit ? clr_code_bit = 0 : clr_code_bit = 1; + cbmaplen = cbmaplen + run_length; + /* put run length of Ones in uncompressed bitmap */ + while (run_length != 0) { + if (run_length > 8) { + bitvec_write_field(dest, wp, data, 8); + run_length = run_length - 8; + } else { + bitvec_write_field(dest, wp, data, run_length); + run_length = 0; + } + } + bit_pos = bit_pos + nbits; + compress_bmap_len = compress_bmap_len - nbits; + } + return 0; +} diff --git a/src/egprs_rlc_compression.h b/src/egprs_rlc_compression.h new file mode 100644 index 0000000..e37fe66 --- /dev/null +++ b/src/egprs_rlc_compression.h @@ -0,0 +1,73 @@ +/* egprs_rlc_compression.h + * Routines for EGPRS RLC bitmap compression handling + */ +#include +#include + +extern "C" { +#include +} + +#include +#include +#include + +#define MAX_CDWDTBL_LEN 79 /* total number of codewords */ +#define BITS_TO_BYTES(X) ((X ? (X/8):0)+1) +#define MOD8(X) (((X)+8) & (0x07)) + +typedef struct node { + struct node *left; + struct node *right; + int run_length; +} Node; + +extern const char *one_run_len_code_list[MAX_CDWDTBL_LEN]; +extern const char *zero_run_len_code_list[MAX_CDWDTBL_LEN]; + +int decompress_crbb(int8_t compress_bmap_len, uint8_t clr_code_bit, + const uint8_t *orig_buf, bitvec *dest); + +/* Creating singleton class + */ +class egprs_compress +{ + static egprs_compress *s_instance; + void *tall_tree_ctx; + + egprs_compress() + { + } + Node *create_tree_node(); + void build_codeword(Node *root, const char *cdwd[]); + void free_codeword(Node *root); + ~egprs_compress() + { + s_instance = NULL; + } +public: + static Node *ones_list; + static Node *zeros_list; + + int decode_tree_init(void *tall_pcu_ctx) + { + tall_tree_ctx = talloc_named_const(tall_pcu_ctx, 0, + "decode-tree context"); + if (!tall_tree_ctx) + return -ENOMEM; + ones_list = talloc(tall_tree_ctx, Node); + zeros_list = talloc(tall_tree_ctx, Node); + instance()->build_codeword( + ones_list, one_run_len_code_list); + instance()->build_codeword( + zeros_list, zero_run_len_code_list); + return 0; + } + static egprs_compress *instance() + { + if (!s_instance) + s_instance = new egprs_compress; + + return s_instance; + } +}; diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2d86cda..4f2853a 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -28,6 +28,7 @@ #include #include #include +#include extern "C" { #include "pcu_vty.h" #include @@ -168,7 +169,6 @@ if (!tall_pcu_ctx) return -ENOMEM; bv_tall_ctx = tall_pcu_ctx; - bts = bts_main_data(); bts->fc_interval = 1; bts->initial_cs_dl = bts->initial_cs_ul = 1; @@ -253,6 +253,11 @@ if (!bts->alloc_algorithm) bts->alloc_algorithm = alloc_algorithm_dynamic; + if (egprs_compress::instance()->decode_tree_init(tall_pcu_ctx) < 0 ){ + fprintf(stderr, "Error initializing tree\n"); + exit(1); + } + rc = pcu_l1if_open(); if (rc < 0) @@ -292,6 +297,5 @@ talloc_report_full(tall_pcu_ctx, stderr); talloc_free(tall_pcu_ctx); - return 0; } diff --git a/tests/Makefile.am b/tests/Makefile.am index 2a3415e..7643c0a 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,7 +1,7 @@ AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGB_CFLAGS) $(LIBOSMOGSM_CFLAGS) -I$(top_srcdir)/src/ AM_LDFLAGS = -lrt -check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest llc/LlcTest codel/codel_test edge/EdgeTest +check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest llc/LlcTest codel/codel_test edge/EdgeTest bitcomp/BitcompTest noinst_PROGRAMS = emu/pcu_emu rlcmac_RLCMACTest_SOURCES = rlcmac/RLCMACTest.cpp @@ -25,6 +25,18 @@ $(LIBOSMOGSM_LIBS) \ $(LIBOSMOCORE_LIBS) \ $(COMMON_LA) + +bitcomp_BitcompTest_SOURCES = bitcomp/BitcompTest.cpp +bitcomp_BitcompTest_LDADD = \ + $(top_builddir)/src/libgprs.la \ + $(LIBOSMOGB_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(COMMON_LA) + +bitcomp_BitcompTest_LDFLAGS = \ + -Wl,-u,bssgp_prim_cb + edge_EdgeTest_SOURCES = edge/EdgeTest.cpp edge_EdgeTest_LDADD = \ @@ -108,6 +120,7 @@ rlcmac/RLCMACTest.ok rlcmac/RLCMACTest.err \ alloc/AllocTest.ok alloc/AllocTest.err \ tbf/TbfTest.ok tbf/TbfTest.err \ + bitcomp/BitcompTest.ok \ types/TypesTest.ok types/TypesTest.err \ ms/MsTest.ok ms/MsTest.err \ llc/LlcTest.ok llc/LlcTest.err \ diff --git a/tests/bitcomp/BitcompTest b/tests/bitcomp/BitcompTest new file mode 100755 index 0000000..3fd0838 --- /dev/null +++ b/tests/bitcomp/BitcompTest Binary files differ diff --git a/tests/bitcomp/BitcompTest.cpp b/tests/bitcomp/BitcompTest.cpp new file mode 100644 index 0000000..07a571c --- /dev/null +++ b/tests/bitcomp/BitcompTest.cpp @@ -0,0 +1,181 @@ +#include "egprs_rlc_compression.h" +#include "decoding.h" +#include "bts.h" +#include "tbf.h" +#include "gprs_debug.h" +#include "pcu_utils.h" +#include "gprs_bssgp_pcu.h" +#include "pcu_l1_if.h" + +extern "C" { +#include "pcu_vty.h" + +#include +#include +#include +#include +#include +#include +} + +#define NEW 1 +#define MASK(n) (0xFF << (8-n)) +#define MAX_CRBB_LEN 23 +#define MAX_URBB_LEN 40 + +void *tall_pcu_ctx; +int16_t spoof_mnc = 0, spoof_mcc = 0; + +struct test_data { + int8_t crbb_len; + uint8_t cc; + uint8_t crbb_data[MAX_CRBB_LEN]; /* compressed data */ + uint8_t ucmp_data[MAX_URBB_LEN]; /* uncompressed data */ + int ucmp_len; + int verify; +} test[] = { + {67, 1, + {0x02, 0x0c, 0xa0, 0x30, 0xcb, 0x1a, 0x0c, 0xe3, 0x6c}, + {0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x01, 0xff, 0xff, + 0xff, 0xf8, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, + 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xdb + }, + 194, 1 + }, + { 40, 1, + {0x53, 0x06, 0xc5, 0x40, 0x6d}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x03 + }, + 182, 1 + }, + { 8, 1, + {0x02}, + {0xff, 0xff, 0xff, 0xf8 + }, + 29, 1 + }, + { 103, 1, + {0x02, 0x0c, 0xe0, 0x41, 0xa0, 0x0c, 0x36, 0x0d, 0x03, + 0x71, 0xb0, 0x6e, 0x24 + }, + {0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xf8, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, + 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff + }, + 288, 1 + }, + /* Test vector from libosmocore test */ + { 35, 0, + {0xde, 0x88, 0x75, 0x65, 0x80}, + {0x37, 0x47, 0x81, 0xf0}, + 28, 1 + }, + { 18, 1, + {0xdd, 0x41, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00 + }, + 90, 1 + }, + /*Invalid inputs*/ + { 18, 1, + {0x1E, 0x70, 0xc0}, + {0x0}, + 0, 0 + }, + { 14, 1, + {0x00, 0x1E, 0x7c}, + {0x0}, + 0, 0 + }, + { 24, 0, + {0x00, 0x00, 0x00}, + {0x0}, + 0, 0 + } + }; + + +/* To verify the result with expected result */ +int check_result(bitvec bits, uint8_t *exp_data, int exp_len) +{ + if (bits.cur_bit != exp_len) + return 0; + size_t n = (exp_len / 8); + int rem = (exp_len % 8); + + if (memcmp(exp_data, bits.data, n) == 0) { + if (rem == 0) + return 1; + if ((bits.data[n] & MASK(rem)) == ((*(exp_data + n)) & MASK(rem))) + return 1; + else + return 0; + } else { + return 0; + } +} + +/* To test decoding of compressed bitmap by Tree based method + * and to verify the result with expected result + * for invalid input verfication is suppressed + */ +static void test_EPDAN_decode_tree(void) +{ + bitvec dest; + int init_flag = 1; + int itr; + uint8_t bits_data[RLC_EGPRS_MAX_WS/8]; + + printf("=== start %s ===\n", __func__); + + for (itr = 0 ; itr < (sizeof(test) / sizeof(test_data)) ; itr++) { + dest.data = bits_data; + dest.data_len = sizeof(bits_data); + dest.cur_bit = 0; + memset(dest.data, 0, sizeof(bits_data)); + decompress_crbb(test[itr].crbb_len, test[itr].cc, + test[itr].crbb_data, &dest + ); + + if (init_flag) + init_flag = 0; + if (test[itr].verify) { + if (check_result(dest, test[itr].ucmp_data, + test[itr].ucmp_len) == 0) { + LOGP(DRLCMACDL, LOGL_DEBUG, "Tree based", + "decoding :Error\n"); + OSMO_ASSERT(0); + } + } + } + + printf("=== end %s ===\n", __func__); +} + +int main(int argc, char **argv) +{ + tall_pcu_ctx = talloc_named_const(NULL, 1, "moiji-mobile TbfTest context"); + if (!tall_pcu_ctx) + abort(); + /*initialization_of_tree*/ + egprs_compress::instance()->decode_tree_init(tall_pcu_ctx); + test_EPDAN_decode_tree(); + if (getenv("TALLOC_REPORT_FULL")) + talloc_report_full(tall_pcu_ctx, stderr); + talloc_free(tall_pcu_ctx); + return EXIT_SUCCESS; +} + +/* + * stubs that should not be reached + */ +extern "C" { +void l1if_pdch_req() { abort(); } +void l1if_connect_pdch() { abort(); } +void l1if_close_pdch() { abort(); } +void l1if_open_pdch() { abort(); } +} diff --git a/tests/bitcomp/BitcompTest.ok b/tests/bitcomp/BitcompTest.ok new file mode 100644 index 0000000..f7720fc --- /dev/null +++ b/tests/bitcomp/BitcompTest.ok @@ -0,0 +1,2 @@ +=== start test_EPDAN_decode_tree === +=== end test_EPDAN_decode_tree === diff --git a/tests/testsuite.at b/tests/testsuite.at index 1049b31..3ab39cc 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -23,6 +23,14 @@ AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/tbf/TbfTest], [0], [expout], [experr]) AT_CLEANUP + +AT_SETUP([bitcomp]) +AT_KEYWORDS([bitcomp]) +cat $abs_srcdir/bitcomp/BitcompTest.ok > expout +cat $abs_srcdir/bitcomp/BitcompTest.err > experr +AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/bitcomp/BitcompTest], [0], [expout], [experr]) +AT_CLEANUP + AT_SETUP([edge]) AT_KEYWORDS([edge]) cat $abs_srcdir/edge/EdgeTest.ok > expout -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 16 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: pravin From gerrit-no-reply at lists.osmocom.org Thu Aug 11 07:19:41 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Thu, 11 Aug 2016 07:19:41 +0000 Subject: osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Patch Set 15: (19 comments) https://gerrit.osmocom.org/#/c/416/15/src/egprs_rlc_compression.cpp File src/egprs_rlc_compression.cpp: Line 45: if (iter->left == NULL) we tend to use if (iter->left) Line 54: if (iter != NULL) { if (!iter) Line 229: Node *root, /* root of Ones or Zeros tree */ same comment as before.. very unusual and not helpful like this. Use @param syntax Line 242: if ((iter->left == NULL) && (iter->right == NULL)) if (iter->left && ..) Line 290: /*If run length > 64, need makeup and terminating code*/ spacing https://gerrit.osmocom.org/#/c/416/15/src/egprs_rlc_compression.h File src/egprs_rlc_compression.h: Line 39: { What is the reason to leave tall_tree_ctx completely uninitiaized in the constructor? Most likely you should do decode_tree_init as well to construct the tree on first usage (and still do the call from main to have it ready) Line 43: void free_codeword(Node *root); remove, there is no clean-up of that. No need to have a partially working function.. Line 44: ~egprs_compress() We can't use c++11 yet just leave it private and don't implement it. If somebody still tries to delete it.. stuff will go wrong. Line 49: static Node *ones_list; you don't need that to be static. Line 52: int decode_tree_init(void *tall_pcu_ctx) do not shadow "tall_pcu_ctx" what is the point of having this inline? It is a one time init function. Line 59: zeros_list = talloc(tall_tree_ctx, Node); ise create_tree_node? Line 60: instance()->build_codeword( you have a "this" and we do not have concurrency here. So no reason to use instance() here. https://gerrit.osmocom.org/#/c/416/15/tests/Makefile.am File tests/Makefile.am: Line 32: $(LIBOSMOGB_LIBS) \ Build error: libosmogb has an undefined symbol it calls. You can either decide not to link libosmogb (why would a T4 decoder need GSM+GB anyway)? or define the symbol so it links https://gerrit.osmocom.org/#/c/416/15/tests/bitcomp/BitcompTest.cpp File tests/bitcomp/BitcompTest.cpp: Line 25: void *tall_pcu_ctx; give it some room to breath and add a newline Line 35: {67, 1, Use C99 initializers Line 103: if (bits.cur_bit != exp_len) So.. maybe print the data in the error case so somebody debugging has it more easy to see what is going on? Line 138: decompress_crbb(test[itr].crbb_len, test[itr].cc, Result ignored Line 144: if (test[itr].verify) { Invalid data not checking the result. That post-condition is too weak. Check the result with an expected result Line 174: extern "C" { if you link less, you might be able to drop these. -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 15 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: pravin Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 11 07:35:22 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 11 Aug 2016 07:35:22 +0000 Subject: [PATCH] osmo-pcu[master]: Add data structure to handle SPB for EGPRS DL In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/654 to look at the new patch set (#3). Add data structure to handle SPB for EGPRS DL Modify the header files with necessary data structure to handle Split block for EGPRS DL TBF. The EGPRS resegmentation feature allows PCU to retransmit RLC blocks of HeaderType1, HeaderType2 by segmenting them to 2 HeaderType3 blocks(Example MCS5 will be retransmitted as 2 MCS2 blocks). Table 10.4.8b.2 of 44.060 explains the possible values of SPB in HeadrType3 for DL direction. The PCU decides to retransmit the blocks by resegmenting it based on Table 8.1.1.1 of 44.060. The retransmission MCS is calculated based on current MCS of the Block and demanded MCS by PCU. Section 10.3a.3.3 of 44.060 shows the HeadrType3 with SPB field present in it Change-Id: I57673e53a9da2affa7e8aaa6551ac4b271c3d525 --- M src/bts.h M src/rlc.h 2 files changed, 45 insertions(+), 4 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/54/654/3 diff --git a/src/bts.h b/src/bts.h index 807ce08..38896c8 100644 --- a/src/bts.h +++ b/src/bts.h @@ -186,6 +186,10 @@ uint8_t alpha, gamma; uint8_t egprs_enabled; uint32_t dl_tbf_idle_msec; /* hold time for idle DL TBFs */ + + /* 0 to support resegmentation in DL, 1 for no reseg */ + uint8_t dl_arq_type; + uint32_t ms_idle_sec; uint8_t cs_adj_enabled; uint8_t cs_adj_upper_limit; diff --git a/src/rlc.h b/src/rlc.h index bf2d70a..4d57c88 100644 --- a/src/rlc.h +++ b/src/rlc.h @@ -84,6 +84,39 @@ }; /* + * EGPRS resegment status information for DL + * When only first segment is sent, bsn state + * will be set to EGPRS_RESEG_FIRST_SEG_SENT and when + * second segment is sent the state will be + * set to EGPRS_RESEG_SECOND_SEG_SENT. + * EGPRS_RESEG_DL_INVALID is set to 8 considering there is a scope for + * 3rd segment according to Table 10.4.8b.2 of 44.060 + * The EGPRS resegmentation feature allows PCU to retransmit + * RLC blocks of HeaderType1, HeaderType2 by segmenting + * them to 2 HeaderType3 blocks(Example MCS5 will be + * retransmitted as 2 MCS2 blocks). Table 10.4.8b.2 of 44.060 + * explains the possible values of SPB in HeadrType3 for DL + * direction.The PCU decides to retransmit the + * blocks by resegmenting it based on Table 8.1.1.1 of 44.060. + * The retransmission MCS is calculated based on current MCS of + * the Block and demanded MCS by PCU. Section 10.3a.3.3 of 44.060 + * shows the HeadrType3 with SPB field present in it +*/ +enum egprs_rlc_dl_reseg_bsn_state { + EGPRS_RESEG_DL_DEFAULT = 0, + EGPRS_RESEG_FIRST_SEG_SENT = 0x01, + EGPRS_RESEG_SECOND_SEG_SENT = 0x02, + EGPRS_RESEG_DL_INVALID = 0x08 +}; + +/* Table 10.4.8b.2 of 44.060 */ +enum egprs_rlcmac_dl_spb_values { + EGPRS_RLCMAC_DL_NO_RETX = 0, + EGPRS_RLCMAC_DL_FIRST_SEG = 2, + EGPRS_RLCMAC_DL_SEC_SEG = 3, +}; + +/* * Valid puncturing scheme values * TS 44.060 10.4.8a.3.1, 10.4.8a.2.1, 10.4.8a.1.1 */ @@ -140,10 +173,7 @@ /* holds the current status of the block w.r.t UL/DL split blocks */ union split_block_status { egprs_rlc_ul_reseg_bsn_state block_status_ul; - /* - * TODO: DL split block status need to be supported - * for EGPRS DL - */ + egprs_rlc_dl_reseg_bsn_state block_status_dl; }; struct gprs_rlc_data { @@ -168,6 +198,13 @@ GprsCodingScheme cs_current_trans; GprsCodingScheme cs_last; + /* + * The MCS of initial transmission of a BSN + * This variable is used for split block + * processing in DL + */ + GprsCodingScheme cs_init; + /* puncturing scheme value to be used for next transmission*/ enum egprs_puncturing_values next_ps; -- To view, visit https://gerrit.osmocom.org/654 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I57673e53a9da2affa7e8aaa6551ac4b271c3d525 Gerrit-PatchSet: 3 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Thu Aug 11 07:55:53 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 11 Aug 2016 07:55:53 +0000 Subject: [PATCH] osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/655 to look at the new patch set (#13). Modify EGPRS DL TBF flow to support SPB Modify the EGPRS DL TBF flow to support Split block during Retx. This patch will also Upgrade the test suite with test cases to validate the EGPRS Downlink SPB for Retransmission Scenarios like MCS6->MCS3, MCS4->MCS1, MCS5->MCS2, MCS9->MCS3 MCS7->MCS2, MCS8->MCS3 have been simulated and Integration tested in NuRAN 1.0 hardware thoroughly. Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 --- M src/gprs_coding_scheme.h M src/pcu_main.cpp M src/pcu_vty.c M src/rlc.cpp M src/rlc.h M src/tbf.h M src/tbf_dl.cpp M tests/edge/EdgeTest.cpp M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 11 files changed, 951 insertions(+), 77 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/55/655/13 diff --git a/src/gprs_coding_scheme.h b/src/gprs_coding_scheme.h index 60a8e79..3b15372 100644 --- a/src/gprs_coding_scheme.h +++ b/src/gprs_coding_scheme.h @@ -113,7 +113,8 @@ static const char *modeName(Mode mode); static Scheme get_retx_mcs(const GprsCodingScheme mcs, - const GprsCodingScheme retx_mcs); + const GprsCodingScheme retx_mcs, + const unsigned arq_type); static enum Scheme egprs_mcs_retx_tbl[MAX_NUM_ARQ] [MAX_NUM_MCS][MAX_NUM_MCS]; @@ -232,8 +233,9 @@ } inline GprsCodingScheme::Scheme GprsCodingScheme::get_retx_mcs( const GprsCodingScheme mcs, - const GprsCodingScheme demanded_mcs) + const GprsCodingScheme demanded_mcs, + const unsigned arq_type) { - return egprs_mcs_retx_tbl[EGPRS_ARQ2][mcs.to_num() - 1] + return egprs_mcs_retx_tbl[arq_type][mcs.to_num() - 1] [demanded_mcs.to_num() - 1]; } diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2d86cda..e34d534 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -210,6 +210,12 @@ bts->dl_tbf_idle_msec = 2000; bts->llc_idle_ack_csec = 10; + /* + * By default resegmentation is supported in DL + * can also be configured through VTY + */ + bts->dl_arq_type = EGPRS_ARQ1; + msgb_set_talloc_ctx(tall_pcu_ctx); osmo_init_logging(&gprs_log_info); diff --git a/src/pcu_vty.c b/src/pcu_vty.c index 58fea99..4dfc6b3 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -129,6 +129,10 @@ vty_out(vty, " window-size %d %d%s", bts->ws_base, bts->ws_pdch, VTY_NEWLINE); + if (bts->dl_arq_type) + vty_out(vty, " dl arq-type %d%s", bts->dl_arq_type, + VTY_NEWLINE); + if (bts->force_llc_lifetime == 0xffff) vty_out(vty, " queue lifetime infinite%s", VTY_NEWLINE); else if (bts->force_llc_lifetime) @@ -477,6 +481,20 @@ bts->max_mcs_dl = 0; bts->max_mcs_ul = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_pcu_dl_arq_type, + cfg_pcu_dl_arq_cmd, + "dl arq-type (0|1)", + EGPRS_STR "DL ARQ options\n" + "enable DL SPB support\n" + "enable DL ARQ2 support") +{ + struct gprs_rlcmac_bts *bts = bts_main_data(); + uint8_t dl_arq_type = atoi(argv[0]); + + bts->dl_arq_type = dl_arq_type; return CMD_SUCCESS; } @@ -954,6 +972,7 @@ install_element(PCU_NODE, &cfg_pcu_no_cs_downgrade_thrsh_cmd); install_element(PCU_NODE, &cfg_pcu_cs_lqual_ranges_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_cmd); + install_element(PCU_NODE, &cfg_pcu_dl_arq_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_max_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_max_cmd); diff --git a/src/rlc.cpp b/src/rlc.cpp index 6770043..60f392e 100644 --- a/src/rlc.cpp +++ b/src/rlc.cpp @@ -285,7 +285,8 @@ } static void gprs_rlc_data_header_init(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding, unsigned int header_bits) + GprsCodingScheme cs, bool with_padding, unsigned int header_bits, + const unsigned int spb) { unsigned int i; unsigned int padding_bits = with_padding ? cs.optionalPaddingBits() : 0; @@ -300,7 +301,7 @@ for (i = 0; i < rlc->num_data_blocks; i++) { gprs_rlc_data_block_info_init(&rlc->block_info[i], cs, - with_padding); + with_padding, spb); rlc->data_offs_bits[i] = header_bits + padding_bits + @@ -310,21 +311,25 @@ } void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsDL()); + cs.numDataHeaderBitsDL(), spb); } void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding) { + /* + * last parameter is sent as 0 since common function used + * for both DL and UL + */ return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsUL()); + cs.numDataHeaderBitsUL(), 0); } void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { unsigned int data_len = cs.maxDataBlockBytes(); if (with_padding) @@ -336,7 +341,7 @@ rdbi->e = 1; rdbi->cv = 15; rdbi->pi = 0; - rdbi->spb = 0; + rdbi->spb = spb; } unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, @@ -411,8 +416,18 @@ enum egprs_puncturing_values gprs_get_punct_scheme( enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current) + const GprsCodingScheme &cs_current, + const enum egprs_rlcmac_dl_spb_values spb) { + + /* + * 10.4.8b of TS 44.060 + * If it is second segment of the block + * dont change the puncturing scheme + */ + if (spb == EGPRS_RLCMAC_DL_SEC_SEG) + return punct; + /* TS 44.060 9.3.2.1.1 */ if ((GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS9) && (GprsCodingScheme::Scheme(cs_current) == GprsCodingScheme::MCS6)) { diff --git a/src/rlc.h b/src/rlc.h index 4d57c88..098c930 100644 --- a/src/rlc.h +++ b/src/rlc.h @@ -213,18 +213,19 @@ }; void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding); void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, enum egprs_puncturing_values punct, enum egprs_puncturing_values punct2, int with_padding); void gprs_rlc_mcs_cps_decode(unsigned int cps, GprsCodingScheme cs, int *punct, int *punct2, int *with_padding); enum egprs_puncturing_values gprs_get_punct_scheme(enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current_trans); + const GprsCodingScheme &cs_current_trans, + const enum egprs_rlcmac_dl_spb_values spb); void gprs_update_punct_scheme(enum egprs_puncturing_values *punct, const GprsCodingScheme &cs); /* diff --git a/src/tbf.h b/src/tbf.h index 1bd7878..cd820b9 100644 --- a/src/tbf.h +++ b/src/tbf.h @@ -421,6 +421,11 @@ int analyse_errors(char *show_rbb, uint8_t ssn, ana_result *res); void schedule_next_frame(); + enum egprs_rlc_dl_reseg_bsn_state egprs_dl_get_data_buffer + (int bsn, uint8_t **block_data); + unsigned int get_egprs_dl_spb_status(int bsn); + enum egprs_rlcmac_dl_spb_values get_egprs_dl_spb_value(int bsn); + struct osmo_timer_list m_llc_timer; }; diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp index 07a747a..f01a9ec 100644 --- a/src/tbf_dl.cpp +++ b/src/tbf_dl.cpp @@ -375,21 +375,27 @@ return -1; if (is_egprs_enabled()) { + /* Table 8.1.1.2 and Table 8.1.1.1 of 44.060 */ m_rlc.block(bsn)->cs_current_trans = - GprsCodingScheme::get_retx_mcs( - m_rlc.block(bsn)->cs_last, ms()->current_cs_dl()); + GprsCodingScheme::get_retx_mcs( + m_rlc.block(bsn)->cs_init, + ms()->current_cs_dl(), + bts->bts_data()->dl_arq_type); LOGP(DRLCMACDL, LOGL_DEBUG, - "- current_cs_dl(%d) demanded_mcs(%d) cs_trans(%d)\n", + "- initial_cs_dl(%d) last_mcs(%d) demanded_mcs(%d)" + "cs_trans(%d) arq_type(%d) bsn(%d)\n", + m_rlc.block(bsn)->cs_init.to_num(), m_rlc.block(bsn)->cs_last.to_num(), ms()->current_cs_dl().to_num(), - m_rlc.block(bsn)->cs_current_trans.to_num()); + m_rlc.block(bsn)->cs_current_trans.to_num(), + bts->bts_data()->dl_arq_type, bsn); /* TODO: Need to remove this check when MCS-8 -> MCS-6 * transistion is handled. * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 */ - if (m_rlc.block(bsn)->cs_last == GprsCodingScheme::MCS8) + if (m_rlc.block(bsn)->cs_init == GprsCodingScheme::MCS8) m_rlc.block(bsn)->cs_current_trans = GprsCodingScheme::MCS8; } else @@ -523,6 +529,11 @@ data = rlc_data->prepare(block_data_len); rlc_data->cs_last = cs; rlc_data->cs_current_trans = cs; + + /* Initialise the variable related to DL SPB */ + rlc_data->spb_status.block_status_dl = EGPRS_RESEG_DL_DEFAULT; + rlc_data->cs_init = cs; + rlc_data->len = block_data_len; rdbi = &(rlc_data->block_info); @@ -616,6 +627,7 @@ unsigned num_bsns; enum egprs_puncturing_values punct[ARRAY_SIZE(rlc.block_info)]; bool need_padding = false; + enum egprs_rlcmac_dl_spb_values spb = EGPRS_RLCMAC_DL_NO_RETX; /* * TODO: This is an experimental work-around to put 2 BSN into @@ -626,6 +638,7 @@ * the current limit. */ cs = m_rlc.block(index)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(index)->cs_init; bsns[0] = index; num_bsns = 1; @@ -634,7 +647,19 @@ num_bsns += 1; } - if (num_bsns == 1) { + /* + * if the intial mcs is 8 and retransmission mcs is either 6 or 3 + * we have to include the padding of 6 octets in first segment + */ + if ((GprsCodingScheme::Scheme(cs_init) == GprsCodingScheme::MCS8) && + (GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS6 || + GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS3)) { + if ((get_egprs_dl_spb_status(index) == + EGPRS_RESEG_DL_DEFAULT) || + (get_egprs_dl_spb_status(index) == + EGPRS_RESEG_SECOND_SEG_SENT)) + need_padding = true; + } else if (num_bsns == 1) { /* TODO: remove the conditional when MCS-6 padding isn't * failing to be decoded by MEs anymore */ /* TODO: support of MCS-8 -> MCS-6 transition should be @@ -646,7 +671,14 @@ cs.decToSingleBlock(&need_padding); } - gprs_rlc_data_info_init_dl(&rlc, cs, need_padding); + spb = get_egprs_dl_spb_value(index); + + LOGP(DRLCMACDL, LOGL_DEBUG, "- need_padding %d spb_status %d spb %d" + "(BSN1 %d BSN2 %d)\n", + need_padding, + get_egprs_dl_spb_status(index), spb, index, index2); + + gprs_rlc_data_info_init_dl(&rlc, cs, need_padding, spb); rlc.usf = 7; /* will be set at scheduler */ rlc.pr = 0; /* FIXME: power reduction */ @@ -665,10 +697,9 @@ data_block_idx++) { int bsn; - GprsCodingScheme cs_enc; uint8_t *block_data; gprs_rlc_data_block_info *rdbi, *block_info; - enum egprs_puncturing_values punct_scheme; + enum egprs_rlc_dl_reseg_bsn_state reseg_status; /* Check if there are more blocks than BSNs */ if (data_block_idx < num_bsns) @@ -676,38 +707,43 @@ else bsn = bsns[0]; - cs_enc = m_rlc.block(bsn)->cs_current_trans; - /* get data and header from current block */ - block_data = m_rlc.block(bsn)->block; - /* Get current puncturing scheme from block */ - punct_scheme = gprs_get_punct_scheme( + + m_rlc.block(bsn)->next_ps = gprs_get_punct_scheme( m_rlc.block(bsn)->next_ps, - m_rlc.block(bsn)->cs_last, cs); + m_rlc.block(bsn)->cs_last, cs, spb); if (cs.isEgprs()) { - OSMO_ASSERT(punct_scheme >= EGPRS_PS_1); - OSMO_ASSERT(punct_scheme <= EGPRS_PS_3); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps >= EGPRS_PS_1); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps <= EGPRS_PS_3); } - punct[data_block_idx] = punct_scheme; + punct[data_block_idx] = m_rlc.block(bsn)->next_ps; rdbi = &rlc.block_info[data_block_idx]; block_info = &m_rlc.block(bsn)->block_info; - if(rdbi->data_len != m_rlc.block(bsn)->len) { - LOGP(DRLCMACDL, LOGL_ERROR, - "ERROR: Expected len = %d for %s instead of " - "%d in data unit %d (BSN %d, %s)\n", - rdbi->data_len, cs.name(), m_rlc.block(bsn)->len, - data_block_idx, bsn, cs_enc.name()); - OSMO_ASSERT(rdbi->data_len == m_rlc.block(bsn)->len); - } - - /* TODO: Need to handle 2 same bsns - * in header type 1 + /* + * get data and header from current block + * function returns the reseg status */ - gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, - cs); + reseg_status = egprs_dl_get_data_buffer(bsn, &block_data); + m_rlc.block(bsn)->spb_status.block_status_dl = reseg_status; + + /* + * If it is first segment of the split block set the state of + * bsn to nacked. If it is the first segment dont update the + * next ps value of bsn. since next segment also needs same cps + */ + if (spb == EGPRS_RLCMAC_DL_FIRST_SEG) + m_window.m_v_b.mark_nacked(bsn); + else { + /* + * TODO: Need to handle 2 same bsns + * in header type 1 + */ + gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, + cs); + } m_rlc.block(bsn)->cs_last = cs; rdbi->e = block_info->e; @@ -1169,3 +1205,120 @@ keep_time_frames = msecs_to_frames(bts_data()->dl_tbf_idle_msec); return frames_since_last_drain(fn) <= keep_time_frames; } + +/* + * This function returns the pointer to data which needs + * to be copied. Also updates the status of the block related to + * Split block handling in the RLC/MAC block. + */ +enum egprs_rlc_dl_reseg_bsn_state + gprs_rlcmac_dl_tbf::egprs_dl_get_data_buffer(int bsn, + uint8_t **block_data) +{ + gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state *block_status_dl = + &rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + *block_data = &rlc_data->block[0]; + + /* + * Table 10.3a.0.1 of 44.060 + * MCS6,9: second segment starts at 74/2 = 37 + * MCS5,7: second segment starts at 56/2 = 28 + * MCS8: second segment starts at 31 + * MCS4: second segment starts at 44/2 = 22 + */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + if (*block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + switch (GprsCodingScheme::Scheme(cs_init)) { + case GprsCodingScheme::MCS6 : + case GprsCodingScheme::MCS9 : + *block_data = &rlc_data->block[37]; + break; + case GprsCodingScheme::MCS7 : + case GprsCodingScheme::MCS5 : + *block_data = &rlc_data->block[28]; + break; + case GprsCodingScheme::MCS8 : + *block_data = &rlc_data->block[31]; + break; + case GprsCodingScheme::MCS4 : + *block_data = &rlc_data->block[22]; + break; + default: + LOGP(DRLCMACDL, LOGL_ERROR, "Software error: " + "--%s hit invalid condition. headerType(%d) " + " blockstatus(%d) cs(%s) PLEASE FIX!\n", name(), + cs_current_trans.headerTypeData(), + *block_status_dl, cs_init.name()); + break; + + } + return EGPRS_RESEG_SECOND_SEG_SENT; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } + } + return EGPRS_RESEG_DL_DEFAULT; +} + +/* + * This function returns the status of split block + * for RLC/MAC block. + */ +unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_status(const int bsn) +{ + const gprs_rlc_data *rlc_data = m_rlc.block(bsn); + + return rlc_data->spb_status.block_status_dl; +} + +/* + * This function returns the spb value to be sent OTA + * for RLC/MAC block. + */ +enum egprs_rlcmac_dl_spb_values gprs_rlcmac_dl_tbf::get_egprs_dl_spb_value + (const int bsn) +{ + struct gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state block_status_dl = + rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + + /* Table 10.4.8b.1 of 44.060 */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + /* + * if we are sending the second segment the spb should be 3 + * other wise it should be 2 + */ + if (block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + return EGPRS_RLCMAC_DL_SEC_SEG; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RLCMAC_DL_FIRST_SEG; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RLCMAC_DL_FIRST_SEG; + } + } + /* Non SPB cases 0 is reurned */ + return EGPRS_RLCMAC_DL_NO_RETX; +} diff --git a/tests/edge/EdgeTest.cpp b/tests/edge/EdgeTest.cpp index 807102c..9081d4d 100644 --- a/tests/edge/EdgeTest.cpp +++ b/tests/edge/EdgeTest.cpp @@ -517,7 +517,7 @@ /* TS 44.060, B.1 */ cs = GprsCodingScheme::CS4; - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -570,7 +570,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -592,7 +592,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -630,7 +630,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -669,7 +669,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -694,7 +694,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -719,7 +719,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -740,7 +740,7 @@ OSMO_ASSERT(data[0] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -777,7 +777,7 @@ cs = GprsCodingScheme::MCS4; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -835,7 +835,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -872,7 +872,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -923,7 +923,7 @@ OSMO_ASSERT(data[3] == 0); /* Block 3 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -967,7 +967,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -993,7 +993,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1020,7 +1020,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1074,7 +1074,7 @@ block_idx++) { struct gprs_rlc_data_info rlc; - gprs_rlc_data_info_init_dl(&rlc, cs, false); + gprs_rlc_data_info_init_dl(&rlc, cs, false, 0); memset(bits, pattern, sizeof(bits)); Decoding::rlc_copy_to_aligned_buffer( @@ -1118,12 +1118,14 @@ struct gprs_rlc_data_info rlc; printf("=== start %s ===\n", __func__); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::CS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::CS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 24); OSMO_ASSERT(rlc.block_info[0].data_len == 20); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::MCS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::MCS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 33); OSMO_ASSERT(rlc.block_info[0].data_len == 22); diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..18cc5cb 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -1814,6 +1814,201 @@ } +static void egprs_spb_to_normal_validation(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + uint16_t bsn1, bsn2, bsn3; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + struct gprs_rlc_dl_header_egprs_2 *egprs2; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + if ((mcs == 6) && (demanded_mcs == 3)) { + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + bsn1 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) + || (egprs2->bsn1_lo); + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(bsn1 == 0); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + bsn2 = (egprs3->bsn1_hi << 9) || (egprs3->bsn1_mid << 1) || + (egprs3->bsn1_lo); + OSMO_ASSERT(bsn2 == bsn1); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Handle (MCS3, MCS3) -> MCS6 case */ + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + mcs)); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs2->cps == 0); + bsn3 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) || + (egprs2->bsn1_lo); + OSMO_ASSERT(bsn3 == bsn2); + + tbf_cleanup(dl_tbf); + } +} +static void establish_and_use_egprs_dl_tbf_for_spb(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + /* TODO: Need to support of MCS8 -> MCS6 ->MCS3 transistion + * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 + * dated 2016-02-07 23:45:40 (UTC) + */ + if (((mcs == 5) && (demanded_mcs == 2)) || + ((mcs == 6) && (demanded_mcs == 3)) || + ((mcs == 4) && (demanded_mcs == 1))) { + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + tbf_cleanup(dl_tbf); + } +} + static void establish_and_use_egprs_dl_tbf_for_retx(BTS *the_bts, int mcs, int demanded_mcs) { @@ -1972,6 +2167,9 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; + /* First parameter is current MCS, second one is demanded_mcs */ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 6); @@ -1981,6 +2179,38 @@ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 9); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 7, 5); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 9, 6); + + printf("=== end %s ===\n", __func__); +} + +static void test_tbf_egprs_spb_dl(void) +{ + BTS the_bts; + gprs_rlcmac_bts *bts; + uint8_t ts_no = 4; + int i, j; + + printf("=== start %s ===\n", __func__); + + bts = the_bts.bts_data(); + bts->cs_downgrade_threshold = 0; + setup_bts(&the_bts, ts_no); + bts->dl_tbf_idle_msec = 200; + bts->egprs_enabled = 1; + + /* ARQ I resegmentation support */ + bts->dl_arq_type = EGPRS_ARQ1; + + /* + * First parameter is current MCS, second one is demanded_mcs + * currently only MCS5->MCS2, MCS6->3, MCS4->MCS1 is tested in UT + * rest scenarios has been integration tested + */ + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 6, 3); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 5, 2); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 4, 1); + /* check MCS6->(MCS3+MCS3)->MCS6 case */ + egprs_spb_to_normal_validation(&the_bts, 6, 3); printf("=== end %s ===\n", __func__); } @@ -1999,6 +2229,8 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; for (i = 1; i <= 9; i++) establish_and_use_egprs_dl_tbf(&the_bts, i); @@ -2071,6 +2303,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_egprs_spb_dl(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..7b3f339 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -72,6 +72,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -81,6 +82,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -157,6 +159,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -166,6 +169,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -242,6 +246,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -251,6 +256,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -259,6 +265,7 @@ - Sending new block at BSN 2, CS=CS-1 -- Chunk with length 160 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=13 block=3 data=07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b @@ -267,6 +274,7 @@ - Sending new block at BSN 3, CS=CS-1 -- Chunk with length 140 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=17 block=4 data=07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @@ -275,6 +283,7 @@ - Sending new block at BSN 4, CS=CS-1 -- Chunk with length 120 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=21 block=5 data=07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 @@ -283,6 +292,7 @@ - Sending new block at BSN 5, CS=CS-1 -- Chunk with length 100 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=26 block=6 data=07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 @@ -291,6 +301,7 @@ - Sending new block at BSN 6, CS=CS-1 -- Chunk with length 80 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=30 block=7 data=07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b @@ -299,6 +310,7 @@ - Sending new block at BSN 7, CS=CS-1 -- Chunk with length 60 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=34 block=8 data=07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f @@ -307,6 +319,7 @@ - Sending new block at BSN 8, CS=CS-1 -- Chunk with length 40 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=39 block=9 data=07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 @@ -315,6 +328,7 @@ - Sending new block at BSN 9, CS=CS-1 -- Chunk with length 20 would exactly fit into space (20): add length header with LI=0, to make frame extend to next block, and we are done data block (BSN 9, CS-1): 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=43 block=10 data=07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 @@ -326,6 +340,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=47 block=11 data=07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 @@ -334,6 +349,7 @@ - Sending new block at BSN 11, CS=CS-1 -- Chunk with length 182 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=52 block=0 data=07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 @@ -342,6 +358,7 @@ - Sending new block at BSN 12, CS=CS-1 -- Chunk with length 162 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=56 block=1 data=07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 @@ -350,6 +367,7 @@ - Sending new block at BSN 13, CS=CS-1 -- Chunk with length 142 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 13, CS-1): 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=60 block=2 data=07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d @@ -358,6 +376,7 @@ - Sending new block at BSN 14, CS=CS-1 -- Chunk with length 122 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=65 block=3 data=07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 @@ -366,6 +385,7 @@ - Sending new block at BSN 15, CS=CS-1 -- Chunk with length 102 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=69 block=4 data=07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 @@ -374,6 +394,7 @@ - Sending new block at BSN 16, CS=CS-1 -- Chunk with length 82 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=73 block=5 data=07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 @@ -382,6 +403,7 @@ - Sending new block at BSN 17, CS=CS-1 -- Chunk with length 62 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=78 block=6 data=07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d @@ -390,6 +412,7 @@ - Sending new block at BSN 18, CS=CS-1 -- Chunk with length 42 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=82 block=7 data=07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 @@ -398,6 +421,7 @@ - Sending new block at BSN 19, CS=CS-1 -- Chunk with length 22 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=86 block=8 data=07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 @@ -411,6 +435,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=16 data block (BSN 20, CS-1): 0a 41 c6 c7 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -449,6 +474,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 data block (BSN 21, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -468,6 +494,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 22, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FINISHED) @@ -1481,6 +1508,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 0, CS-1): 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 MSG = 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 @@ -1491,6 +1519,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 1, CS-1): 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 MSG = 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 @@ -1501,6 +1530,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FINISHED data block (BSN 2, CS-1): 4d 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling cannot be scheduled in this TS 7 (first control TS 4) @@ -1784,6 +1814,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=10 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 0, CS-4): 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654292 TS 7 @@ -1797,6 +1828,7 @@ TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) downlink (V(A)==0 .. V(S)==1) - Restarting at BSN 0, because all blocks have been transmitted. - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-4): 07 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 @@ -2365,6 +2397,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654279 block=10 data=00 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 @@ -2384,6 +2417,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -2406,6 +2440,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654288 block=0 data=00 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 @@ -2425,6 +2460,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654292 block=1 data=00 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2447,6 +2483,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654296 block=2 data=00 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c @@ -2466,6 +2503,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654301 block=3 data=00 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b @@ -2488,6 +2526,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 6, CS-1): 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654305 block=4 data=00 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 @@ -2507,6 +2546,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654309 block=5 data=00 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 @@ -2526,6 +2566,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654314 block=6 data=00 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 @@ -2548,6 +2589,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654318 block=7 data=00 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 @@ -2567,6 +2609,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654322 block=8 data=00 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2589,6 +2632,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654327 block=9 data=00 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c @@ -2608,6 +2652,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654331 block=10 data=00 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b @@ -2630,6 +2675,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 13, CS-1): 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654335 block=11 data=00 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 @@ -2649,6 +2695,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654340 block=0 data=00 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 @@ -2668,6 +2715,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654344 block=1 data=00 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 @@ -2690,6 +2738,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654348 block=2 data=00 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 @@ -2709,6 +2758,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654353 block=3 data=00 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2731,6 +2781,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654357 block=4 data=00 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c @@ -2750,6 +2801,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654361 block=5 data=00 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b @@ -2772,6 +2824,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 20, CS-1): 16 35 45 54 20 32 38 4c 4c 43 20 50 41 43 4b 45 54 20 32 39 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because 20 blocks sent. TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW): Scheduling polling at FN 2654379 TS 7 @@ -2795,6 +2848,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 21, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) msg block (BSN 21, CS-1): 07 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654370 block=7 data=00 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 @@ -2814,6 +2868,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 22, CS-1): 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) msg block (BSN 22, CS-1): 07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654374 block=8 data=07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 @@ -2836,6 +2891,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 23, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) msg block (BSN 23, CS-1): 07 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654379 block=9 data=00 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 @@ -2855,6 +2911,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 24, CS-1): 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) msg block (BSN 24, CS-1): 07 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654383 block=10 data=00 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2877,6 +2934,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 25, CS-1): 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 25 BSN2 -1) - Copying data unit 0 (BSN 25) msg block (BSN 25, CS-1): 07 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654387 block=11 data=00 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c @@ -2896,6 +2954,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 26, CS-1): 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 26 BSN2 -1) - Copying data unit 0 (BSN 26) msg block (BSN 26, CS-1): 07 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654392 block=0 data=00 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b @@ -2918,6 +2977,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 27, CS-1): 16 35 45 54 20 33 38 4c 4c 43 20 50 41 43 4b 45 54 20 33 39 +- need_padding 0 spb_status 0 spb 0(BSN1 27 BSN2 -1) - Copying data unit 0 (BSN 27) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) @@ -3028,6 +3088,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654405 block=3 data=00 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 @@ -3047,6 +3108,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654409 block=4 data=00 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 @@ -3066,6 +3128,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (16) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654413 block=5 data=00 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 @@ -3085,6 +3148,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (14) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654418 block=6 data=00 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 @@ -3104,6 +3168,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654422 block=7 data=00 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -3123,6 +3188,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654426 block=8 data=00 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 @@ -3142,6 +3208,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654431 block=9 data=00 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b @@ -3161,6 +3228,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654435 block=10 data=00 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 @@ -3180,6 +3248,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654439 block=11 data=00 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 @@ -3199,6 +3268,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654444 block=0 data=00 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c @@ -3218,6 +3288,7 @@ Complete DL frame for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=21 TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 10, CS-1): 4d 43 20 50 41 43 4b 45 54 20 30 39 20 28 54 42 46 20 32 29 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654461 TS 7 @@ -3698,6 +3769,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 0, MCS-1): 14 15 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3711,6 +3783,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3721,6 +3794,7 @@ - Sending new block at BSN 2, CS=MCS-1 -- Chunk with length 490 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3731,6 +3805,7 @@ - Sending new block at BSN 3, CS=MCS-1 -- Chunk with length 468 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3741,6 +3816,7 @@ - Sending new block at BSN 4, CS=MCS-1 -- Chunk with length 446 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3751,6 +3827,7 @@ - Sending new block at BSN 5, CS=MCS-1 -- Chunk with length 424 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3761,6 +3838,7 @@ - Sending new block at BSN 6, CS=MCS-1 -- Chunk with length 402 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3771,6 +3849,7 @@ - Sending new block at BSN 7, CS=MCS-1 -- Chunk with length 380 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3781,6 +3860,7 @@ - Sending new block at BSN 8, CS=MCS-1 -- Chunk with length 358 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3791,6 +3871,7 @@ - Sending new block at BSN 9, CS=MCS-1 -- Chunk with length 336 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3801,6 +3882,7 @@ - Sending new block at BSN 10, CS=MCS-1 -- Chunk with length 314 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3811,6 +3893,7 @@ - Sending new block at BSN 11, CS=MCS-1 -- Chunk with length 292 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3821,6 +3904,7 @@ - Sending new block at BSN 12, CS=MCS-1 -- Chunk with length 270 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3831,6 +3915,7 @@ - Sending new block at BSN 13, CS=MCS-1 -- Chunk with length 248 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3841,6 +3926,7 @@ - Sending new block at BSN 14, CS=MCS-1 -- Chunk with length 226 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3851,6 +3937,7 @@ - Sending new block at BSN 15, CS=MCS-1 -- Chunk with length 204 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3861,6 +3948,7 @@ - Sending new block at BSN 16, CS=MCS-1 -- Chunk with length 182 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3871,6 +3959,7 @@ - Sending new block at BSN 17, CS=MCS-1 -- Chunk with length 160 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3881,6 +3970,7 @@ - Sending new block at BSN 18, CS=MCS-1 -- Chunk with length 138 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3891,6 +3981,7 @@ - Sending new block at BSN 19, CS=MCS-1 -- Chunk with length 116 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 19, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3901,6 +3992,7 @@ - Sending new block at BSN 20, CS=MCS-1 -- Chunk with length 94 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 20, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3911,6 +4003,7 @@ - Sending new block at BSN 21, CS=MCS-1 -- Chunk with length 72 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 21, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3921,6 +4014,7 @@ - Sending new block at BSN 22, CS=MCS-1 -- Chunk with length 50 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 22, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3931,6 +4025,7 @@ - Sending new block at BSN 23, CS=MCS-1 -- Chunk with length 28 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 23, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3946,6 +4041,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 24, MCS-1): 0c 1d 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4006,6 +4102,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=16 data block (BSN 0, MCS-2): 14 21 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4019,6 +4116,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4029,6 +4127,7 @@ - Sending new block at BSN 2, CS=MCS-2 -- Chunk with length 484 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4039,6 +4138,7 @@ - Sending new block at BSN 3, CS=MCS-2 -- Chunk with length 456 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4049,6 +4149,7 @@ - Sending new block at BSN 4, CS=MCS-2 -- Chunk with length 428 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4059,6 +4160,7 @@ - Sending new block at BSN 5, CS=MCS-2 -- Chunk with length 400 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4069,6 +4171,7 @@ - Sending new block at BSN 6, CS=MCS-2 -- Chunk with length 372 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4079,6 +4182,7 @@ - Sending new block at BSN 7, CS=MCS-2 -- Chunk with length 344 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4089,6 +4193,7 @@ - Sending new block at BSN 8, CS=MCS-2 -- Chunk with length 316 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4099,6 +4204,7 @@ - Sending new block at BSN 9, CS=MCS-2 -- Chunk with length 288 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4109,6 +4215,7 @@ - Sending new block at BSN 10, CS=MCS-2 -- Chunk with length 260 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4119,6 +4226,7 @@ - Sending new block at BSN 11, CS=MCS-2 -- Chunk with length 232 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4129,6 +4237,7 @@ - Sending new block at BSN 12, CS=MCS-2 -- Chunk with length 204 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4139,6 +4248,7 @@ - Sending new block at BSN 13, CS=MCS-2 -- Chunk with length 176 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4149,6 +4259,7 @@ - Sending new block at BSN 14, CS=MCS-2 -- Chunk with length 148 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4159,6 +4270,7 @@ - Sending new block at BSN 15, CS=MCS-2 -- Chunk with length 120 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4169,6 +4281,7 @@ - Sending new block at BSN 16, CS=MCS-2 -- Chunk with length 92 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4179,6 +4292,7 @@ - Sending new block at BSN 17, CS=MCS-2 -- Chunk with length 64 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4189,6 +4303,7 @@ - Sending new block at BSN 18, CS=MCS-2 -- Chunk with length 36 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4204,6 +4319,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=18 data block (BSN 19, MCS-2): 10 25 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4264,6 +4380,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=25 data block (BSN 0, MCS-3): 14 33 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4277,6 +4394,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4287,6 +4405,7 @@ - Sending new block at BSN 2, CS=MCS-3 -- Chunk with length 475 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4297,6 +4416,7 @@ - Sending new block at BSN 3, CS=MCS-3 -- Chunk with length 438 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4307,6 +4427,7 @@ - Sending new block at BSN 4, CS=MCS-3 -- Chunk with length 401 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4317,6 +4438,7 @@ - Sending new block at BSN 5, CS=MCS-3 -- Chunk with length 364 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4327,6 +4449,7 @@ - Sending new block at BSN 6, CS=MCS-3 -- Chunk with length 327 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4337,6 +4460,7 @@ - Sending new block at BSN 7, CS=MCS-3 -- Chunk with length 290 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4347,6 +4471,7 @@ - Sending new block at BSN 8, CS=MCS-3 -- Chunk with length 253 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4357,6 +4482,7 @@ - Sending new block at BSN 9, CS=MCS-3 -- Chunk with length 216 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4367,6 +4493,7 @@ - Sending new block at BSN 10, CS=MCS-3 -- Chunk with length 179 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4377,6 +4504,7 @@ - Sending new block at BSN 11, CS=MCS-3 -- Chunk with length 142 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4387,6 +4515,7 @@ - Sending new block at BSN 12, CS=MCS-3 -- Chunk with length 105 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4397,6 +4526,7 @@ - Sending new block at BSN 13, CS=MCS-3 -- Chunk with length 68 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4410,6 +4540,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-3): 3f 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4425,6 +4556,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=34 data block (BSN 15, MCS-3): 02 45 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4485,6 +4617,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=32 data block (BSN 0, MCS-4): 14 41 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4498,6 +4631,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4508,6 +4642,7 @@ - Sending new block at BSN 2, CS=MCS-4 -- Chunk with length 468 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4518,6 +4653,7 @@ - Sending new block at BSN 3, CS=MCS-4 -- Chunk with length 424 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4528,6 +4664,7 @@ - Sending new block at BSN 4, CS=MCS-4 -- Chunk with length 380 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4538,6 +4675,7 @@ - Sending new block at BSN 5, CS=MCS-4 -- Chunk with length 336 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4548,6 +4686,7 @@ - Sending new block at BSN 6, CS=MCS-4 -- Chunk with length 292 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4558,6 +4697,7 @@ - Sending new block at BSN 7, CS=MCS-4 -- Chunk with length 248 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4568,6 +4708,7 @@ - Sending new block at BSN 8, CS=MCS-4 -- Chunk with length 204 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4578,6 +4719,7 @@ - Sending new block at BSN 9, CS=MCS-4 -- Chunk with length 160 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4588,6 +4730,7 @@ - Sending new block at BSN 10, CS=MCS-4 -- Chunk with length 116 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4598,6 +4741,7 @@ - Sending new block at BSN 11, CS=MCS-4 -- Chunk with length 72 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4613,6 +4757,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 12, MCS-4): 38 1d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4673,6 +4818,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-5): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4686,6 +4832,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4696,6 +4843,7 @@ - Sending new block at BSN 2, CS=MCS-5 -- Chunk with length 456 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4706,6 +4854,7 @@ - Sending new block at BSN 3, CS=MCS-5 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4716,6 +4865,7 @@ - Sending new block at BSN 4, CS=MCS-5 -- Chunk with length 344 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4726,6 +4876,7 @@ - Sending new block at BSN 5, CS=MCS-5 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4736,6 +4887,7 @@ - Sending new block at BSN 6, CS=MCS-5 -- Chunk with length 232 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4746,6 +4898,7 @@ - Sending new block at BSN 7, CS=MCS-5 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4756,6 +4909,7 @@ - Sending new block at BSN 8, CS=MCS-5 -- Chunk with length 120 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4766,6 +4920,7 @@ - Sending new block at BSN 9, CS=MCS-5 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4781,6 +4936,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-5): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4841,6 +4997,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-6): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4854,6 +5011,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4864,6 +5022,7 @@ - Sending new block at BSN 2, CS=MCS-6 -- Chunk with length 438 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4874,6 +5033,7 @@ - Sending new block at BSN 3, CS=MCS-6 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4884,6 +5044,7 @@ - Sending new block at BSN 4, CS=MCS-6 -- Chunk with length 290 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4894,6 +5055,7 @@ - Sending new block at BSN 5, CS=MCS-6 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4904,6 +5066,7 @@ - Sending new block at BSN 6, CS=MCS-6 -- Chunk with length 142 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4917,6 +5080,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-6): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4932,6 +5096,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-6): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4993,6 +5158,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-7): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5002,12 +5168,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(7) last_mcs(5) demanded_mcs(7)cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-7 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5022,6 +5189,7 @@ - Sending new block at BSN 3, CS=MCS-7 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5036,6 +5204,7 @@ - Sending new block at BSN 5, CS=MCS-7 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5050,6 +5219,7 @@ - Sending new block at BSN 7, CS=MCS-7 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5064,6 +5234,7 @@ - Sending new block at BSN 9, CS=MCS-7 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 9) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5081,6 +5252,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-7): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5142,6 +5314,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=56 data block (BSN 0, MCS-8): 14 71 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5152,12 +5325,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(8) demanded_mcs(8) cs_trans(8) +- initial_cs_dl(8) last_mcs(8) demanded_mcs(8)cs_trans(8) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-8 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5172,6 +5346,7 @@ - Sending new block at BSN 3, CS=MCS-8 -- Chunk with length 376 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5186,6 +5361,7 @@ - Sending new block at BSN 5, CS=MCS-8 -- Chunk with length 240 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5200,6 +5376,7 @@ - Sending new block at BSN 7, CS=MCS-8 -- Chunk with length 104 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5217,6 +5394,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=30 data block (BSN 8, MCS-8): 48 3d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5279,6 +5457,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-9): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5288,12 +5467,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(9) last_mcs(6) demanded_mcs(9)cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-9 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5308,6 +5488,7 @@ - Sending new block at BSN 3, CS=MCS-9 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5322,6 +5503,7 @@ - Sending new block at BSN 5, CS=MCS-9 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5339,6 +5521,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-9): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5356,6 +5539,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-9): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5402,11 +5586,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(6)cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5450,11 +5636,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 96 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(1) demanded_mcs(1) cs_trans(1) +- initial_cs_dl(1) last_mcs(1) demanded_mcs(1)cs_trans(1) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 98 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5498,11 +5686,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-2): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 92 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(2) demanded_mcs(2) cs_trans(2) +- initial_cs_dl(2) last_mcs(2) demanded_mcs(2)cs_trans(2) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 94 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5546,6 +5736,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5557,6 +5748,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-5): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5564,10 +5756,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-5): 0f 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7)cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7)cs_trans(7) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-7): 07 00 00 02 c0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 @@ -5612,6 +5805,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5623,6 +5817,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-6): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5630,10 +5825,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-6): 0f 40 00 00 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9)cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9)cs_trans(9) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-9): 07 00 00 02 28 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 @@ -5686,6 +5882,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-7): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5694,13 +5891,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-7): 0f 00 00 02 a0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5)cs_trans(5) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5)cs_trans(5) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-5): 07 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5752,6 +5951,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-9): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5760,13 +5960,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-9): 0f 00 00 02 00 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6)cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6)cs_trans(6) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-6): 07 40 00 02 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5780,3 +5982,233 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-5 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(2)cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 d2 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(2) demanded_mcs(2)cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 f2 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-4 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (44) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-4): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-4): 07 00 00 80 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(4) demanded_mcs(1)cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 d6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(1) demanded_mcs(1)cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 f6 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(6)cs_trans(6) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 2 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..c38417d 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,9 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_egprs_spb_dl === +Testing retx for MCS 6 to reseg_mcs 3 +Testing retx for MCS 5 to reseg_mcs 2 +Testing retx for MCS 4 to reseg_mcs 1 +Testing retx for MCS 6 to reseg_mcs 3 +=== end test_tbf_egprs_spb_dl === -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 13 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Thu Aug 11 08:56:17 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 11 Aug 2016 08:56:17 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 13: (1 comment) https://gerrit.osmocom.org/#/c/655/10/src/rlc.cpp File src/rlc.cpp: PS10, Line 427: > 10.4.8b section of TS 44.060 explains the spb values. I will introduce the Done -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 13 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 11 08:56:36 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 11 Aug 2016 08:56:36 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 13: (1 comment) https://gerrit.osmocom.org/#/c/655/10/src/pcu_vty.c File src/pcu_vty.c: PS10, Line 133: % > why the extra space at the end of the line? we never use this anywhere else Done -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 13 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 11 09:40:22 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Thu, 11 Aug 2016 09:40:22 +0000 Subject: osmo-bts[master]: sysmo: fix dyn TS: Revert "Activate PTCCH UL" [in sysmobts] In-Reply-To: References: Message-ID: Patch Set 2: At the very least: add fixme comment to the code, add link to the corresponding ticket to commit message. -- To view, visit https://gerrit.osmocom.org/671 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia59d95c75a8a5d3bd596f55cd1dc0906a6a95f7f Gerrit-PatchSet: 2 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 11 09:42:10 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 11 Aug 2016 09:42:10 +0000 Subject: osmo-bts[master]: sysmo: fix dyn TS: Revert "Activate PTCCH UL" [in sysmobts] In-Reply-To: References: Message-ID: Patch Set 2: > At the very least: add fixme comment to the code, add link to the > corresponding ticket to commit message. The nature of a revert is that a patch is cleanly reverted. If you'd like a comment to the ticket, IMHO it should be a separate patch (by you). I will gladly +vote on that. -- To view, visit https://gerrit.osmocom.org/671 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia59d95c75a8a5d3bd596f55cd1dc0906a6a95f7f Gerrit-PatchSet: 2 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 11 09:45:09 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Thu, 11 Aug 2016 09:45:09 +0000 Subject: osmo-bts[master]: sysmo: fix dyn TS: Revert "Activate PTCCH UL" [in sysmobts] In-Reply-To: References: Message-ID: Patch Set 2: Commit will not make revert "unclean" but will make use of "git blame" easier. -- To view, visit https://gerrit.osmocom.org/671 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia59d95c75a8a5d3bd596f55cd1dc0906a6a95f7f Gerrit-PatchSet: 2 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 11 10:31:35 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 11 Aug 2016 10:31:35 +0000 Subject: [PATCH] osmo-bts[master]: sysmo: fix dyn TS: Revert "Activate PTCCH UL" [in sysmobts] In-Reply-To: References: Message-ID: Hello Max, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/671 to look at the new patch set (#3). sysmo: fix dyn TS: Revert "Activate PTCCH UL" [in sysmobts] This reverts commit 53d792c3b027bfb42d77804e3e687a287e122ef3. See http://osmocom.org/issues/1796 The commit caused this error for PDCH TS with SysmoBTS: DL1P <0007> l1_if.c:164 Tx L1 prim MPH-ACTIVATE.req DL1C <0006> oml.c:811 Error activating L1 SAPI PTCCH on TS 7: Invalid parameter DL1C <0006> oml.c:1089 (bts=0,trx=0,ts=7,ss=0) act failed mark broken due status: -4 Plain PDCH TS show this error but continue to function despite the SAPI activation failure. As a side effect, the SAPI activation failure breaks dynamic TS. GPRS initially works, but the broken status prevents transitions to TCH/* modes in the BSC: DRLL <0000> chan_alloc.c:355 Failed to allocate TCH_H channel DRSL <0004> abis_rsl.c:1656 BTS 0 CHAN RQD: no resources for TCH_H 0x45 Since the commit only enabled PTCCH UL in sysmobts, no other BTS models are affected. Notice that lc15 still has PTCCH UL disabled all the while, before and after this commit and its revert. Also note that PTCCH DL is and has been enabled without problems (see further above in sapi_dir_pdtch_sapis[]). This is only about PTCCH UL. Related: OS#1796 Change-Id: Ia59d95c75a8a5d3bd596f55cd1dc0906a6a95f7f --- M src/osmo-bts-sysmo/oml.c 1 file changed, 1 insertion(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/71/671/3 diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c index e9a4794..585e6d0 100644 --- a/src/osmo-bts-sysmo/oml.c +++ b/src/osmo-bts-sysmo/oml.c @@ -617,9 +617,8 @@ { GsmL1_Sapi_Pdtch, GsmL1_Dir_RxUplink }, { GsmL1_Sapi_Ptcch, GsmL1_Dir_TxDownlink }, { GsmL1_Sapi_Prach, GsmL1_Dir_RxUplink }, - { GsmL1_Sapi_Ptcch, GsmL1_Dir_RxUplink }, - /* FIXME: do we still need this if? */ #if 0 + { GsmL1_Sapi_Ptcch, GsmL1_Dir_RxUplink }, { GsmL1_Sapi_Pacch, GsmL1_Dir_TxDownlink }, #endif }; -- To view, visit https://gerrit.osmocom.org/671 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia59d95c75a8a5d3bd596f55cd1dc0906a6a95f7f Gerrit-PatchSet: 3 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Thu Aug 11 10:31:49 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 11 Aug 2016 10:31:49 +0000 Subject: osmo-bts[master]: sysmo: fix dyn TS: Revert "Activate PTCCH UL" [in sysmobts] In-Reply-To: References: Message-ID: Patch Set 3: Max, instead of editing the revert patch, I have edited the commit log message to point at OS#1796 (and generally clarified the log msg). I hope this is sufficient to conclude the issue. -- To view, visit https://gerrit.osmocom.org/671 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia59d95c75a8a5d3bd596f55cd1dc0906a6a95f7f Gerrit-PatchSet: 3 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 11 11:05:36 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 11 Aug 2016 11:05:36 +0000 Subject: osmo-pcu[master]: jenkins.sh: use absolute paths instead of 'cd ..' and $PWD In-Reply-To: References: Message-ID: Patch Set 1: > Okay, but is there a good reason for it? My reasons: 1. I find it hard to follow the cwd and what paths like "../install" actually mean. With abs path variables, cwd is always clear. 2. When editing, it is easy to forget a "cd .." in the middle, and the rest ends up in the wrong dir. With abs path variables, we will always be in the right dir. -- To view, visit https://gerrit.osmocom.org/680 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: If79d283fa0a559bb7ea319c513d09466eff523d1 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 11 11:06:26 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 11 Aug 2016 11:06:26 +0000 Subject: [MERGED] osmo-pcu[master]: jenkins.sh: use absolute paths instead of 'cd ..' and $PWD In-Reply-To: References: Message-ID: Neels Hofmeyr has submitted this change and it was merged. Change subject: jenkins.sh: use absolute paths instead of 'cd ..' and $PWD ...................................................................... jenkins.sh: use absolute paths instead of 'cd ..' and $PWD Change-Id: If79d283fa0a559bb7ea319c513d09466eff523d1 --- M contrib/jenkins.sh 1 file changed, 16 insertions(+), 11 deletions(-) Approvals: Jenkins Builder: Verified Holger Freyther: Looks good to me, approved diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index 7d3acc0..b4b0cb7 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -12,18 +12,22 @@ exit 0 fi -rm -rf deps/install -mkdir deps || true -cd deps +base="$PWD" +deps="$base/deps" +inst="$deps/install" + +rm -rf "$inst" +mkdir "$deps" || true +cd "$deps" osmo-deps.sh libosmocore cd libosmocore autoreconf --install --force -./configure --prefix=$PWD/../install +./configure --prefix="$inst" $MAKE $PARALLEL_MAKE install # Install the API -cd ../ +cd "$deps" if ! test -d layer1-api; then git clone git://git.sysmocom.de/sysmo-bts/layer1-api.git layer1-api @@ -32,16 +36,17 @@ cd layer1-api git fetch origin git reset --hard origin/master -mkdir -p $PWD/../install/include/sysmocom/femtobts/ -cp include/*.h ../install/include/sysmocom/femtobts/ +api_incl="$inst/include/sysmocom/femtobts/" +mkdir -p "$api_incl" +cp include/*.h "$api_incl" -cd ../../ +cd "$base" autoreconf --install --force BTS_CONFIG="--enable-sysmocom-bts=$sysmobts --enable-sysmocom-dsp=$sysmodsp" if [ $sysmobts = "no" ]; then BTS_CONFIG="$BTS_CONFIG --enable-vty-tests" fi -PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig ./configure $BTS_CONFIG -PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig $MAKE $PARALLEL_MAKE -DISTCHECK_CONFIGURE_FLAGS="$BTS_CONFIG" AM_DISTCHECK_CONFIGURE_FLAGS="$BTS_CONFIG" PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig LD_LIBRARY_PATH=$PWD/deps/install/lib $MAKE distcheck +PKG_CONFIG_PATH="$inst/lib/pkgconfig" ./configure $BTS_CONFIG +PKG_CONFIG_PATH="$inst/lib/pkgconfig" $MAKE $PARALLEL_MAKE +DISTCHECK_CONFIGURE_FLAGS="$BTS_CONFIG" AM_DISTCHECK_CONFIGURE_FLAGS="$BTS_CONFIG" PKG_CONFIG_PATH="$inst/lib/pkgconfig" LD_LIBRARY_PATH="$inst/lib" $MAKE distcheck -- To view, visit https://gerrit.osmocom.org/680 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: If79d283fa0a559bb7ea319c513d09466eff523d1 Gerrit-PatchSet: 2 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Thu Aug 11 11:06:28 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 11 Aug 2016 11:06:28 +0000 Subject: [MERGED] osmo-pcu[master]: jenkins.sh: more quotes, cosmetics, less dup In-Reply-To: References: Message-ID: Neels Hofmeyr has submitted this change and it was merged. Change subject: jenkins.sh: more quotes, cosmetics, less dup ...................................................................... jenkins.sh: more quotes, cosmetics, less dup Rename BTS_CONFIG to PCU_CONFIG. More quotes. Unify bash if-style. Define *_PATH variables once globally instead of duping in every line. Change-Id: If148632c3f340a8a395fa432135e593fecc41e82 --- M contrib/jenkins.sh 1 file changed, 16 insertions(+), 17 deletions(-) Approvals: Jenkins Builder: Verified Holger Freyther: Looks good to me, approved diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index b4b0cb7..e108e36 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -7,9 +7,9 @@ exit 1 fi -if [ $sysmobts = "no" -a $sysmodsp = "yes" ]; then - echo "This config does not make sense." - exit 0 +if [ "$sysmobts" = "no" -a "$sysmodsp" = "yes" ]; then + echo "This config does not make sense." + exit 0 fi base="$PWD" @@ -17,22 +17,19 @@ inst="$deps/install" rm -rf "$inst" -mkdir "$deps" || true +mkdir -p "$deps" + cd "$deps" osmo-deps.sh libosmocore - cd libosmocore autoreconf --install --force ./configure --prefix="$inst" $MAKE $PARALLEL_MAKE install -# Install the API cd "$deps" -if ! test -d layer1-api; -then +if [ ! -d layer1-api ]; then git clone git://git.sysmocom.de/sysmo-bts/layer1-api.git layer1-api fi - cd layer1-api git fetch origin git reset --hard origin/master @@ -40,13 +37,15 @@ mkdir -p "$api_incl" cp include/*.h "$api_incl" -cd "$base" -autoreconf --install --force -BTS_CONFIG="--enable-sysmocom-bts=$sysmobts --enable-sysmocom-dsp=$sysmodsp" -if [ $sysmobts = "no" ]; then - BTS_CONFIG="$BTS_CONFIG --enable-vty-tests" +PCU_CONFIG="--enable-sysmocom-bts=$sysmobts --enable-sysmocom-dsp=$sysmodsp" +if [ "$sysmobts" = "no" ]; then + PCU_CONFIG="$PCU_CONFIG --enable-vty-tests" fi -PKG_CONFIG_PATH="$inst/lib/pkgconfig" ./configure $BTS_CONFIG -PKG_CONFIG_PATH="$inst/lib/pkgconfig" $MAKE $PARALLEL_MAKE -DISTCHECK_CONFIGURE_FLAGS="$BTS_CONFIG" AM_DISTCHECK_CONFIGURE_FLAGS="$BTS_CONFIG" PKG_CONFIG_PATH="$inst/lib/pkgconfig" LD_LIBRARY_PATH="$inst/lib" $MAKE distcheck +export PKG_CONFIG_PATH="$inst/lib/pkgconfig" +export LD_LIBRARY_PATH="$inst/lib" +cd "$base" +autoreconf --install --force +./configure $PCU_CONFIG +$MAKE $PARALLEL_MAKE +DISTCHECK_CONFIGURE_FLAGS="$PCU_CONFIG" AM_DISTCHECK_CONFIGURE_FLAGS="$PCU_CONFIG" $MAKE distcheck -- To view, visit https://gerrit.osmocom.org/681 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: If148632c3f340a8a395fa432135e593fecc41e82 Gerrit-PatchSet: 2 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Thu Aug 11 11:06:28 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 11 Aug 2016 11:06:28 +0000 Subject: [MERGED] osmo-pcu[master]: jenkins.sh: change build matrix to $with_dsp and $with_vty In-Reply-To: References: Message-ID: Neels Hofmeyr has submitted this change and it was merged. Change subject: jenkins.sh: change build matrix to $with_dsp and $with_vty ...................................................................... jenkins.sh: change build matrix to $with_dsp and $with_vty The new $with_dsp matrix parameter is defined as "sysmo" or empty/"none". The lc15 DSP might be added in the future. Fetch the sysmo layer 1 API only if with_dsp==sysmo. The new $with_vty parameter is independent of $with_dsp, it is now up to jenkins to define a matrix filter. For compat, until jenkins is reconfigured with the new matrix parameters, use $sysmodsp to init the new parameters to reflect previous behavior. The $sysmobts matrix parameter made no sense, drop it. Change-Id: Ia120f918342dc9563814252258b73bfb267e5253 --- M contrib/jenkins.sh 1 file changed, 43 insertions(+), 19 deletions(-) Approvals: Max: Looks good to me, but someone else must approve Jenkins Builder: Verified Holger Freyther: Looks good to me, approved diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index e108e36..7826911 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -7,10 +7,14 @@ exit 1 fi -if [ "$sysmobts" = "no" -a "$sysmodsp" = "yes" ]; then - echo "This config does not make sense." - exit 0 +# Compat: to be able to smoothly reconfigure the jenkins job, handle both +# old and new matrix variables +if [ -z "$with_dsp" -a "$sysmodsp" = yes ]; then + with_dsp="sysmo" +else + with_vty="yes" fi +# end of compat part base="$PWD" deps="$base/deps" @@ -19,6 +23,40 @@ rm -rf "$inst" mkdir -p "$deps" +# Collect configure options for osmo-pcu +PCU_CONFIG="" +if [ "$with_dsp" = sysmo ]; then + PCU_CONFIG="$PCU_CONFIG --enable-sysmocom-dsp" + + # For direct sysmo DSP access, provide the SysmoBTS Layer 1 API + cd "$deps" + if [ ! -d layer1-api ]; then + git clone git://git.sysmocom.de/sysmo-bts/layer1-api.git layer1-api + fi + cd layer1-api + git fetch origin + git reset --hard origin/master + api_incl="$inst/include/sysmocom/femtobts/" + mkdir -p "$api_incl" + cp include/*.h "$api_incl" + +elif [ -z "$with_dsp" -o "$with_dsp" = none ]; then + echo "Direct DSP access disabled" +else + echo 'Invalid $with_dsp value:' $with_dsp + exit 1 +fi + +if [ "$with_vty" = "yes" ]; then + PCU_CONFIG="$PCU_CONFIG --enable-vty-tests" +elif [ -z "$with_vty" -o "$with_vty" = "no" ]; then + echo "VTY tests disabled" +else + echo 'Invalid $with_vty value:' $with_vty + exit 1 +fi + +# Build deps cd "$deps" osmo-deps.sh libosmocore cd libosmocore @@ -26,24 +64,10 @@ ./configure --prefix="$inst" $MAKE $PARALLEL_MAKE install -cd "$deps" -if [ ! -d layer1-api ]; then - git clone git://git.sysmocom.de/sysmo-bts/layer1-api.git layer1-api -fi -cd layer1-api -git fetch origin -git reset --hard origin/master -api_incl="$inst/include/sysmocom/femtobts/" -mkdir -p "$api_incl" -cp include/*.h "$api_incl" - -PCU_CONFIG="--enable-sysmocom-bts=$sysmobts --enable-sysmocom-dsp=$sysmodsp" -if [ "$sysmobts" = "no" ]; then - PCU_CONFIG="$PCU_CONFIG --enable-vty-tests" -fi - export PKG_CONFIG_PATH="$inst/lib/pkgconfig" export LD_LIBRARY_PATH="$inst/lib" + +# Build osmo-pcu cd "$base" autoreconf --install --force ./configure $PCU_CONFIG -- To view, visit https://gerrit.osmocom.org/682 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ia120f918342dc9563814252258b73bfb267e5253 Gerrit-PatchSet: 3 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Thu Aug 11 11:06:28 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 11 Aug 2016 11:06:28 +0000 Subject: [MERGED] osmo-pcu[master]: jenkins.sh: ensure $MAKE is set In-Reply-To: References: Message-ID: Neels Hofmeyr has submitted this change and it was merged. Change subject: jenkins.sh: ensure $MAKE is set ...................................................................... jenkins.sh: ensure $MAKE is set Change-Id: I2da8acdfe3abf79f68db4d00d04a7d162f0123ce --- M contrib/jenkins.sh 1 file changed, 5 insertions(+), 0 deletions(-) Approvals: Jenkins Builder: Verified Holger Freyther: Looks good to me, approved diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index 27cdaa9..7d3acc0 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -2,6 +2,11 @@ set -ex +if [ -z "$MAKE" ]; then + echo 'The $MAKE variable is not defined, cannot build' + exit 1 +fi + if [ $sysmobts = "no" -a $sysmodsp = "yes" ]; then echo "This config does not make sense." exit 0 -- To view, visit https://gerrit.osmocom.org/679 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I2da8acdfe3abf79f68db4d00d04a7d162f0123ce Gerrit-PatchSet: 2 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Thu Aug 11 11:08:52 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 11 Aug 2016 11:08:52 +0000 Subject: [ABANDON] openbsc[master]: gsm_ts2chan_nr(): use constants instead of magic numbers In-Reply-To: References: Message-ID: Neels Hofmeyr has abandoned this change. Change subject: gsm_ts2chan_nr(): use constants instead of magic numbers ...................................................................... Abandoned I'd prefer using enum constants but no need to keep this lingering forever. -- To view, visit https://gerrit.osmocom.org/625 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: abandon Gerrit-Change-Id: I0392d179f98842d75eee586161e0aa014337f9ab Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Thu Aug 11 12:30:41 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Thu, 11 Aug 2016 12:30:41 +0000 Subject: [PATCH] openbsc[master]: Adding SNDCP-XID encoder / decoder and unit test In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/641 to look at the new patch set (#9). Adding SNDCP-XID encoder / decoder and unit test The SNDCP-XID (or layer-3 xid) is used to exchange layer-3 parameters such as compression. The encoder encodes a bytestream that is then sent as regular XID field from LLC. We will need the SNDCP-XID to negotiate the parameters for our upcomming GPRS data and header compression features Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e --- M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_sndcp_xid.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_sndcp_xid.c M openbsc/tests/Makefile.am M openbsc/tests/sgsn/Makefile.am M openbsc/tests/testsuite.at A openbsc/tests/xid_sndcp/Makefile.am A openbsc/tests/xid_sndcp/sndcp_xid_test.c A openbsc/tests/xid_sndcp/sndcp_xid_test.ok 11 files changed, 2,414 insertions(+), 5 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/41/641/9 diff --git a/openbsc/configure.ac b/openbsc/configure.ac index fbf2930..9cfdc7c 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -230,6 +230,7 @@ tests/gtphub/Makefile tests/mm_auth/Makefile tests/xid/Makefile + tests/xid_sndcp/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index ce5f768..e200b05 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,7 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_llc_xid.h gprs_sndcp.h + gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_sndcp_xid.h b/openbsc/include/openbsc/gprs_sndcp_xid.h new file mode 100644 index 0000000..8c5cbf4 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_xid.h @@ -0,0 +1,214 @@ +/* GPRS SNDCP XID field encoding/decoding as per 3GPP TS 44.065 */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_SNDCP_XID_H +#define _GPRS_SNDCP_XID_H + +#include +#include + +#define CURRENT_SNDCP_VERSION 0 /* See 3GPP TS 44.065, clause 8 */ +#define MAX_ENTITIES 32 /* 3GPP TS 44.065 reserves 5 bit + * for compression enitity number */ + +/* According to: 3GPP TS 44.065, 6.5.1.1 Format of the protocol control + * information compression field (Figure 7) + * 3GPP TS 44.065, 6.6.1.1 Format of the data compression + * field (Figure 9) */ +struct gprs_sndcp_comp_field { + struct llist_head list; + + /* Propose bit (P), see also: 6.5.1.1.2 and 6.6.1.1.2 */ + unsigned int p; + + /* Entity number, see also: 6.5.1.1.3 and 6.6.1.1.3 */ + unsigned int entity; + + /* Algorithm identifier, see also: 6.5.1.1.4 and 6.6.1.1.4 */ + int algo; + + /* Number of contained PCOMP / DCOMP values */ + unsigned int comp_len; + + /* PCOMP / DCOMP values, see also: 6.5.1.1.5 and 6.6.1.1.5 */ + unsigned int comp[16]; + + /* Note: Only one of the following struct pointers may, + be used unused pointers must be set to NULL! */ + struct gprs_sndcp_pcomp_rfc1144_params *rfc1144_params; + struct gprs_sndcp_pcomp_rfc2507_params *rfc2507_params; + struct gprs_sndcp_pcomp_rohc_params *rohc_params; + struct gprs_sndcp_dcomp_v42bis_params *v42bis_params; + struct gprs_sndcp_dcomp_v44_params *v44_params; +}; + +/* According to: 3GPP TS 44.065, 6.5.1.1.4 Algorithm identifier */ +enum gprs_sndcp_hdr_comp_algo { + RFC_1144, /* TCP/IP header compression, see also 6.5.2 */ + RFC_2507, /* TCP/UDP/IP header compression, see also: 6.5.3 */ + ROHC /* Robust Header Compression, see also 6.5.4 */ +}; + +/* According to: 3GPP TS 44.065, 6.5.1.1.4 Algorithm identifier */ +enum gprs_sndcp_data_comp_algo { + V42BIS, /* V.42bis data compression, see also 6.6.2 */ + V44 /* V44 data compression, see also: 6.6.3 */ +}; + +/* According to: 3GPP TS 44.065, 8 SNDCP XID parameters */ +enum gprs_sndcp_xid_param_types { + SNDCP_XID_VERSION_NUMBER, + SNDCP_XID_DATA_COMPRESSION, /* See also: subclause 6.6.1 */ + SNDCP_XID_PROTOCOL_COMPRESSION, /* See also: subclause 6.5.1 */ +}; + +/* According to: 3GPP TS 44.065, 6.5.2.1 Parameters (Table 5) */ +struct gprs_sndcp_pcomp_rfc1144_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int s01; /* (default 15) */ +}; + +/* According to: 3GPP TS 44.065, 6.5.2.2 Assignment of PCOMP values */ +enum gprs_sndcp_pcomp_rfc1144_pcomp { + RFC1144_PCOMP1, /* Uncompressed TCP */ + RFC1144_PCOMP2, /* Compressed TCP */ + RFC1144_PCOMP_NUM /* Number of pcomp values */ +}; + +/* According to: 3GPP TS 44.065, 6.5.3.1 Parameters (Table 6) */ +struct gprs_sndcp_pcomp_rfc2507_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int f_max_period; /* (default 256) */ + int f_max_time; /* (default 5) */ + int max_header; /* (default 168) */ + int tcp_space; /* (default 15) */ + int non_tcp_space; /* (default 15) */ +}; + +/* According to: 3GPP TS 44.065, 6.5.3.2 Assignment of PCOMP values for RFC2507 */ +enum gprs_sndcp_pcomp_rfc2507_pcomp { + RFC2507_PCOMP1, /* Full Header */ + RFC2507_PCOMP2, /* Compressed TCP */ + RFC2507_PCOMP3, /* Compressed TCP non delta */ + RFC2507_PCOMP4, /* Compressed non TCP */ + RFC2507_PCOMP5, /* Context state */ + RFC2507_PCOMP_NUM /* Number of pcomp values */ +}; + +/* According to: 3GPP TS 44.065, 6.5.4.1 Parameter (Table 10) */ +struct gprs_sndcp_pcomp_rohc_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int max_cid; /* (default 15) */ + int max_header; /* (default 168) */ + unsigned int profile_len; /* (default 1) */ + uint16_t profile[16]; /* (default 0, ROHC uncompressed) */ +}; + +/* According to: 3GPP TS 44.065, 6.5.4.2 Assignment of PCOMP values for ROHC */ +enum gprs_sndcp_pcomp_rohc_pcomp { + ROHC_PCOMP1, /* ROHC small CIDs */ + ROHC_PCOMP2, /* ROHC large CIDs */ + ROHC_PCOMP_NUM /* Number of pcomp values */ +}; + +/* ROHC compression profiles, see also: + http://www.iana.org/assignments/rohc-pro-ids/rohc-pro-ids.xhtml */ +enum gprs_sndcp_xid_rohc_profiles { + ROHC_UNCOMPRESSED = 0x0000, /* ROHC uncompressed [RFC5795] */ + ROHC_RTP = 0x0001, /* ROHC RTP [RFC3095] */ + ROHCV2_RTP = 0x0101, /* ROHCv2 RTP [RFC5225] */ + ROHC_UDP = 0x0002, /* ROHC UDP [RFC3095] */ + ROHCv2_UDP = 0x0102, /* ROHCv2 UDP [RFC5225] */ + ROHC_ESP = 0x0003, /* ROHC ESP [RFC3095] */ + ROHCV2_ESP = 0x0103, /* ROHCv2 ESP [RFC5225] */ + ROHC_IP = 0x0004, /* ROHC IP [RFC3843] */ + ROHCV2_IP = 0x0104, /* ROHCv2 IP [RFC5225] */ + ROHC_LLA = 0x0005, /* ROHC LLA [RFC4362] */ + ROHC_LLA_WITH_R_MODE = 0x0105, /* ROHC LLA with R-mode [RFC3408] */ + ROHC_TCP = 0x0006, /* ROHC TCP [RFC6846] */ + ROHC_RTP_UDP_LITE = 0x0007, /* ROHC RTP/UDP-Lite [RFC4019] */ + ROHCV2_RTP_UDP_LITE = 0x0107, /* ROHCv2 RTP/UDP-Lite [RFC5225] */ + ROHC_UDP_LITE = 0x0008, /* ROHC UDP-Lite [RFC4019] */ + ROHCV2_UDP_LITE = 0x0108, /* ROHCv2 UDP-Lite [RFC5225] */ +}; + +/* According to: 3GPP TS 44.065, 6.6.2.1 Parameters (Table 7a) */ +struct gprs_sndcp_dcomp_v42bis_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int p0; /* (default 3) */ + int p1; /* (default 2048) */ + int p2; /* (default 20) */ + +}; + +/* According to: 3GPP TS 44.065, 6.6.2.2 Assignment of DCOMP values */ +enum gprs_sndcp_dcomp_v42bis_dcomp { + V42BIS_DCOMP1, /* V.42bis enabled */ + V42BIS_DCOMP_NUM /* Number of dcomp values */ +}; + +/* According to: 3GPP TS 44.065, 6.6.3.1 Parameters (Table 7c) */ +struct gprs_sndcp_dcomp_v44_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int c0; /* (default 10000000) */ + int p0; /* (default 3) */ + int p1t; /* Refer to subclause 6.6.3.1.4 */ + int p1r; /* Refer to subclause 6.6.3.1.5 */ + int p3t; /* (default 3 x p1t) */ + int p3r; /* (default 3 x p1r) */ +}; + +/* According to: 3GPP TS 44.065, 6.6.3.2 Assignment of DCOMP values */ +enum gprs_sndcp_dcomp_v44_dcomp { + V44_DCOMP1, /* Packet method compressed */ + V44_DCOMP2, /* Multi packet method compressed */ + V44_DCOMP_NUM /* Number of dcomp values */ +}; + +/* Transform a list with compression fields into an SNDCP-XID message (dst) */ +int gprs_sndcp_compile_xid(uint8_t *dst, unsigned int dst_maxlen, + const struct llist_head *comp_fields); + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +struct llist_head *gprs_sndcp_parse_xid(const void *ctx, + const uint8_t * src, + unsigned int src_len, + const struct llist_head *comp_fields_req); + +/* Free a list with SNDCP-XID fields */ +struct llist_head *gprs_sndcp_free_comp_fields(struct llist_head *comp_fields); + +/* Find out to which compression class the specified comp-field belongs + * (header compression or data compression?) */ +int gprs_sndcp_get_compression_class( + const struct gprs_sndcp_comp_field *comp_field); + +/* Dump a list with SNDCP-XID fields (Debug) */ +void gprs_sndcp_dump_comp_fields(const struct llist_head *comp_fields, + unsigned int logl); + +#endif diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 1b6de46..fa4a3dd 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -26,11 +26,11 @@ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ - oap.c oap_messages.c gprs_llc_xid.c + oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ - $(LIBCRYPTO_LIBS) -lrt + $(LIBCRYPTO_LIBS) -lrt -lm osmo_gtphub_SOURCES = gtphub_main.c gtphub.c gtphub_sock.c gtphub_ares.c \ gtphub_vty.c sgsn_ares.c gprs_utils.c diff --git a/openbsc/src/gprs/gprs_sndcp_xid.c b/openbsc/src/gprs/gprs_sndcp_xid.c new file mode 100644 index 0000000..fd2a692 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_xid.c @@ -0,0 +1,1872 @@ +/* GPRS SNDCP XID field encoding/decoding as per 3GPP TS 44.065 */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* When the propose bit in an SNDCP-XID compression field is set to zero, + * the algorithm identifier is stripped. The algoritm parameters are specific + * for each algorithms. The following struct is used to pass the information + * about the referenced algorithm to the parser. */ +struct entity_algo_table { + unsigned int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + unsigned int algo; /* see also: 6.5.1.1.4 and 6.6.1.1.4 */ + unsigned int compclass; /* Can be either SNDCP_XID_DATA_COMPRESSION or + SNDCP_XID_PROTOCOL_COMPRESSION */ +}; + +/* FUNCTIONS RELATED TO SNDCP-XID ENCODING */ + +/* Encode applicable sapis (works the same in all three compression schemes) */ +static int encode_pcomp_applicable_sapis(uint8_t *dst, + const unsigned int *nsapis, + unsigned int nsapis_len) +{ + /* NOTE: Buffer *dst needs offer at 2 bytes + * of space to store the generation results */ + + uint16_t blob; + unsigned int nsapi; + int i; + + OSMO_ASSERT(dst); + OSMO_ASSERT(nsapis); + + /* Bail if number of possible nsapis exceeds valid range + * (Only 11 nsapis possible for PDP-Contexts) */ + OSMO_ASSERT(nsapis_len <= 11); + + /* Encode applicable SAPIs */ + blob = 0; + for (i = 0; i < nsapis_len; i++) { + nsapi = nsapis[i]; + /* Only NSAPI 5 to 15 are applicable for user traffic (PDP- + * contexts). Only for these NSAPIs SNDCP-XID parameters + * can apply. See also 3GPP TS 44.065, 5.1 Service primitives */ + OSMO_ASSERT(nsapi >= 5 && nsapi <= 15); + blob |= (1 << nsapi); + } + + /* Store result */ + *dst = (blob >> 8) & 0xFF; + dst++; + *dst = blob & 0xFF; + + return 2; +} + +/* Encode rfc1144 parameter field + * (see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */ +static int encode_pcomp_rfc1144_params(uint8_t *dst, unsigned int dst_maxlen, const struct + gprs_sndcp_pcomp_rfc1144_params *params) +{ + /* NOTE: Buffer *dst should offer at least 3 bytes + * of space to store the generation results */ + + int dst_counter = 0; + int rc; + + OSMO_ASSERT(params); + OSMO_ASSERT(dst); + OSMO_ASSERT(dst_maxlen >= 3); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode s01 (see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */ + OSMO_ASSERT(params->s01 >= 0); + OSMO_ASSERT(params->s01 <= 255); + *dst = params->s01; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + +/* + * Encode rfc2507 parameter field + * (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) + */ +static int encode_pcomp_rfc2507_params(uint8_t *dst, unsigned int dst_maxlen, + const struct + gprs_sndcp_pcomp_rfc2507_params *params) +{ + /* NOTE: Buffer *dst should offer at least 3 bytes + * of space to store the generation results */ + + int dst_counter = 0; + int rc; + + OSMO_ASSERT(params); + OSMO_ASSERT(dst); + OSMO_ASSERT(dst_maxlen >= 9); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode F_MAX_PERIOD (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->f_max_period >= 1); + OSMO_ASSERT(params->f_max_period <= 65535); + *dst = (params->f_max_period >> 8) & 0xFF; + dst++; + dst_counter++; + *dst = (params->f_max_period) & 0xFF; + dst++; + dst_counter++; + + /* Encode F_MAX_TIME (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->f_max_time >= 1); + OSMO_ASSERT(params->f_max_time <= 255); + *dst = params->f_max_time; + dst++; + dst_counter++; + + /* Encode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->max_header >= 60); + OSMO_ASSERT(params->max_header <= 255); + *dst = params->max_header; + dst++; + dst_counter++; + + /* Encode TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->tcp_space >= 3); + OSMO_ASSERT(params->tcp_space <= 255); + *dst = params->tcp_space; + dst++; + dst_counter++; + + /* Encode NON_TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->non_tcp_space >= 3); + OSMO_ASSERT(params->non_tcp_space <= 65535); + *dst = (params->non_tcp_space >> 8) & 0xFF; + dst++; + dst_counter++; + *dst = (params->non_tcp_space) & 0xFF; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + +/* Encode ROHC parameter field + * (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ +static int encode_pcomp_rohc_params(uint8_t *dst, unsigned int dst_maxlen, + const struct gprs_sndcp_pcomp_rohc_params + *params) +{ + /* NOTE: Buffer *dst should offer at least 36 + * (2 * 16 Profiles + 2 * 3 Parameter) bytes + * of memory space to store generation results */ + + int i; + int dst_counter = 0; + int rc; + + OSMO_ASSERT(params); + OSMO_ASSERT(dst); + OSMO_ASSERT(dst_maxlen >= 38); + + /* Bail if number of ROHC profiles exceeds limit + * (ROHC supports only a maximum of 16 different profiles) */ + OSMO_ASSERT(params->profile_len >= 0); + OSMO_ASSERT(params->profile_len <= 16); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode MAX_CID (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + OSMO_ASSERT(params->max_cid >= 0); + OSMO_ASSERT(params->max_cid <= 16383); + *dst = (params->max_cid >> 8) & 0xFF; + dst++; + *dst = params->max_cid & 0xFF; + dst++; + dst_counter += 2; + + /* Encode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + OSMO_ASSERT(params->max_header >= 60); + OSMO_ASSERT(params->max_header <= 255); + *dst = (params->max_header >> 8) & 0xFF; + dst++; + *dst = params->max_header & 0xFF; + dst++; + dst_counter += 2; + + /* Encode ROHC Profiles (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + for (i = 0; i < params->profile_len; i++) { + *dst = (params->profile[i] >> 8) & 0xFF; + dst++; + *dst = params->profile[i] & 0xFF; + dst++; + dst_counter += 2; + } + + /* Return generated length */ + return dst_counter; +} + +/* Encode V.42bis parameter field + * (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ +static int encode_dcomp_v42bis_params(uint8_t *dst, unsigned int dst_maxlen, + const struct + gprs_sndcp_dcomp_v42bis_params *params) +{ + /* NOTE: Buffer *dst should offer at least 6 bytes + * of space to store the generation results */ + + int dst_counter = 0; + int rc; + + OSMO_ASSERT(params); + OSMO_ASSERT(dst); + OSMO_ASSERT(dst_maxlen >= 6); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode P0 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + OSMO_ASSERT(params->p0 >= 0); + OSMO_ASSERT(params->p0 <= 3); + *dst = params->p0 & 0x03; + dst++; + dst_counter++; + + /* Encode P1 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + OSMO_ASSERT(params->p1 >= 512); + OSMO_ASSERT(params->p1 <= 65535); + *dst = (params->p1 >> 8) & 0xFF; + dst++; + *dst = params->p1 & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P2 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + OSMO_ASSERT(params->p2 >= 6); + OSMO_ASSERT(params->p2 <= 250); + *dst = params->p2; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + +/* Encode V44 parameter field + * (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ +static int encode_dcomp_v44_params(uint8_t *dst, unsigned int dst_maxlen, + const struct gprs_sndcp_dcomp_v44_params + *params) +{ + /* NOTE: Buffer *dst should offer at least 12 bytes + * of space to store the generation results */ + + int dst_counter = 0; + int rc; + + OSMO_ASSERT(params); + OSMO_ASSERT(dst); + OSMO_ASSERT(dst_maxlen >= 12); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode C0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->c0 == 0x80 || params->c0 == 0xC0); + *dst = params->c0 & 0xC0; + dst++; + dst_counter++; + + /* Encode P0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p0 >= 0); + OSMO_ASSERT(params->p0 <= 3); + *dst = params->p0 & 0x03; + dst++; + dst_counter++; + + /* Encode P1T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p1t >= 256); + OSMO_ASSERT(params->p1t <= 65535); + *dst = (params->p1t >> 8) & 0xFF; + dst++; + *dst = params->p1t & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P1R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p1r >= 256); + OSMO_ASSERT(params->p1r <= 65535); + *dst = (params->p1r >> 8) & 0xFF; + dst++; + *dst = params->p1r & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P3T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p3t >= 0); + OSMO_ASSERT(params->p3t <= 65535); + OSMO_ASSERT(params->p3t >= 2 * params->p1t); + *dst = (params->p3t >> 8) & 0xFF; + dst++; + *dst = params->p3t & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P3R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p3r >= 0); + OSMO_ASSERT(params->p3r <= 65535); + OSMO_ASSERT(params->p3r >= 2 * params->p1r); + *dst = (params->p3r >> 8) & 0xFF; + dst++; + *dst = params->p3r & 0xFF; + dst++; + dst_counter += 2; + + /* Return generated length */ + return dst_counter; +} + +/* Encode data or protocol control information compression field + * (see also: 3GPP TS 44.065, 6.6.1.1, Figure 9 and + * 3GPP TS 44.065, 6.5.1.1, Figure 7) */ +static int encode_comp_field(uint8_t *dst, unsigned int dst_maxlen, + const struct gprs_sndcp_comp_field *comp_field) +{ + int dst_counter = 0; + int len; + int expected_length; + int i; + + OSMO_ASSERT(dst); + OSMO_ASSERT(comp_field); + + uint8_t payload_bytes[256]; + int payload_bytes_len = -1; + + /* If possible, try do encode payload bytes first */ + if (comp_field->rfc1144_params) { + payload_bytes_len = + encode_pcomp_rfc1144_params(payload_bytes, + sizeof(payload_bytes), + comp_field->rfc1144_params); + } else if (comp_field->rfc2507_params) { + payload_bytes_len = + encode_pcomp_rfc2507_params(payload_bytes, + sizeof(payload_bytes), + comp_field->rfc2507_params); + } else if (comp_field->rohc_params) { + payload_bytes_len = + encode_pcomp_rohc_params(payload_bytes, + sizeof(payload_bytes), + comp_field->rohc_params); + } else if (comp_field->v42bis_params) { + payload_bytes_len = + encode_dcomp_v42bis_params(payload_bytes, + sizeof(payload_bytes), + comp_field->v42bis_params); + } else if (comp_field->v44_params) { + payload_bytes_len = + encode_dcomp_v44_params(payload_bytes, + sizeof(payload_bytes), + comp_field->v44_params); + } else + OSMO_ASSERT(false); + + /* Bail immediately if payload byte generation failed */ + OSMO_ASSERT(payload_bytes_len >= 0); + + /* Bail if comp_len is out of bounds */ + OSMO_ASSERT(comp_field->comp_len <= sizeof(comp_field->comp)); + + /* Calculate length field of the data block */ + if (comp_field->p) { + len = + payload_bytes_len + + ceil((double)(comp_field->comp_len) / 2.0); + expected_length = len + 3; + } else { + len = payload_bytes_len; + expected_length = len + 2; + } + + /* Bail immediately if no sufficient memory space is supplied */ + OSMO_ASSERT(dst_maxlen >= expected_length); + + /* Check if the entity number is within bounds */ + OSMO_ASSERT(comp_field->entity <= 0x1f); + + /* Check if the algorithm number is within bounds */ + OSMO_ASSERT(comp_field->algo >= 0 || comp_field->algo <= 0x1f); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode Propose bit */ + if (comp_field->p) + *dst |= (1 << 7); + + /* Encode entity number */ + *dst |= comp_field->entity & 0x1F; + dst++; + dst_counter++; + + /* Encode algorithm number */ + if (comp_field->p) { + *dst |= comp_field->algo & 0x1F; + dst++; + dst_counter++; + } + + /* Encode length field */ + *dst |= len & 0xFF; + dst++; + dst_counter++; + + /* Encode PCOMP/DCOMP values */ + if (comp_field->p) { + for (i = 0; i < comp_field->comp_len; i++) { + /* Check if submitted PCOMP/DCOMP + values are within bounds */ + if ((comp_field->comp[i] < 0) + || (comp_field->comp[i] > 0x0F)) + return -EINVAL; + + if (i & 1) { + *dst |= comp_field->comp[i] & 0x0F; + dst++; + dst_counter++; + } else + *dst |= (comp_field->comp[i] << 4) & 0xF0; + } + + if (i & 1) { + dst++; + dst_counter++; + } + } + + /* Append payload bytes */ + memcpy(dst, payload_bytes, payload_bytes_len); + dst_counter += payload_bytes_len; + + /* Return generated length */ + return dst_counter; +} + +/* Find out to which compression class the specified comp-field belongs + * (header compression or data compression?) */ +int gprs_sndcp_get_compression_class(const struct gprs_sndcp_comp_field + *comp_field) +{ + OSMO_ASSERT(comp_field); + + if (comp_field->rfc1144_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->rfc2507_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->rohc_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->v42bis_params) + return SNDCP_XID_DATA_COMPRESSION; + else if (comp_field->v44_params) + return SNDCP_XID_DATA_COMPRESSION; + else + return -EINVAL; +} + +/* Convert all compression fields to bytstreams */ +static int gprs_sndcp_pack_fields(const struct llist_head *comp_fields, + uint8_t *dst, + unsigned int dst_maxlen, int class) +{ + struct gprs_sndcp_comp_field *comp_field; + int byte_counter = 0; + int rc; + + OSMO_ASSERT(comp_fields); + OSMO_ASSERT(dst); + + llist_for_each_entry_reverse(comp_field, comp_fields, list) { + if (class == gprs_sndcp_get_compression_class(comp_field)) { + rc = encode_comp_field(dst + byte_counter, + dst_maxlen - byte_counter, + comp_field); + + /* When input data is correct, there is + * no reason for the encoder to fail! */ + OSMO_ASSERT(rc >= 0); + + byte_counter += rc; + } + } + + /* Return generated length */ + return byte_counter; +} + +/* Transform a list with compression fields into an SNDCP-XID message (dst) */ +int gprs_sndcp_compile_xid(uint8_t *dst, unsigned int dst_maxlen, + const struct llist_head *comp_fields) +{ + int rc; + int byte_counter = 0; + uint8_t comp_bytes[512]; + uint8_t xid_version_number[1] = { CURRENT_SNDCP_VERSION }; + + OSMO_ASSERT(comp_fields); + OSMO_ASSERT(dst); + + /* Exit immediately if no sufficient memory space is supplied */ + OSMO_ASSERT(dst_maxlen >= 2 + sizeof(xid_version_number)); + + /* Prepend header */ + dst = + tlv_put(dst, SNDCP_XID_VERSION_NUMBER, + sizeof(xid_version_number), xid_version_number); + byte_counter += (sizeof(xid_version_number) + 2); + + /* Add data compression fields */ + rc = gprs_sndcp_pack_fields(comp_fields, comp_bytes, + sizeof(comp_bytes), + SNDCP_XID_DATA_COMPRESSION); + OSMO_ASSERT(rc >= 0); + + if (rc > 0) { + dst = tlv_put(dst, SNDCP_XID_DATA_COMPRESSION, rc, comp_bytes); + byte_counter += rc + 2; + } + + /* Add header compression fields */ + rc = gprs_sndcp_pack_fields(comp_fields, comp_bytes, + sizeof(comp_bytes), + SNDCP_XID_PROTOCOL_COMPRESSION); + OSMO_ASSERT(rc >= 0); + + if (rc > 0) { + dst = tlv_put(dst, SNDCP_XID_PROTOCOL_COMPRESSION, rc, + comp_bytes); + byte_counter += rc + 2; + } + + /* Return generated length */ + return byte_counter; +} + +/* FUNCTIONS RELATED TO SNDCP-XID DECODING */ + +/* Decode applicable sapis (works the same in all three compression schemes) */ +static int decode_pcomp_applicable_sapis(unsigned int *nsapis, + unsigned int *nsapis_len, + const uint8_t *src, + unsigned int src_len) +{ + uint16_t blob; + int i; + int nsapi_len = 0; + + OSMO_ASSERT(src); + + /* Exit immediately if no result can be stored */ + if (!nsapis) + return -EINVAL; + + /* Exit immediately if not enough input data is available */ + if (src_len < 2) + return -EINVAL; + + /* Read bitmask */ + blob = *src; + blob = (blob << 8) & 0xFF00; + src++; + blob |= (*src) & 0xFF; + blob = (blob >> 5); + + /* Decode applicable SAPIs */ + for (i = 0; i < 15; i++) { + if ((blob >> i) & 1) { + nsapis[nsapi_len] = i + 5; + nsapi_len++; + } + } + + /* Return consumed length */ + *nsapis_len = nsapi_len; + return 2; +} + +/* Decode 16 bit field */ +static int decode_pcomp_16_bit_field(int *value_int, uint16_t * value_uint16, + const uint8_t *src, + unsigned int src_len, + int value_min, int value_max) +{ + uint16_t blob; + + OSMO_ASSERT(src); + + /* Reset values to zero (just to be sure) */ + if (value_int) + *value_int = -1; + if (value_uint16) + *value_uint16 = 0; + + /* Exit if not enough src are available */ + if (src_len < 2) + return -EINVAL; + + /* Decode bit value */ + blob = *src; + blob = (blob << 8) & 0xFF00; + src++; + blob |= *src; + + /* Check if parsed value is within bounds */ + if (blob < value_min) + return -EINVAL; + if (blob > value_max) + return -EINVAL; + + /* Hand back results to the caller */ + if (value_int) + *value_int = blob; + if (value_uint16) + *value_uint16 = blob; + + /* Return consumed length */ + return 2; +} + +/* Decode 8 bit field */ +static int decode_pcomp_8_bit_field(int *value_int, uint8_t *value_uint8, + const uint8_t *src, + unsigned int src_len, + int value_min, int value_max) +{ + uint8_t blob; + + OSMO_ASSERT(src); + + /* Reset values to invalid (just to be sure) */ + if (value_int) + *value_int = -1; + if (value_uint8) + *value_uint8 = 0; + + /* Exit if not enough src are available */ + if (src_len < 1) + return -EINVAL; + + /* Decode bit value */ + blob = *src; + + /* Check if parsed value is within bounds */ + if (blob < value_min) + return -EINVAL; + if (blob > value_max) + return -EINVAL; + + /* Hand back results to the caller */ + if (value_int) + *value_int = blob; + if (value_uint8) + *value_uint8 = blob; + + /* Return consumed length */ + return 1; +} + +/* Decode rfc1144 parameter field see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */ +static int decode_pcomp_rfc1144_params(struct gprs_sndcp_pcomp_rfc1144_params + *params, const uint8_t *src, + unsigned int src_len) +{ + int rc; + int byte_counter = 0; + + OSMO_ASSERT(params); + OSMO_ASSERT(src); + + /* Mark all optional parameters invalid by default */ + params->s01 = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode parameter S0 -1 + * (see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */ + rc = decode_pcomp_8_bit_field(¶ms->s01, NULL, src, + src_len - byte_counter, 0, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Decode rfc2507 parameter field + * (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ +static int decode_pcomp_rfc2507_params(struct gprs_sndcp_pcomp_rfc2507_params + *params, const uint8_t *src, + unsigned int src_len) +{ + int rc; + int byte_counter = 0; + + OSMO_ASSERT(params); + OSMO_ASSERT(src); + + /* Mark all optional parameters invalid by default */ + params->f_max_period = -1; + params->f_max_time = -1; + params->max_header = -1; + params->tcp_space = -1; + params->non_tcp_space = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode F_MAX_PERIOD (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_16_bit_field(¶ms->f_max_period, NULL, src, + src_len - byte_counter, 1, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode F_MAX_TIME (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_8_bit_field(¶ms->f_max_time, NULL, src, + src_len - byte_counter, 1, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_8_bit_field(¶ms->max_header, NULL, src, + src_len - byte_counter, 60, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_8_bit_field(¶ms->tcp_space, NULL, src, + src_len - byte_counter, 3, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode NON_TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_16_bit_field(¶ms->non_tcp_space, NULL, src, + src_len - byte_counter, 3, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Decode ROHC parameter field (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ +static int decode_pcomp_rohc_params(struct gprs_sndcp_pcomp_rohc_params *params, + const uint8_t *src, unsigned int src_len) +{ + int rc; + int byte_counter = 0; + int i; + + OSMO_ASSERT(params); + OSMO_ASSERT(src); + + /* Mark all optional parameters invalid by default */ + params->max_cid = -1; + params->max_header = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_CID (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + rc = decode_pcomp_16_bit_field(¶ms->max_cid, NULL, src, + src_len - byte_counter, 0, 16383); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + rc = decode_pcomp_16_bit_field(¶ms->max_header, NULL, src, + src_len - byte_counter, 60, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode Profiles (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + for (i = 0; i < 16; i++) { + params->profile_len = 0; + rc = decode_pcomp_16_bit_field(NULL, ¶ms->profile[i], src, + src_len - byte_counter, 0, + 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + params->profile_len = i + 1; + } + + /* Return consumed length */ + return byte_counter; +} + +/* Decode V.42bis parameter field + * (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ +static int decode_dcomp_v42bis_params(struct gprs_sndcp_dcomp_v42bis_params + *params, const uint8_t *src, + unsigned int src_len) +{ + int rc; + int byte_counter = 0; + + OSMO_ASSERT(params); + OSMO_ASSERT(src); + + /* Mark all optional parameters invalid by default */ + params->p0 = -1; + params->p1 = -1; + params->p2 = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode P0 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + rc = decode_pcomp_8_bit_field(¶ms->p0, NULL, src, + src_len - byte_counter, 0, 3); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + rc = decode_pcomp_16_bit_field(¶ms->p1, NULL, src, + src_len - byte_counter, 512, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P2 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + rc = decode_pcomp_8_bit_field(¶ms->p2, NULL, src, + src_len - byte_counter, 6, 250); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Decode V44 parameter field (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ +static int decode_dcomp_v44_params(struct gprs_sndcp_dcomp_v44_params *params, + const uint8_t *src, unsigned int src_len) +{ + int rc; + int byte_counter = 0; + + OSMO_ASSERT(params); + OSMO_ASSERT(src); + + /* Mark all optional parameters invalid by default */ + params->c0 = -1; + params->p0 = -1; + params->p1t = -1; + params->p1r = -1; + params->p3t = -1; + params->p3r = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode C0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_8_bit_field(¶ms->c0, NULL, src, + src_len - byte_counter, 0, 255); + if (rc <= 0) + return byte_counter; + if ((params->c0 != 0x80) && (params->c0 != 0xC0)) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Decode P0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_8_bit_field(¶ms->p0, NULL, src, + src_len - byte_counter, 0, 3); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_16_bit_field(¶ms->p1t, NULL, src, + src_len - byte_counter, 265, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_16_bit_field(¶ms->p1r, NULL, src, + src_len - byte_counter, 265, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P3T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_16_bit_field(¶ms->p3t, NULL, src, + src_len - byte_counter, 265, 65535); + if (rc <= 0) + return byte_counter; + if (params->p3t < 2 * params->p1t) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Decode P3R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_16_bit_field(¶ms->p3r, NULL, src, + src_len - byte_counter, 265, 65535); + if (rc <= 0) + return byte_counter; + if (params->p3r < 2 * params->p1r) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Lookup algorithm identfier by entity ID */ +static int lookup_algorithm_identifier(int entity, const struct + entity_algo_table + *lt, unsigned int lt_len, int compclass) +{ + int i; + + if (!lt) + return -1; + + for (i = 0; i < lt_len; i++) { + if ((lt[i].entity == entity) + && (lt[i].compclass == compclass)) + return lt[i].algo; + } + + return -1; +} + +/* Helper function for decode_comp_field(), decodes + * numeric pcomp/dcomp values */ +static int decode_comp_values(struct gprs_sndcp_comp_field *comp_field, + const uint8_t *src, int compclass) +{ + int src_counter = 0; + int i; + + OSMO_ASSERT(comp_field); + OSMO_ASSERT(src); + + if (comp_field->p) { + /* Determine the number of expected PCOMP/DCOMP values */ + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + /* For protocol compression */ + switch (comp_field->algo) { + case RFC_1144: + comp_field->comp_len = RFC1144_PCOMP_NUM; + break; + case RFC_2507: + comp_field->comp_len = RFC2507_PCOMP_NUM; + break; + case ROHC: + comp_field->comp_len = ROHC_PCOMP_NUM; + break; + + /* Exit if the algorithem type encodes + something unknown / unspecified */ + default: + return -EINVAL; + } + } else { + /* For data compression */ + switch (comp_field->algo) { + case V42BIS: + comp_field->comp_len = V42BIS_DCOMP_NUM; + break; + case V44: + comp_field->comp_len = V44_DCOMP_NUM; + break; + + /* Exit if the algorithem type encodes + something unknown / unspecified */ + default: + return -EINVAL; + } + } + + for (i = 0; i < comp_field->comp_len; i++) { + if (i & 1) { + comp_field->comp[i] = (*src) & 0x0F; + src++; + src_counter++; + } else + comp_field->comp[i] = ((*src) >> 4) & 0x0F; + } + + if (i & 1) { + src++; + src_counter++; + } + } + + return src_counter; +} + +/* Helper function for decode_comp_field(), decodes the parameters + * which are protocol compression specific */ +static int decode_pcomp_params(struct gprs_sndcp_comp_field *comp_field, + const uint8_t *src, int src_len) +{ + int rc; + + OSMO_ASSERT(comp_field); + OSMO_ASSERT(src); + + switch (comp_field->algo) { + case RFC_1144: + comp_field->rfc1144_params = talloc_zero(comp_field, struct + gprs_sndcp_pcomp_rfc1144_params); + rc = decode_pcomp_rfc1144_params(comp_field->rfc1144_params, + src, src_len); + if (rc < 0) + talloc_free(comp_field->rfc1144_params); + break; + case RFC_2507: + comp_field->rfc2507_params = talloc_zero(comp_field, struct + gprs_sndcp_pcomp_rfc2507_params); + rc = decode_pcomp_rfc2507_params(comp_field->rfc2507_params, + src, src_len); + if (rc < 0) + talloc_free(comp_field->rfc1144_params); + break; + case ROHC: + comp_field->rohc_params = talloc_zero(comp_field, struct + gprs_sndcp_pcomp_rohc_params); + rc = decode_pcomp_rohc_params(comp_field->rohc_params, src, + src_len); + if (rc < 0) + talloc_free(comp_field->rohc_params); + break; + + /* If no suitable decoder is detected, + leave the remaining bytes undecoded */ + default: + rc = src_len; + } + + if (rc < 0) { + comp_field->rfc1144_params = NULL; + comp_field->rfc2507_params = NULL; + comp_field->rohc_params = NULL; + } + + return rc; +} + +/* Helper function for decode_comp_field(), decodes the parameters + * which are data compression specific */ +static int decode_dcomp_params(struct gprs_sndcp_comp_field *comp_field, + const uint8_t *src, int src_len) +{ + int rc; + + OSMO_ASSERT(comp_field); + OSMO_ASSERT(src); + + switch (comp_field->algo) { + case V42BIS: + comp_field->v42bis_params = talloc_zero(comp_field, struct + gprs_sndcp_dcomp_v42bis_params); + rc = decode_dcomp_v42bis_params(comp_field->v42bis_params, src, + src_len); + if (rc < 0) + talloc_free(comp_field->v42bis_params); + break; + case V44: + comp_field->v44_params = talloc_zero(comp_field, struct + gprs_sndcp_dcomp_v44_params); + rc = decode_dcomp_v44_params(comp_field->v44_params, src, + src_len); + if (rc < 0) + talloc_free(comp_field->v44_params); + break; + + /* If no suitable decoder is detected, + * leave the remaining bytes undecoded */ + default: + rc = src_len; + } + + if (rc < 0) { + comp_field->v42bis_params = NULL; + comp_field->v44_params = NULL; + } + + return rc; +} + +/* Decode data or protocol control information compression field + * (see also: 3GPP TS 44.065, 6.6.1.1, Figure 9 and + * 3GPP TS 44.065, 6.5.1.1, Figure 7) */ +static int decode_comp_field(struct gprs_sndcp_comp_field *comp_field, + const uint8_t *src, unsigned int src_len, + const struct entity_algo_table *lt, + unsigned int lt_len, int compclass) +{ + int src_counter = 0; + unsigned int len; + int rc; + + OSMO_ASSERT(comp_field); + + /* Exit immediately if it is clear that no + parseable data is present */ + if (src_len < 1 || !src) + return -EINVAL; + + /* Zero out target struct */ + memset(comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + + /* Decode Propose bit and Entity number */ + if ((*src) & 0x80) + comp_field->p = 1; + comp_field->entity = (*src) & 0x1F; + src_counter++; + src++; + + /* Decode algorithm number (if present) */ + if (comp_field->p) { + comp_field->algo = (*src) & 0x1F; + src_counter++; + src++; + } + /* Alternatively take the information from the lookup table */ + else + comp_field->algo = + lookup_algorithm_identifier(comp_field->entity, lt, + lt_len, compclass); + + /* Decode length field */ + len = *src; + src_counter++; + src++; + + /* Decode PCOMP/DCOMP values */ + rc = decode_comp_values(comp_field, src, compclass); + if (rc < 0) + return -EINVAL; + src_counter += rc; + src += rc; + len -= rc; + + /* Decode algorithm specific payload data */ + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + rc = decode_pcomp_params(comp_field, src, len); + else if (compclass == SNDCP_XID_DATA_COMPRESSION) + rc = decode_dcomp_params(comp_field, src, len); + else + return -EINVAL; + + if (rc >= 0) + src_counter += rc; + else + return -EINVAL; + + /* Return consumed length */ + return src_counter; +} + +/* Helper function for gprs_sndcp_decode_xid() to decode XID blocks */ +static int decode_xid_block(struct llist_head *comp_fields, uint8_t tag, + uint16_t tag_len, const uint8_t *val, + const struct entity_algo_table *lt, + unsigned int lt_len) +{ + struct gprs_sndcp_comp_field *comp_field; + int byte_counter = 0; + int comp_field_count = 0; + int rc; + + OSMO_ASSERT(comp_fields); + OSMO_ASSERT(val); + + byte_counter = 0; + do { + /* Bail if more than the maximum number of + comp_fields is generated */ + if (comp_field_count > MAX_ENTITIES * 2) { + return -EINVAL; + } + + /* Parse and add comp_field */ + comp_field = + talloc_zero(comp_fields, struct gprs_sndcp_comp_field); + + rc = decode_comp_field(comp_field, val + byte_counter, + tag_len - byte_counter, lt, lt_len, tag); + + if (rc < 0) { + talloc_free(comp_field); + return -EINVAL; + } + + byte_counter += rc; + llist_add(&comp_field->list, comp_fields); + comp_field_count++; + } + while (tag_len - byte_counter > 0); + + return byte_counter; +} + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +static int gprs_sndcp_decode_xid(struct llist_head *comp_fields, + const uint8_t *src, unsigned int src_len, + const struct + entity_algo_table + *lt, unsigned int lt_len) +{ + int src_pos = 0; + uint8_t tag; + uint16_t tag_len; + const uint8_t *val; + int byte_counter = 0; + int rc; + int tlv_count = 0; + + OSMO_ASSERT(comp_fields); + OSMO_ASSERT(src); + + /* Valid TLV-Tag and types */ + static const struct tlv_definition sndcp_xid_def = { + .def = { + [SNDCP_XID_VERSION_NUMBER] = {TLV_TYPE_TLV,}, + [SNDCP_XID_DATA_COMPRESSION] = {TLV_TYPE_TLV,}, + [SNDCP_XID_PROTOCOL_COMPRESSION] = {TLV_TYPE_TLV,}, + }, + }; + + /* Parse TLV-Encoded SNDCP-XID message and defer payload + to the apporpiate sub-parser functions */ + while (1) { + + /* Bail if an the maximum number of TLV fields + * have been parsed */ + if (tlv_count >= 3) { + gprs_sndcp_free_comp_fields(comp_fields); + return -EINVAL; + } + + /* Parse TLV field */ + rc = tlv_parse_one(&tag, &tag_len, &val, &sndcp_xid_def, + src + src_pos, src_len - src_pos); + if (rc > 0) + src_pos += rc; + else { + gprs_sndcp_free_comp_fields(comp_fields); + return -EINVAL; + } + + /* Decode compression parameters */ + if ((tag == SNDCP_XID_PROTOCOL_COMPRESSION) + || (tag == SNDCP_XID_DATA_COMPRESSION)) { + rc = decode_xid_block(comp_fields, tag, tag_len, val, + lt, lt_len); + + if (rc < 0) { + gprs_sndcp_free_comp_fields(comp_fields); + return -EINVAL; + } else + byte_counter += rc; + } + + /* Stop when no further TLV elements can be expected */ + if (src_len - src_pos <= 2) + break; + + tlv_count++; + } + + return 0; +} + +/* Fill up lookutable from a list with comression entitiy fields */ +static int gprs_sndcp_fill_table(struct + entity_algo_table *lt, + unsigned int lt_len, + const struct llist_head *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field; + int i = 0; + + OSMO_ASSERT(lt); + OSMO_ASSERT(comp_fields); + + if (!comp_fields) + return -EINVAL; + if (!lt) + return -EINVAL; + + memset(lt, 0, lt_len * sizeof(lt)); + + llist_for_each_entry(comp_field, comp_fields, list) { + + lt[i].entity = comp_field->entity; + lt[i].algo = comp_field->algo; + lt[i].compclass = gprs_sndcp_get_compression_class(comp_field); + + if (lt[i].compclass < 0) { + memset(lt, 0, lt_len * sizeof(lt)); + return -EINVAL; + } + + i++; + } + + return i; +} + +/* Complete comp field params + * (if a param (dst) is not valid, it will be copied from source (src) */ +static int complete_comp_field_params(struct gprs_sndcp_comp_field + *comp_field_dst, const struct + gprs_sndcp_comp_field *comp_field_src) +{ + OSMO_ASSERT(comp_field_dst); + OSMO_ASSERT(comp_field_src); + + if (comp_field_dst->algo < 0) + return -EINVAL; + + if (comp_field_dst->rfc1144_params && comp_field_src->rfc1144_params) { + if (comp_field_dst->rfc1144_params->s01 < 0) { + comp_field_dst->rfc1144_params->s01 = + comp_field_src->rfc1144_params->s01; + } + return 0; + } + + if (comp_field_dst->rfc2507_params && comp_field_src->rfc2507_params) { + + if (comp_field_dst->rfc2507_params->f_max_period < 0) { + comp_field_dst->rfc2507_params->f_max_period = + comp_field_src->rfc2507_params->f_max_period; + } + if (comp_field_dst->rfc2507_params->f_max_time < 0) { + comp_field_dst->rfc2507_params->f_max_time = + comp_field_src->rfc2507_params->f_max_time; + } + if (comp_field_dst->rfc2507_params->max_header < 0) { + comp_field_dst->rfc2507_params->max_header = + comp_field_src->rfc2507_params->max_header; + } + if (comp_field_dst->rfc2507_params->tcp_space < 0) { + comp_field_dst->rfc2507_params->tcp_space = + comp_field_src->rfc2507_params->tcp_space; + } + if (comp_field_dst->rfc2507_params->non_tcp_space < 0) { + comp_field_dst->rfc2507_params->non_tcp_space = + comp_field_src->rfc2507_params->non_tcp_space; + } + return 0; + } + + if (comp_field_dst->rohc_params && comp_field_src->rohc_params) { + if (comp_field_dst->rohc_params->max_cid < 0) { + comp_field_dst->rohc_params->max_cid = + comp_field_src->rohc_params->max_cid; + } + if (comp_field_dst->rohc_params->max_header < 0) { + comp_field_dst->rohc_params->max_header = + comp_field_src->rohc_params->max_header; + } + if (comp_field_dst->rohc_params->profile_len > 0) { + memcpy(comp_field_dst->rohc_params->profile, + comp_field_src->rohc_params->profile, + sizeof(comp_field_dst->rohc_params->profile)); + comp_field_dst->rohc_params->profile_len = + comp_field_src->rohc_params->profile_len; + } + + return 0; + } + + if (comp_field_dst->v42bis_params && comp_field_src->v42bis_params) { + if (comp_field_dst->v42bis_params->p0 < 0) { + comp_field_dst->v42bis_params->p0 = + comp_field_src->v42bis_params->p0; + } + if (comp_field_dst->v42bis_params->p1 < 0) { + comp_field_dst->v42bis_params->p1 = + comp_field_src->v42bis_params->p1; + } + if (comp_field_dst->v42bis_params->p2 < 0) { + comp_field_dst->v42bis_params->p2 = + comp_field_src->v42bis_params->p2; + } + return 0; + } + + if (comp_field_dst->v44_params && comp_field_src->v44_params) { + if (comp_field_dst->v44_params->c0 < 0) { + comp_field_dst->v44_params->c0 = + comp_field_src->v44_params->c0; + } + if (comp_field_dst->v44_params->p0 < 0) { + comp_field_dst->v44_params->p0 = + comp_field_src->v44_params->p0; + } + if (comp_field_dst->v44_params->p1t < 0) { + comp_field_dst->v44_params->p1t = + comp_field_src->v44_params->p1t; + } + if (comp_field_dst->v44_params->p1r < 0) { + comp_field_dst->v44_params->p1r = + comp_field_src->v44_params->p1r; + } + if (comp_field_dst->v44_params->p3t < 0) { + comp_field_dst->v44_params->p3t = + comp_field_src->v44_params->p3t; + } + if (comp_field_dst->v44_params->p3r < 0) { + comp_field_dst->v44_params->p3r = + comp_field_src->v44_params->p3r; + } + return 0; + } + + /* There should be at least exist one param set + * in the destination struct, otherwise something + * must be wrong! */ + return -EINVAL; +} + +/* Complete missing parameters in a comp_field */ +static int gprs_sndcp_complete_comp_field(struct gprs_sndcp_comp_field + *comp_field, const struct llist_head + *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field_src; + int rc = 0; + + OSMO_ASSERT(comp_field); + OSMO_ASSERT(comp_fields); + + llist_for_each_entry(comp_field_src, comp_fields, list) { + if (comp_field_src->entity == comp_field->entity) { + + /* Complete header fields */ + if (comp_field_src->comp_len > 0) { + memcpy(comp_field->comp, + comp_field_src->comp, + sizeof(comp_field_src->comp)); + comp_field->comp_len = comp_field_src->comp_len; + } + + /* Complete parameter fields */ + rc = complete_comp_field_params(comp_field, + comp_field_src); + } + } + + return rc; +} + +/* Complete missing parameters of all comp_field in a list */ +static int gprs_sndcp_complete_comp_fields(struct llist_head + *comp_fields_incomplete, + const struct llist_head *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field_incomplete; + int rc; + + OSMO_ASSERT(comp_fields_incomplete); + OSMO_ASSERT(comp_fields); + + llist_for_each_entry(comp_field_incomplete, comp_fields_incomplete, + list) { + + rc = gprs_sndcp_complete_comp_field(comp_field_incomplete, + comp_fields); + if (rc < 0) + return -EINVAL; + + } + + return 0; +} + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +struct llist_head *gprs_sndcp_parse_xid(const void *ctx, + const uint8_t *src, + unsigned int src_len, + const struct llist_head + *comp_fields_req) +{ + int rc; + int lt_len; + struct llist_head *comp_fields; + struct entity_algo_table lt[MAX_ENTITIES * 2]; + + OSMO_ASSERT(src); + + comp_fields = talloc_zero(ctx, struct llist_head); + INIT_LLIST_HEAD(comp_fields); + + if (comp_fields_req) { + /* Generate lookup table */ + lt_len = + gprs_sndcp_fill_table(lt, MAX_ENTITIES * 2, + comp_fields_req); + if (lt_len < 0) + return gprs_sndcp_free_comp_fields(comp_fields); + + /* Parse SNDCP-CID XID-Field */ + rc = gprs_sndcp_decode_xid(comp_fields, src, src_len, lt, + lt_len); + if (rc < 0) + return gprs_sndcp_free_comp_fields(comp_fields); + + rc = gprs_sndcp_complete_comp_fields(comp_fields, + comp_fields_req); + if (rc < 0) + return gprs_sndcp_free_comp_fields(comp_fields); + + } else { + /* Parse SNDCP-CID XID-Field */ + rc = gprs_sndcp_decode_xid(comp_fields, src, src_len, NULL, 0); + if (rc < 0) + return gprs_sndcp_free_comp_fields(comp_fields); + } + + return comp_fields; +} + +/* Free a list with SNDCP-XID fields */ +struct llist_head *gprs_sndcp_free_comp_fields(struct llist_head *comp_fields) +{ + if (comp_fields != NULL) + talloc_free(comp_fields); + return NULL; +} + +/* Helper for gprs_sndcp_dump_comp_fields(), + * dumps protocol compression parameters */ +static void dump_pcomp_params(const struct gprs_sndcp_comp_field + *comp_field, unsigned int logl) +{ + int i; + + OSMO_ASSERT(comp_field); + + switch (comp_field->algo) { + case RFC_1144: + if (comp_field->rfc1144_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_pcomp_rfc1144_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_pcomp_rfc1144_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%i;\n", + comp_field->rfc1144_params->nsapi_len); + if (comp_field->rfc1144_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rfc1144_params->nsapi_len; i++) { + LOGP(DSNDCP, logl, + " nsapi[%i]=%i;\n", i, + comp_field->rfc1144_params->nsapi[i]); + } + LOGP(DSNDCP, logl, " s01=%i;\n", + comp_field->rfc1144_params->s01); + LOGP(DSNDCP, logl, " }\n"); + break; + case RFC_2507: + if (comp_field->rfc2507_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_pcomp_rfc2507_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_pcomp_rfc2507_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%i;\n", + comp_field->rfc2507_params->nsapi_len); + if (comp_field->rfc2507_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rfc2507_params->nsapi_len; i++) { + LOGP(DSNDCP, logl, + " nsapi[%i]=%i;\n", i, + comp_field->rfc2507_params->nsapi[i]); + } + LOGP(DSNDCP, logl, + " f_max_period=%i;\n", + comp_field->rfc2507_params->f_max_period); + LOGP(DSNDCP, logl, + " f_max_time=%i;\n", + comp_field->rfc2507_params->f_max_time); + LOGP(DSNDCP, logl, + " max_header=%i;\n", + comp_field->rfc2507_params->max_header); + LOGP(DSNDCP, logl, + " tcp_space=%i;\n", + comp_field->rfc2507_params->tcp_space); + LOGP(DSNDCP, logl, + " non_tcp_space=%i;\n", + comp_field->rfc2507_params->non_tcp_space); + LOGP(DSNDCP, logl, " }\n"); + break; + case ROHC: + if (comp_field->rohc_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_pcomp_rohc_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_pcomp_rohc_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%i;\n", + comp_field->rohc_params->nsapi_len); + if (comp_field->rohc_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rohc_params->nsapi_len; i++) { + LOGP(DSNDCP, logl, + " nsapi[%i]=%i;\n", i, + comp_field->rohc_params->nsapi[i]); + } + LOGP(DSNDCP, logl, + " max_cid=%i;\n", comp_field->rohc_params->max_cid); + LOGP(DSNDCP, logl, + " max_header=%i;\n", + comp_field->rohc_params->max_header); + LOGP(DSNDCP, logl, + " profile_len=%i;\n", + comp_field->rohc_params->profile_len); + if (comp_field->rohc_params->profile_len == 0) + LOGP(DSNDCP, logl, " profile[] = NULL;\n"); + for (i = 0; i < comp_field->rohc_params->profile_len; i++) + LOGP(DSNDCP, logl, + " profile[%i]=%04x;\n", + i, comp_field->rohc_params->profile[i]); + LOGP(DSNDCP, logl, " }\n"); + break; + } + +} + +/* Helper for gprs_sndcp_dump_comp_fields(), + * data protocol compression parameters */ +static void dump_dcomp_params(const struct gprs_sndcp_comp_field + *comp_field, unsigned int logl) +{ + int i; + + OSMO_ASSERT(comp_field); + + switch (comp_field->algo) { + case V42BIS: + if (comp_field->v42bis_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_dcomp_v42bis_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_dcomp_v42bis_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%i;\n", + comp_field->v42bis_params->nsapi_len); + if (comp_field->v42bis_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->v42bis_params->nsapi_len; i++) + LOGP(DSNDCP, logl, + " nsapi[%i]=%i;\n", i, + comp_field->v42bis_params->nsapi[i]); + LOGP(DSNDCP, logl, " p0=%i;\n", + comp_field->v42bis_params->p0); + LOGP(DSNDCP, logl, " p1=%i;\n", + comp_field->v42bis_params->p1); + LOGP(DSNDCP, logl, " p2=%i;\n", + comp_field->v42bis_params->p2); + LOGP(DSNDCP, logl, " }\n"); + break; + case V44: + if (comp_field->v44_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_dcomp_v44_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_dcomp_v44_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%i;\n", + comp_field->v44_params->nsapi_len); + if (comp_field->v44_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->v44_params->nsapi_len; i++) { + LOGP(DSNDCP, logl, + " nsapi[%i]=%i;\n", i, + comp_field->v44_params->nsapi[i]); + } + LOGP(DSNDCP, logl, " c0=%i;\n", + comp_field->v44_params->c0); + LOGP(DSNDCP, logl, " p0=%i;\n", + comp_field->v44_params->p0); + LOGP(DSNDCP, logl, " p1t=%i;\n", + comp_field->v44_params->p1t); + LOGP(DSNDCP, logl, " p1r=%i;\n", + comp_field->v44_params->p1r); + LOGP(DSNDCP, logl, " p3t=%i;\n", + comp_field->v44_params->p3t); + LOGP(DSNDCP, logl, " p3r=%i;\n", + comp_field->v44_params->p3r); + LOGP(DSNDCP, logl, " }\n"); + break; + } +} + +/* Dump a list with SNDCP-XID fields (Debug) */ +void gprs_sndcp_dump_comp_fields(const struct llist_head *comp_fields, + unsigned int logl) +{ + struct gprs_sndcp_comp_field *comp_field; + int i; + int compclass; + + OSMO_ASSERT(comp_fields); + + llist_for_each_entry(comp_field, comp_fields, list) { + LOGP(DSNDCP, logl, "SNDCP-XID:\n"); + LOGP(DSNDCP, logl, "struct gprs_sndcp_comp_field {\n"); + LOGP(DSNDCP, logl, " entity=%i;\n", comp_field->entity); + LOGP(DSNDCP, logl, " algo=%i;\n", comp_field->algo); + LOGP(DSNDCP, logl, " comp_len=%i;\n", comp_field->comp_len); + if (comp_field->comp_len == 0) + LOGP(DSNDCP, logl, " comp[] = NULL;\n"); + for (i = 0; i < comp_field->comp_len; i++) { + LOGP(DSNDCP, logl, " comp[%i]=%i;\n", i, + comp_field->comp[i]); + } + + compclass = gprs_sndcp_get_compression_class(comp_field); + + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + dump_pcomp_params(comp_field, logl); + } else if (compclass == SNDCP_XID_DATA_COMPRESSION) { + dump_dcomp_params(comp_field, logl); + } + + LOGP(DSNDCP, logl, "}\n"); + } + +} diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index ba5ca28..071166b 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid xid_sndcp if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 74af159..45d1780 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -31,6 +31,7 @@ $(top_builddir)/src/gprs/oap.o \ $(top_builddir)/src/gprs/oap_messages.o \ $(top_builddir)/src/gprs/gprs_llc_xid.o \ + $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ @@ -38,5 +39,5 @@ $(LIBOSMOGB_LIBS) \ $(LIBCARES_LIBS) \ $(LIBCRYPTO_LIBS) \ - -lgtp -lrt + -lgtp -lrt -lm diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index 6470ab9..22b3db9 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -129,3 +129,10 @@ cat $abs_srcdir/xid/xid_test.ok > expout AT_CHECK([$abs_top_builddir/tests/xid/xid_test], [], [expout], [ignore]) AT_CLEANUP + +AT_SETUP([xid_sndcp]) +AT_KEYWORDS([xid_sndcp]) +cat $abs_srcdir/xid_sndcp/sndcp_xid_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/xid_sndcp/sndcp_xid_test], [], [expout], [ignore]) +AT_CLEANUP + diff --git a/openbsc/tests/xid_sndcp/Makefile.am b/openbsc/tests/xid_sndcp/Makefile.am new file mode 100644 index 0000000..99b9d1a --- /dev/null +++ b/openbsc/tests/xid_sndcp/Makefile.am @@ -0,0 +1,20 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) + +EXTRA_DIST = sndcp_xid_test.ok + +noinst_PROGRAMS = sndcp_xid_test + +sndcp_xid_test_SOURCES = sndcp_xid_test.c + +sndcp_xid_test_LDADD = \ + $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOGB_LIBS) \ + $(LIBCARES_LIBS) \ + $(LIBCRYPTO_LIBS) \ + -lgtp -lrt -lm + + diff --git a/openbsc/tests/xid_sndcp/sndcp_xid_test.c b/openbsc/tests/xid_sndcp/sndcp_xid_test.c new file mode 100644 index 0000000..59ff968 --- /dev/null +++ b/openbsc/tests/xid_sndcp/sndcp_xid_test.c @@ -0,0 +1,283 @@ +/* Test SNDCP-XID Encoding/Decoding */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include + +#include +#include + +#include + +#include +#include + +/* Test SNDCP-XID decoding with a real world sample */ +static void test_xid_decode_realworld(const void *ctx) +{ + struct llist_head *comp_fields; + int rc; + printf("Testing SNDCP XID-Decoder/Encoder (real world data)\n"); + + /* Example of a real world SNDCP-XID message */ + uint8_t xid[] = + { 0x00, 0x01, 0x00, 0x02, 0x31, 0x82, 0x02, 0x27, 0x89, 0xff, 0xe0, + 0x00, 0x0f, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, + 0x01, 0x02, 0x00, 0x03, 0x01, 0x03, 0x00, 0x04, 0x01, 0x04, 0x00, 0x05, + 0x01, 0x05, 0x00, 0x06, 0x00, 0x07, 0x01, 0x07, 0x00, 0x08, 0x01, 0x08, + 0x80, 0x00, 0x04, 0x12, 0x00, 0x40, 0x07 }; + uint8_t xid_r[512]; + + /* Parse and show contained comp fields */ + comp_fields = gprs_sndcp_parse_xid(ctx, xid, sizeof(xid), NULL); + OSMO_ASSERT(comp_fields); + printf("Decoded:\n"); + gprs_sndcp_dump_comp_fields(comp_fields, DSNDCP); + + /* Encode comp-fields again */ + rc = gprs_sndcp_compile_xid(xid_r,sizeof(xid_r), comp_fields); + printf("Result length=%i\n",rc); + printf("Encoded: %s\n", osmo_hexdump_nospc(xid, sizeof(xid))); + printf("Rencoded: %s\n", osmo_hexdump_nospc(xid_r, rc)); + + OSMO_ASSERT(rc == 54); + OSMO_ASSERT(memcmp(xid, xid_r, sizeof(xid)) == 0); + + /* Free comp fields */ + gprs_sndcp_free_comp_fields(comp_fields); + + printf("\n"); +} + +/* Encode and decode test with artificial test data */ +static void test_xid_encode_decode(const void *ctx) +{ + printf("Testing SNDCP XID-Encoder/Decoder\n"); + + LLIST_HEAD(comp_fields); + struct gprs_sndcp_pcomp_rfc1144_params rfc1144_params; + struct gprs_sndcp_comp_field rfc1144_comp_field; + struct gprs_sndcp_pcomp_rfc2507_params rfc2507_params; + struct gprs_sndcp_comp_field rfc2507_comp_field; + struct gprs_sndcp_pcomp_rohc_params rohc_params; + struct gprs_sndcp_comp_field rohc_comp_field; + struct gprs_sndcp_dcomp_v42bis_params v42bis_params; + struct gprs_sndcp_comp_field v42bis_comp_field; + struct gprs_sndcp_dcomp_v44_params v44_params; + struct gprs_sndcp_comp_field v44_comp_field; + struct llist_head *comp_fields_dec; + + uint8_t xid[512]; + unsigned int xid_len = sizeof(xid); + int rc; + + memset(&rfc1144_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + memset(&rfc2507_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + memset(&rohc_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + memset(&v42bis_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + memset(&v44_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + + /* Setup which NSAPIs shall make use of rfc1144 */ + rfc1144_params.nsapi[0] = 5; + rfc1144_params.nsapi_len = 1; + + /* Setup rfc1144 operating parameters */ + rfc1144_params.s01 = 7; + + /* Setup rfc1144 compression field */ + rfc1144_comp_field.p = 1; + rfc1144_comp_field.entity = 0; + rfc1144_comp_field.algo = RFC_1144; + rfc1144_comp_field.comp[RFC1144_PCOMP1] = 1; + rfc1144_comp_field.comp[RFC1144_PCOMP2] = 2; + rfc1144_comp_field.comp_len = RFC1144_PCOMP_NUM; + rfc1144_comp_field.rfc1144_params = &rfc1144_params; + + /* Setup which NSAPIs shall make use of rfc1144 */ + rfc2507_params.nsapi[0] = 6; + rfc2507_params.nsapi_len = 1; + + /* Setup rfc2507 operating parameters */ + rfc2507_params.f_max_period = 256; + rfc2507_params.f_max_time = 5; + rfc2507_params.max_header = 168; + rfc2507_params.tcp_space = 15; + rfc2507_params.non_tcp_space = 15; + + /* Setup rfc2507 compression field */ + rfc2507_comp_field.p = 1; + rfc2507_comp_field.entity = 1; + rfc2507_comp_field.algo = RFC_2507; + rfc2507_comp_field.comp[RFC2507_PCOMP1] = 3; + rfc2507_comp_field.comp[RFC2507_PCOMP2] = 4; + rfc2507_comp_field.comp[RFC2507_PCOMP3] = 5; + rfc2507_comp_field.comp[RFC2507_PCOMP4] = 6; + rfc2507_comp_field.comp[RFC2507_PCOMP5] = 7; + rfc2507_comp_field.comp_len = RFC2507_PCOMP_NUM; + rfc2507_comp_field.rfc2507_params = &rfc2507_params; + + /* Setup which NSAPIs shall make use of ROHC */ + rohc_params.nsapi[0] = 5; + rohc_params.nsapi[1] = 6; + rohc_params.nsapi[2] = 7; + rohc_params.nsapi[3] = 8; + rohc_params.nsapi[4] = 9; + rohc_params.nsapi[5] = 10; + rohc_params.nsapi[6] = 11; + rohc_params.nsapi[7] = 12; + rohc_params.nsapi[8] = 13; + rohc_params.nsapi[9] = 14; + rohc_params.nsapi[10] = 15; + rohc_params.nsapi_len = 11; + + /* Setup ROHC operating parameters */ + rohc_params.max_cid = 15; /* default */ + rohc_params.max_header = 168; /* default */ + rohc_params.profile[0] = ROHC_UNCOMPRESSED; + rohc_params.profile[1] = ROHC_RTP; + rohc_params.profile[2] = ROHCV2_RTP; + rohc_params.profile[3] = ROHC_UDP; + rohc_params.profile[4] = ROHCv2_UDP; + rohc_params.profile[5] = ROHC_ESP; + rohc_params.profile[6] = ROHCV2_ESP; + rohc_params.profile[7] = ROHC_IP; + rohc_params.profile[8] = ROHCV2_IP; + rohc_params.profile[9] = ROHC_LLA; + rohc_params.profile[10] = ROHC_LLA_WITH_R_MODE; + rohc_params.profile[11] = ROHC_TCP; + rohc_params.profile[12] = ROHC_RTP_UDP_LITE; + rohc_params.profile[13] = ROHCV2_RTP_UDP_LITE; + rohc_params.profile[14] = ROHC_UDP_LITE; + rohc_params.profile[15] = ROHCV2_UDP_LITE; + rohc_params.profile_len = 16; + + /* Setup ROHC compression field */ + rohc_comp_field.p = 1; + rohc_comp_field.entity = 2; + rohc_comp_field.algo = ROHC; + rohc_comp_field.comp[ROHC_PCOMP1] = 8; + rohc_comp_field.comp[ROHC_PCOMP2] = 9; + rohc_comp_field.comp_len = ROHC_PCOMP_NUM; + rohc_comp_field.rohc_params = &rohc_params; + + /* Setup which NSAPIs shall make use of v42bis */ + v42bis_params.nsapi[0] = 5; + v42bis_params.nsapi_len = 1; + + /* Setup v42bis operating parameters */ + v42bis_params.p0 = 3; + v42bis_params.p1 = 2048; + v42bis_params.p2 = 20; + + /* Setup v42bis compression field */ + v42bis_comp_field.p = 1; + v42bis_comp_field.entity = 3; + v42bis_comp_field.algo = V42BIS; + v42bis_comp_field.comp[V42BIS_DCOMP1] = 10; + v42bis_comp_field.comp_len = V42BIS_DCOMP_NUM; + v42bis_comp_field.v42bis_params = &v42bis_params; + + /* Setup which NSAPIs shall make use of v44 */ + v44_params.nsapi[0] = 5; + v44_params.nsapi_len = 1; + + /* Setup v44 operating parameters */ + v44_params.c0 = 0x80; + v44_params.p0 = 3; + v44_params.p1t = 300; + v44_params.p1r = 300; + v44_params.p3t = 600; + v44_params.p3r = 600; + + /* Setup v44 compression field */ + v44_comp_field.p = 1; + v44_comp_field.entity = 3; + v44_comp_field.algo = V44; + v44_comp_field.comp[V44_DCOMP1] = 10; + v44_comp_field.comp[V44_DCOMP2] = 11; + v44_comp_field.comp_len = V44_DCOMP_NUM; + v44_comp_field.v44_params = &v44_params; + + /* Add compression field(s) to list */ + llist_add(&v44_comp_field.list, &comp_fields); + llist_add(&v42bis_comp_field.list, &comp_fields); + llist_add(&rfc1144_comp_field.list, &comp_fields); + llist_add(&rfc2507_comp_field.list, &comp_fields); + llist_add(&rohc_comp_field.list, &comp_fields); + printf("Test input data:\n"); + gprs_sndcp_dump_comp_fields(&comp_fields, DSNDCP); + + /* Encode SNDCP-XID fields */ + rc = gprs_sndcp_compile_xid(xid, xid_len, &comp_fields); + OSMO_ASSERT(rc > 0); + + printf("Encoded: %s (%i bytes)\n", osmo_hexdump_nospc(xid, rc), rc); + + /* Parse and show contained comp fields */ + comp_fields_dec = gprs_sndcp_parse_xid(ctx, xid, rc, NULL); + OSMO_ASSERT(comp_fields_dec); + + printf("Decoded:\n"); + gprs_sndcp_dump_comp_fields(comp_fields_dec, DSNDCP); + + /* Free comp fields */ + gprs_sndcp_free_comp_fields(comp_fields_dec); +} + +static struct log_info_cat gprs_categories[] = { + [DSNDCP] = { + .name = "DSNDCP", + .description = + "GPRS Sub-Network Dependent Control Protocol (SNDCP)", + .enabled = 1,.loglevel = LOGL_DEBUG, + } +}; + +static struct log_info info = { + .cat = gprs_categories, + .num_cat = ARRAY_SIZE(gprs_categories), +}; + +int main(int argc, char **argv) +{ + void *xid_ctx; + + osmo_init_logging(&info); + + xid_ctx = talloc_named_const(NULL, 0, "xid_ctx"); + + test_xid_decode_realworld(xid_ctx); + test_xid_encode_decode(xid_ctx); + + printf("Done\n"); + + talloc_report_full(xid_ctx, stderr); + OSMO_ASSERT(talloc_total_blocks(xid_ctx) == 1); + return 0; +} + +/* stubs */ +struct osmo_prim_hdr; +int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) +{ + abort(); +} diff --git a/openbsc/tests/xid_sndcp/sndcp_xid_test.ok b/openbsc/tests/xid_sndcp/sndcp_xid_test.ok new file mode 100644 index 0000000..f357282 --- /dev/null +++ b/openbsc/tests/xid_sndcp/sndcp_xid_test.ok @@ -0,0 +1,11 @@ +Testing SNDCP XID-Decoder/Encoder (real world data) +Decoded: +Result length=54 +Encoded: 000100023182022789ffe0000f00a8000000010101000201020003010300040104000501050006000701070008010880000412004007 +Rencoded: 000100023182022789ffe0000f00a8000000010101000201020003010300040104000501050006000701070008010880000412004007 + +Testing SNDCP XID-Encoder/Decoder +Test input data: +Encoded: 000100011a83010dab00208003012c012c02580258830007a000200308001402408000041200200781010c3456700040010005a80f000f82022789ffe0000f00a80000000101010002010200030103000401040005010500060007010700080108 (97 bytes) +Decoded: +Done -- To view, visit https://gerrit.osmocom.org/641 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e Gerrit-PatchSet: 9 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Thu Aug 11 12:30:41 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Thu, 11 Aug 2016 12:30:41 +0000 Subject: [PATCH] openbsc[master]: V42BIS integration In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/644 to look at the new patch set (#16). V42BIS integration The previously committed SPANDSP v42bis implementation has been edited to function outside the SPANDSP library. Debug printf statements were changed into DEBUGP statements. Als removed the assembely code in top_bit(). Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d --- M openbsc/include/openbsc/debug.h M openbsc/include/openbsc/v42bis.h R openbsc/include/openbsc/v42bis_private.h M openbsc/src/gprs/v42bis.c 4 files changed, 20 insertions(+), 21 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/44/644/16 diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 90ddca5..ca3d4ad 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -37,6 +37,7 @@ DGTPHUB, DRANAP, DSUA, + DV42BIS, Debug_LastEntry, }; diff --git a/openbsc/include/openbsc/v42bis.h b/openbsc/include/openbsc/v42bis.h index f13e5c5..e7592e8 100644 --- a/openbsc/include/openbsc/v42bis.h +++ b/openbsc/include/openbsc/v42bis.h @@ -36,6 +36,8 @@ #if !defined(_SPANDSP_V42BIS_H_) #define _SPANDSP_V42BIS_H_ +#define SPAN_DECLARE(x) x + #define V42BIS_MAX_BITS 12 #define V42BIS_MAX_CODEWORDS 4096 /* 2^V42BIS_MAX_BITS */ #define V42BIS_TABLE_SIZE 5021 /* This should be a prime >(2^V42BIS_MAX_BITS) */ diff --git a/openbsc/include/openbsc/private_v42bis.h b/openbsc/include/openbsc/v42bis_private.h similarity index 100% rename from openbsc/include/openbsc/private_v42bis.h rename to openbsc/include/openbsc/v42bis_private.h diff --git a/openbsc/src/gprs/v42bis.c b/openbsc/src/gprs/v42bis.c index 6d38916..de9c2af 100644 --- a/openbsc/src/gprs/v42bis.c +++ b/openbsc/src/gprs/v42bis.c @@ -31,9 +31,8 @@ /*! \file */ -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif +#define FALSE 0 +#define TRUE 1 #include #include @@ -44,13 +43,10 @@ #include #include -#include "spandsp/telephony.h" -#include "spandsp/logging.h" -#include "spandsp/bit_operations.h" -#include "spandsp/v42bis.h" +#include +#include +#include -#include "spandsp/private/logging.h" -#include "spandsp/private/v42bis.h" /* Fixed parameters from the spec. */ #define V42BIS_N3 8 /* Character size (bits) */ @@ -310,7 +306,7 @@ { if (ss->transparent) { - printf("Going compressed\n"); + DEBUGP(DV42BIS,"Going compressed\n"); /* 7.8.1 Transition to compressed mode */ /* Switch out of transparent now, between codes. We need to send the octet which did not match, just before switching. */ @@ -332,7 +328,7 @@ { if (!ss->transparent) { - printf("Going transparent\n"); + DEBUGP(DV42BIS,"Going transparent\n"); /* 7.8.2 Transition to transparent mode */ /* Switch into transparent now, between codes, and the unmatched octet should go out in transparent mode, just below */ @@ -401,7 +397,7 @@ { if (s->compress.dict[i].parent_code != 0xFFFF) { - printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); + DEBUGP(DV42BIS,"Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); } } return 0; @@ -454,13 +450,13 @@ ss->escaped = FALSE; if (code == V42BIS_ECM) { - printf("Hit V42BIS_ECM\n"); + DEBUGP(DV42BIS,"Hit V42BIS_ECM\n"); ss->transparent = FALSE; code_len = ss->v42bis_parm_c2; } else if (code == V42BIS_EID) { - printf("Hit V42BIS_EID\n"); + DEBUGP(DV42BIS,"Hit V42BIS_EID\n"); ss->output_buf[ss->output_octet_count++] = ss->escape_code - 1; if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) { @@ -470,11 +466,11 @@ } else if (code == V42BIS_RESET) { - printf("Hit V42BIS_RESET\n"); + DEBUGP(DV42BIS,"Hit V42BIS_RESET\n"); } else { - printf("Hit V42BIS_???? - %" PRIu32 "\n", code); + DEBUGP(DV42BIS,"Hit V42BIS_???? - %" PRIu32 "\n", code); } } else if (code == ss->escape_code) @@ -500,17 +496,17 @@ switch (new_code) { case V42BIS_ETM: - printf("Hit V42BIS_ETM\n"); + DEBUGP(DV42BIS,"Hit V42BIS_ETM\n"); ss->transparent = TRUE; code_len = 8; break; case V42BIS_FLUSH: - printf("Hit V42BIS_FLUSH\n"); + DEBUGP(DV42BIS,"Hit V42BIS_FLUSH\n"); v42bis_decompress_flush(s); break; case V42BIS_STEPUP: /* We need to increase the codeword size */ - printf("Hit V42BIS_STEPUP\n"); + DEBUGP(DV42BIS,"Hit V42BIS_STEPUP\n"); if (ss->v42bis_parm_c3 >= s->v42bis_parm_n2) { /* Invalid condition */ @@ -547,7 +543,7 @@ /* Trace back through the octets which form the string, and output them. */ while (code >= V42BIS_N5) { -if (code > 4095) {printf("Code is 0x%" PRIu32 "\n", code); exit(2);} +if (code > 4095) {DEBUGP(DV42BIS,"Code is 0x%" PRIu32 "\n", code); exit(2);} *string-- = ss->dict[code].node_octet; code = ss->dict[code].parent_code; } @@ -631,7 +627,7 @@ { if (s->decompress.dict[i].parent_code != 0xFFFF) { - printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); + DEBUGP(DV42BIS,"Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); } } return 0; -- To view, visit https://gerrit.osmocom.org/644 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d Gerrit-PatchSet: 16 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Thu Aug 11 12:30:41 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Thu, 11 Aug 2016 12:30:41 +0000 Subject: [PATCH] openbsc[master]: Adding LLC-XID encoder / decoder and unit test In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/638 to look at the new patch set (#8). Adding LLC-XID encoder / decoder and unit test The lle-xid encoder/decoder is needed to encode and decode llc xid parameter messages. We need this to exchange sndcp-parameters (SNDCP-XID) and also simple parameters such as encryption IOVs Change-Id: Ia06e4cb08bf9b48c2a4682606d1b1a91d19a9d37 --- M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_llc_xid.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_llc_xid.c M openbsc/tests/Makefile.am M openbsc/tests/testsuite.at A openbsc/tests/xid/Makefile.am A openbsc/tests/xid/xid_test.c A openbsc/tests/xid/xid_test.ok 10 files changed, 553 insertions(+), 3 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/38/638/8 diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 0980413..fbf2930 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -229,6 +229,7 @@ tests/oap/Makefile tests/gtphub/Makefile tests/mm_auth/Makefile + tests/xid/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index c272b14..11f650d 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,7 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h + gtphub.h gprs_llc_xid.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_llc_xid.h b/openbsc/include/openbsc/gprs_llc_xid.h new file mode 100644 index 0000000..66ac6bc --- /dev/null +++ b/openbsc/include/openbsc/gprs_llc_xid.h @@ -0,0 +1,63 @@ +/* GPRS LLC XID field encoding/decoding as per 3GPP TS 44.064 */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_LLC_XID_H +#define _GPRS_LLC_XID_H + +#include +#include + +/* 3GPP TS 44.064 6.4.1.6 Exchange Identification (XID) + command/response parameter field */ +struct gprs_llc_xid_field { + struct llist_head list; + uint8_t type; /* See also Table 6: LLC layer parameter + negotiation */ + uint8_t *data; /* Payload data (memory is owned by the + * creator of the struct) */ + unsigned int data_len; /* Payload length */ +}; + +/* Transform a list with XID fields into a XID message (dst) */ +int gprs_llc_compile_xid(uint8_t *dst, int dst_maxlen, + const struct llist_head *xid_fields); + +/* Transform a XID message (dst) into a list of XID fields */ +struct llist_head *gprs_llc_parse_xid(const void *ctx, const uint8_t *src, + int src_len); + +/* Free XID-list with including all its XID-Fields */ +struct llist_head *gprs_llc_free_xid(struct llist_head *xid_fields); + +/* Create a duplicate of an XID-Field */ +struct gprs_llc_xid_field *gprs_llc_dup_xid_field(const void *ctx, + const struct gprs_llc_xid_field *xid_field); + +/* Copy an llist with xid fields */ +struct llist_head *gprs_llc_copy_xid(const void *ctx, + const struct llist_head *xid_fields); + +/* Dump a list with XID fields (Debug) */ +void gprs_llc_dump_xid_fields(const struct llist_head *xid_fields, + unsigned int logl); + +#endif diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 6dc7e16..8cbdd91 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -28,7 +28,7 @@ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ - oap.c oap_messages.c + oap.c oap_messages.c gprs_llc_xid.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/gprs_llc_xid.c b/openbsc/src/gprs/gprs_llc_xid.c new file mode 100644 index 0000000..651534b --- /dev/null +++ b/openbsc/src/gprs/gprs_llc_xid.c @@ -0,0 +1,283 @@ +/* GPRS LLC XID field encoding/decoding as per 3GPP TS 44.064 */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Parse XID parameter field */ +static int decode_xid_field(struct gprs_llc_xid_field *xid_field, + const uint8_t *src, uint8_t src_len) +{ + uint8_t xl; + uint8_t type; + uint8_t len; + int src_counter = 0; + + OSMO_ASSERT(xid_field); + OSMO_ASSERT(src); + + /* Exit immediately if it is clear that no + * parseable data is present */ + if (src_len < 1 || !src) + return -EINVAL; + + /* Extract header info */ + xl = (*src >> 7) & 1; + type = (*src >> 2) & 0x1F; + + /* Extract length field */ + len = (*src) & 0x3; + src++; + src_counter++; + if (xl) { + if (src_len < 2) + return -EINVAL; + len = (len << 6) & 0xC0; + len |= ((*src) >> 2) & 0x3F; + src++; + src_counter++; + } + + /* Fill out struct */ + xid_field->type = type; + xid_field->data_len = len; + if (len > 0) { + if (src_len < src_counter + len) + return -EINVAL; + xid_field->data = + talloc_zero_size(xid_field, xid_field->data_len); + memcpy(xid_field->data, src, xid_field->data_len); + } else + xid_field->data = NULL; + + /* Return consumed length */ + return src_counter + len; +} + +/* Encode XID parameter field */ +static int encode_xid_field(uint8_t *dst, int dst_maxlen, + const struct gprs_llc_xid_field *xid_field) +{ + int xl = 0; + + OSMO_ASSERT(xid_field); + OSMO_ASSERT(dst); + + /* When the length does not fit into 2 bits, + * we need extended length fields */ + if (xid_field->data_len > 3) + xl = 1; + + /* Exit immediately if it is clear that no + * encoding result can be stored */ + if (dst_maxlen < xid_field->data_len + 1 + xl) + return -EINVAL; + + /* There are only 5 bits reserved for the type, exit on exceed */ + if (xid_field->type > 31) + return -EINVAL; + + /* Encode header */ + memset(dst, 0, dst_maxlen); + if (xl) + dst[0] |= 0x80; + dst[0] |= (((xid_field->type) & 0x1F) << 2); + + if (xl) { + dst[0] |= (((xid_field->data_len) >> 6) & 0x03); + dst[1] = ((xid_field->data_len) << 2) & 0xFC; + } else + dst[0] |= ((xid_field->data_len) & 0x03); + + /* Append payload data */ + if (xid_field->data && xid_field->data_len) + memcpy(dst + 1 + xl, xid_field->data, xid_field->data_len); + + /* Return generated length */ + return xid_field->data_len + 1 + xl; +} + +/* Transform a list with XID fields into a XID message (dst) */ +int gprs_llc_compile_xid(uint8_t *dst, int dst_maxlen, + const struct llist_head *xid_fields) +{ + struct gprs_llc_xid_field *xid_field; + int rc; + int byte_counter = 0; + + OSMO_ASSERT(xid_fields); + OSMO_ASSERT(dst); + + llist_for_each_entry_reverse(xid_field, xid_fields, list) { + /* Encode XID-Field */ + rc = encode_xid_field(dst, dst_maxlen, xid_field); + if (rc < 0) + return -EINVAL; + + /* Advance pointer and lower maxlen for the + * next encoding round */ + dst += rc; + byte_counter += rc; + dst_maxlen -= rc; + } + + /* Return generated length */ + return byte_counter; +} + +/* Transform a XID message (dst) into a list of XID fields */ +struct llist_head *gprs_llc_parse_xid(const void *ctx, const uint8_t *src, + int src_len) +{ + struct gprs_llc_xid_field *xid_field; + struct llist_head *xid_fields; + + int rc; + int max_loops = src_len; + + OSMO_ASSERT(src); + + xid_fields = talloc_zero(ctx, struct llist_head); + INIT_LLIST_HEAD(xid_fields); + + while (1) { + /* Bail in case decode_xid_field() constantly returns zero */ + if (max_loops <= 0) { + talloc_free(xid_fields); + return NULL; + } + + /* Decode XID field */ + xid_field = talloc_zero(xid_fields, struct gprs_llc_xid_field); + rc = decode_xid_field(xid_field, src, src_len); + + /* Immediately stop on error */ + if (rc < 0) { + talloc_free(xid_fields); + return NULL; + } + + /* Add parsed XID field to list */ + llist_add(&xid_field->list, xid_fields); + + /* Advance pointer and lower dst_len for the next + * decoding round */ + src += rc; + src_len -= rc; + + /* We are (scuccessfully) done when no further byes are left */ + if (src_len == 0) + return xid_fields; + + max_loops--; + } +} + +/* Free XID-list with including all its XID-Fields */ +struct llist_head *gprs_llc_free_xid(struct llist_head *xid_fields) +{ + if (xid_fields != NULL) + talloc_free(xid_fields); + return NULL; +} + +/* Create a duplicate of an XID-Field */ +struct gprs_llc_xid_field *gprs_llc_dup_xid_field(const void *ctx, const struct + gprs_llc_xid_field + *xid_field) +{ + struct gprs_llc_xid_field *duplicate_of_xid_field; + + OSMO_ASSERT(xid_field); + + /* Create a copy of the XID field in memory */ + duplicate_of_xid_field = talloc_zero(ctx, struct gprs_llc_xid_field); + memcpy(duplicate_of_xid_field, xid_field, + sizeof(struct gprs_llc_xid_field)); + duplicate_of_xid_field->data = + talloc_zero_size(duplicate_of_xid_field, xid_field->data_len); + memcpy(duplicate_of_xid_field->data, xid_field->data, + xid_field->data_len); + + /* Unlink duplicate from source list */ + INIT_LLIST_HEAD(&duplicate_of_xid_field->list); + + return duplicate_of_xid_field; +} + +/* Copy an llist with xid fields */ +struct llist_head *gprs_llc_copy_xid(const void *ctx, + const struct llist_head *xid_fields) +{ + struct gprs_llc_xid_field *xid_field; + struct llist_head *xid_fields_copy; + + OSMO_ASSERT(xid_fields); + + xid_fields_copy = talloc_zero(ctx, struct llist_head); + INIT_LLIST_HEAD(xid_fields_copy); + + /* Create duplicates and add them to the target list */ + llist_for_each_entry(xid_field, xid_fields, list) { + llist_add(&gprs_llc_dup_xid_field(ctx, xid_field)->list, + xid_fields_copy); + } + + return xid_fields_copy; +} + +/* Dump a list with XID fields (Debug) */ +void gprs_llc_dump_xid_fields(const struct llist_head *xid_fields, + unsigned int logl) +{ + struct gprs_llc_xid_field *xid_field; + + OSMO_ASSERT(xid_fields); + + llist_for_each_entry(xid_field, xid_fields, list) { + if (xid_field->data_len) { + OSMO_ASSERT(xid_field->data); + LOGP(DSNDCP, logl, + "XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + osmo_hexdump_nospc(xid_field->data, + xid_field->data_len)); + } else { + LOGP(DSNDCP, logl, + "XID: type=%i, data_len=%i, data=NULL\n", + xid_field->type, xid_field->data_len); + } + } +} diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index 09298a3..ba5ca28 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index dab9568..6470ab9 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -124,3 +124,8 @@ AT_CHECK([$abs_top_builddir/tests/mm_auth/mm_auth_test], [], [expout], [ignore]) AT_CLEANUP +AT_SETUP([xid]) +AT_KEYWORDS([xid]) +cat $abs_srcdir/xid/xid_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/xid/xid_test], [], [expout], [ignore]) +AT_CLEANUP diff --git a/openbsc/tests/xid/Makefile.am b/openbsc/tests/xid/Makefile.am new file mode 100644 index 0000000..9b64965 --- /dev/null +++ b/openbsc/tests/xid/Makefile.am @@ -0,0 +1,21 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) + +EXTRA_DIST = xid_test.ok + +noinst_PROGRAMS = xid_test + +xid_test_SOURCES = xid_test.c + +xid_test_LDADD = \ + $(top_builddir)/src/gprs/gprs_llc_xid.o \ + $(top_builddir)/src/libcommon/libcommon.a \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOGB_LIBS) \ + $(LIBCARES_LIBS) \ + $(LIBCRYPTO_LIBS) \ + -lgtp -lrt -lm + + diff --git a/openbsc/tests/xid/xid_test.c b/openbsc/tests/xid/xid_test.c new file mode 100644 index 0000000..1b5b758 --- /dev/null +++ b/openbsc/tests/xid/xid_test.c @@ -0,0 +1,165 @@ +/* Test LLC-XID Encoding/Decoding */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include + +#include +#include + +#include + +#include +#include + +/* Test XID encoding */ +static void test_xid_encode(const void *ctx) +{ + struct gprs_llc_xid_field xid_field_1; + struct gprs_llc_xid_field xid_field_2; + struct gprs_llc_xid_field xid_field_3; + struct gprs_llc_xid_field xid_field_4; + LLIST_HEAD(xid_fields); + uint8_t xid[255]; + uint8_t xid_expected[] = + { 0x10, 0x8c, 0x14, 0x43, 0x43, 0x43, 0x43, 0x43, 0x0b, 0x42, 0x42, + 0x42, 0x05, 0x41 }; + int rc; + + printf("Testing LLC XID-Encoder\n"); + + /* Setup some simple XID data */ + xid_field_1.type = 1; + xid_field_2.type = 2; + xid_field_3.type = 3; + xid_field_4.type = 4; + + xid_field_1.data = (uint8_t *) "A"; + xid_field_2.data = (uint8_t *) "BBB"; + xid_field_3.data = (uint8_t *) "CCCCC"; + xid_field_4.data = NULL; + + xid_field_1.data_len = 1; + xid_field_2.data_len = 3; + xid_field_3.data_len = 5; + xid_field_4.data_len = 0; + + llist_add(&xid_field_4.list, &xid_fields); + llist_add(&xid_field_3.list, &xid_fields); + llist_add(&xid_field_2.list, &xid_fields); + llist_add(&xid_field_1.list, &xid_fields); + + printf("Data to encode:\n"); + gprs_llc_dump_xid_fields(&xid_fields, DSNDCP); + + /* Encode data */ + rc = gprs_llc_compile_xid(xid, sizeof(xid), &xid_fields); + OSMO_ASSERT(rc == 14); + printf("Encoded: %s (%i bytes)\n", osmo_hexdump_nospc(xid, rc), rc); + printf("Expected: %s (%i bytes)\n", + osmo_hexdump_nospc(xid_expected, sizeof(xid_expected)), + (int)sizeof(xid_expected)); + + OSMO_ASSERT(memcmp(xid_expected, xid, sizeof(xid_expected)) == 0); + + printf("\n"); +} + +/* Test XID decoding */ +static void test_xid_decode(const void *ctx) +{ + struct llist_head *xid_fields; + int rc; + + printf("Testing LLC XID-Decoder/Encoder\n"); + + /* Example of a real world LLC-XID message */ + uint8_t xid[] = + { 0x01, 0x00, 0x16, 0x05, 0xf0, 0x1a, 0x05, 0xf0, 0xac, 0xd8, 0x00, + 0x01, 0x00, 0x02, 0x31, 0x82, 0x02, 0x27, 0x89, 0xff, 0xe0, 0x00, 0x0f, + 0x00, 0xa8, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x01, 0x02, + 0x00, 0x03, 0x01, 0x03, 0x00, 0x04, 0x01, 0x04, 0x00, 0x05, 0x01, 0x05, + 0x00, 0x06, 0x00, 0x07, 0x01, 0x07, 0x00, 0x08, 0x01, 0x08, 0x80, 0x00, + 0x04, 0x12, 0x00, 0x40, 0x07 }; + + uint8_t xid_r[512]; + + /* Decode and display XID fields */ + xid_fields = gprs_llc_parse_xid(ctx, xid, sizeof(xid)); + OSMO_ASSERT(xid_fields); + + printf("Decoded:\n"); + gprs_llc_dump_xid_fields(xid_fields, DSNDCP); + + + /* Encode xid-fields again */ + rc = gprs_llc_compile_xid(xid_r, sizeof(xid_r), xid_fields); + printf("Result length=%i\n",rc); + printf("Encoded: %s\n", osmo_hexdump_nospc(xid, sizeof(xid))); + printf("Rencoded: %s\n", osmo_hexdump_nospc(xid_r, rc)); + + OSMO_ASSERT(rc == 64); + OSMO_ASSERT(memcmp(xid, xid_r, sizeof(xid)) == 0); + + /* Free xid fields */ + gprs_llc_free_xid(xid_fields); + + printf("\n"); +} + +static struct log_info_cat gprs_categories[] = { + [DSNDCP] = { + .name = "DSNDCP", + .description = + "GPRS Sub-Network Dependent Control Protocol (SNDCP)", + .enabled = 1,.loglevel = LOGL_DEBUG, + } +}; + +static struct log_info info = { + .cat = gprs_categories, + .num_cat = ARRAY_SIZE(gprs_categories), +}; + +int main(int argc, char **argv) +{ + void *xid_ctx; + + osmo_init_logging(&info); + + xid_ctx = talloc_named_const(NULL, 0, "xid_ctx"); + + test_xid_decode(xid_ctx); + test_xid_encode(xid_ctx); + printf("Done\n"); + + talloc_report_full(xid_ctx, stderr); + OSMO_ASSERT(talloc_total_blocks(xid_ctx) == 1); + return 0; +} + +/* stubs */ +struct osmo_prim_hdr; +int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) +{ + abort(); +} diff --git a/openbsc/tests/xid/xid_test.ok b/openbsc/tests/xid/xid_test.ok new file mode 100644 index 0000000..4cf825c --- /dev/null +++ b/openbsc/tests/xid/xid_test.ok @@ -0,0 +1,12 @@ +Testing LLC XID-Decoder/Encoder +Decoded: +Result length=64 +Encoded: 01001605f01a05f0acd8000100023182022789ffe0000f00a8000000010101000201020003010300040104000501050006000701070008010880000412004007 +Rencoded: 01001605f01a05f0acd8000100023182022789ffe0000f00a8000000010101000201020003010300040104000501050006000701070008010880000412004007 + +Testing LLC XID-Encoder +Data to encode: +Encoded: 108c1443434343430b4242420541 (14 bytes) +Expected: 108c1443434343430b4242420541 (14 bytes) + +Done -- To view, visit https://gerrit.osmocom.org/638 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia06e4cb08bf9b48c2a4682606d1b1a91d19a9d37 Gerrit-PatchSet: 8 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Thu Aug 11 14:52:23 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 11 Aug 2016 14:52:23 +0000 Subject: openbsc[master]: Adding LLC-XID encoder / decoder and unit test In-Reply-To: References: Message-ID: Patch Set 8: Code-Review-1 You should add the tests/xid/xid_test binary to openbsc/.gitignore with the other tests -- To view, visit https://gerrit.osmocom.org/638 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia06e4cb08bf9b48c2a4682606d1b1a91d19a9d37 Gerrit-PatchSet: 8 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 11 14:54:06 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 11 Aug 2016 14:54:06 +0000 Subject: openbsc[master]: Adding SNDCP-XID encoder / decoder and unit test In-Reply-To: References: Message-ID: Patch Set 9: You should add the tests/xid_sndcp/sndcp_xid_test binary to openbsc/.gitignore with the other tests interesting how you have both "xid_sndcp" and "sndcp_xid" in your file naming :) would be nicer to stick to one of them. -- To view, visit https://gerrit.osmocom.org/641 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e Gerrit-PatchSet: 9 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 11 14:54:12 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 11 Aug 2016 14:54:12 +0000 Subject: openbsc[master]: Adding SNDCP-XID encoder / decoder and unit test In-Reply-To: References: Message-ID: Patch Set 9: Code-Review-1 -- To view, visit https://gerrit.osmocom.org/641 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e Gerrit-PatchSet: 9 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 11 16:04:12 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Thu, 11 Aug 2016 16:04:12 +0000 Subject: [PATCH] openbsc[master]: Adding compression control In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/642 to look at the new patch set (#12). Adding compression control In this commit two modules were added: gprs_sndcp_comp.h/c: This part handles the creation and destruction of conpression entites. It handles the allocation and freeing of the memory and offers functions to query compression parameters (i.e. which compression entity should be used if a packet from NSAPI x has to be compressed?) gprs_sndcp_pcomp.c/h: This is the code that performs the actual header compression. It takes care that the packets are compressed/decompressed with the right modes etc. It works, but is not yet ready for merging. Both files depend on each other so that they only can be merged both at the same time. Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 --- M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_sndcp_comp.h A openbsc/include/openbsc/gprs_sndcp_pcomp.h M openbsc/include/openbsc/sgsn.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_sndcp_comp.c A openbsc/src/gprs/gprs_sndcp_pcomp.c M openbsc/src/gprs/sgsn_vty.c M openbsc/tests/sgsn/Makefile.am 9 files changed, 814 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/42/642/12 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index f402fea..88a7e2c 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,7 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ - slhc.h + slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_sndcp_comp.h b/openbsc/include/openbsc/gprs_sndcp_comp.h new file mode 100644 index 0000000..e2d79ab --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_comp.h @@ -0,0 +1,85 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_SNDCP_COMP_H +#define _GPRS_SNDCP_COMP_H + +#include +#include +#include + +/* Header / Data compression entity */ +struct gprs_sndcp_comp { + struct llist_head list; + + /* Serves as an ID in case we want to delete this entity later */ + int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + + /* Specifies to which NSAPIs the compression entity is assigned */ + int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + int nsapi[11]; /* Applicable NSAPIs (default 0) */ + + /* Assigned pcomp values */ + int comp_len; /* Number of contained PCOMP / DCOMP values */ + int comp[16]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */ + + /* Algorithm parameters */ + int algo; /* Algorithm type (see gprs_sndcp_xid.h) */ + int compclass; /* See gprs_sndcp_xid.h/c */ + void *state; /* Algorithm status and parameters */ +}; + +/* Free a list with compression entities */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities); + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, int entity); + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_entities_add(const void *ctx, struct + llist_head + *comp_entities, const struct + gprs_sndcp_comp_field + *comp_field); + +/* Find compression entity by its entity number */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_entity(const struct llist_head + *comp_entities, int entity); + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head + *comp_entities, int comp); + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head + *comp_entities, int nsapi); + +/* Find a comp_index for a given pcomp/dcomp value */ +int gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp + *comp_entity, int comp); + +/* Find a pcomp/dcomp value for a given comp_index */ +int gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp + *comp_entity, int comp_index); + +#endif diff --git a/openbsc/include/openbsc/gprs_sndcp_pcomp.h b/openbsc/include/openbsc/gprs_sndcp_pcomp.h new file mode 100644 index 0000000..5dafdbb --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_pcomp.h @@ -0,0 +1,47 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_SNDCP_pcomp_H +#define _GPRS_SNDCP_pcomp_H + +#include +#include +#include + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field); + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity); + +/* Expand header compressed packet */ +int gprs_sndcp_pcomp_expand(uint8_t *packet, int packet_len, int pcomp, + const struct llist_head *comp_entities); + +/* Expand header compressed packet */ +int gprs_sndcp_pcomp_compress(uint8_t *packet, int packet_len, + int *pcomp, + const struct llist_head *comp_entities, + int nsapi); + +#endif diff --git a/openbsc/include/openbsc/sgsn.h b/openbsc/include/openbsc/sgsn.h index 59126fe..b64d223 100644 --- a/openbsc/include/openbsc/sgsn.h +++ b/openbsc/include/openbsc/sgsn.h @@ -88,6 +88,13 @@ int dynamic_lookup; + /* RFC1144 TCP/IP Header compression */ + struct { + int passive; + int active; + int s01; + } pcomp_rfc1144; + struct oap_config oap; }; diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 245636b..2910c02 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -27,7 +27,7 @@ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ - slhc.c + slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/gprs_sndcp_comp.c b/openbsc/src/gprs/gprs_sndcp_comp.c new file mode 100644 index 0000000..8153fd2 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_comp.c @@ -0,0 +1,320 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +/* Create a new compression entity from a XID-Field */ +static struct gprs_sndcp_comp *gprs_sndcp_comp_create(const void + *ctx, const struct + gprs_sndcp_comp_field + *comp_field) +{ + OSMO_ASSERT(comp_field); + + struct gprs_sndcp_comp *comp_entity; + comp_entity = talloc_zero(ctx, struct gprs_sndcp_comp); + + /* Copy relevant information from the SNDCP-XID field */ + comp_entity->entity = comp_field->entity; + comp_entity->comp_len = comp_field->comp_len; + memcpy(comp_entity->comp, comp_field->comp, + comp_field->comp_len * sizeof(int)); + + if (comp_field->rfc1144_params) { + comp_entity->nsapi_len = comp_field->rfc1144_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc1144_params->nsapi, + comp_entity->nsapi_len * sizeof(int)); + } else if (comp_field->rfc2507_params) { + comp_entity->nsapi_len = comp_field->rfc2507_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc2507_params->nsapi, + comp_entity->nsapi_len * sizeof(int)); + } else if (comp_field->rohc_params) { + comp_entity->nsapi_len = comp_field->rohc_params->nsapi_len; + memcpy(comp_entity->nsapi, comp_field->rohc_params->nsapi, + comp_entity->nsapi_len * sizeof(int)); + } else if (comp_field->v42bis_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + comp_entity->nsapi_len * sizeof(int)); + } else if (comp_field->v44_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + comp_entity->nsapi_len * sizeof(int)); + } else { + talloc_free(comp_entity); + LOGP(DSNDCP, LOGL_ERROR, + "Comp field contained invalid parameters, compression entity not created!\n"); + return NULL; + } + + comp_entity->algo = comp_field->algo; + comp_entity->state = NULL; + + /* Determine of which class our compression entity will be + * (Protocol or Data compresson ?) */ + comp_entity->compclass = gprs_sndcp_get_compression_class(comp_field); + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + if (gprs_sndcp_pcomp_init(ctx, comp_entity, comp_field) == 0) + LOGP(DSNDCP, LOGL_INFO, + "New header compression entity (%i) created.\n", + comp_entity->entity); + else { + talloc_free(comp_entity); + LOGP(DSNDCP, LOGL_ERROR, + "Header compression entity (%i) creation failed!\n", + comp_entity->entity); + return NULL; + } + } else { + LOGP(DSNDCP, LOGL_INFO, + "New data compression entity (%i) created.\n", + comp_entity->entity); + } + + return comp_entity; +} + +/* Free a list with compression entities */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities) +{ + struct llist_head *ce, *ce2; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + /* Free compression entity */ + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %i ...\n", + comp_entity->entity); + gprs_sndcp_pcomp_term(comp_entity); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %i ...\n", + comp_entity->entity); + } + } + + llist_for_each_safe(ce, ce2, comp_entities) { + llist_del(ce); + talloc_free(ce); + } + +} + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, int entity) +{ + struct gprs_sndcp_comp *comp_entity; + struct gprs_sndcp_comp *comp_entity_to_delete = NULL; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) + comp_entity_to_delete = comp_entity; + } + + if (comp_entity_to_delete) { + if (comp_entity_to_delete->compclass == + SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %i ...\n", + comp_entity_to_delete->entity); + gprs_sndcp_pcomp_term(comp_entity_to_delete); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %i ...\n", + comp_entity_to_delete->entity); + } + + /* Delete compression entity */ + llist_del(&comp_entity_to_delete->list); + talloc_free(comp_entity_to_delete); + } + +} + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_entities_add(const void *ctx, struct + llist_head + *comp_entities, const struct + gprs_sndcp_comp_field + *comp_field) +{ + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(comp_entities); + OSMO_ASSERT(comp_field); + + /* Just to be sure, if the entity is already in + * the list it will be deleted now */ + gprs_sndcp_comp_delete(comp_entities, comp_field->entity); + + /* Create and add a new entity to the list */ + comp_entity = gprs_sndcp_comp_create(ctx, comp_field); + + if (comp_entity) { + llist_add(&comp_entity->list, comp_entities); + return comp_entity; + } + + return NULL; +} + +/* Find compression entity by its entity number */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_entity(const struct + llist_head + *comp_entities, int entity) +{ + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) + return comp_entity; + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given entity number %i.\n", + entity); + return NULL; +} + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct + llist_head + *comp_entities, int comp) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return comp_entity; + } + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given pcomp/dcomp value %i.\n", + comp); + return NULL; +} + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct + llist_head + *comp_entities, int nsapi) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->nsapi_len; i++) { + if (comp_entity->nsapi[i] == nsapi) + return comp_entity; + } + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given nsapi value %i\n", + nsapi); + return NULL; + +} + +/* Find a comp_index for a given pcomp/dcomp value */ +int gprs_sndcp_comp_get_idx(const struct + gprs_sndcp_comp + *comp_entity, int comp) +{ + int i; + + OSMO_ASSERT(comp_entity); + + /* A pcomp/dcomp field set to zero always disables + * all sort of compression and is assigned fix. So we + * just return zero in this case */ + if (comp == 0) + return 0; + + /* Look in the pcomp/dcomp list for the index */ + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return i + 1; + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching comp_index for given pcomp/dcomp value %i\n", + comp); + return 0; + +} + +/* Find a pcomp/dcomp value for a given comp_index */ +int gprs_sndcp_comp_get_comp(const struct + gprs_sndcp_comp + *comp_entity, int comp_index) +{ + OSMO_ASSERT(comp_entity); + + /* A comp_index of zero translates to zero right away. */ + if (comp_index == 0) + return 0; + + if (comp_index > comp_entity->comp_len) { + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching pcomp/dcomp value for given comp_index value %i.\n", + comp_index); + return 0; + } + + /* Look in the pcomp/dcomp list for the comp_index */ + return comp_entity->comp[comp_index - 1]; + +} diff --git a/openbsc/src/gprs/gprs_sndcp_pcomp.c b/openbsc/src/gprs/gprs_sndcp_pcomp.c new file mode 100644 index 0000000..786bcff --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_pcomp.c @@ -0,0 +1,300 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a new header compression + * entity is created by gprs_sndcp.c */ + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + comp_entity->state = + slhc_init(ctx, comp_field->rfc1144_params->s01 + 1, + comp_field->rfc1144_params->s01 + 1); + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression initalized.\n"); + return 0; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a header compression + * entity is deleted by gprs_sndcp.c */ + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + if (comp_entity->state) { + slhc_free((struct slcompress *) comp_entity-> + state); + comp_entity->state = NULL; + } + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression terminated.\n"); + return; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + + +/* Display compressor status */ +static void gprs_sndcp_pcomp_rfc1144_stat(struct slcompress *comp) +{ + slhc_i_status(comp); + slhc_o_status(comp); +} + + +/* Compress a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_compress(struct slcompress *comp, + uint8_t *packet, + int packet_len, + int *pcomp_index) +{ + uint8_t *packet_compressed; + uint8_t *packet_compressed_ptr; /* Not used */ + int packet_compressed_len; + + /* Reserve some space for to store the compression result */ + packet_compressed = talloc_zero_size(NULL, packet_len); + + /* Run compressor */ + memcpy(packet_compressed, packet, packet_len); + packet_compressed_len = + slhc_compress(comp, packet, packet_len, + (uint8_t *) packet_compressed, + &packet_compressed_ptr, 0); + + /* Copy back compression result */ + memcpy(packet, packet_compressed, packet_len); + talloc_free(packet_compressed); + + /* Generate pcomp_index */ + if ((packet[0] & SL_TYPE_COMPRESSED_TCP) == SL_TYPE_COMPRESSED_TCP) { + *pcomp_index = 2; + } else if ((packet[0] & SL_TYPE_UNCOMPRESSED_TCP) == + SL_TYPE_UNCOMPRESSED_TCP) { + *pcomp_index = 1; + + /* Remove tag for uncompressed TCP, because the + * packet type is already define by pcomp */ + packet[0] &= 0x4F; + } else + *pcomp_index = 0; + + return packet_compressed_len; +} + +/* Expand a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_expand(struct slcompress *comp, + uint8_t *packet, + int packet_len, + int pcomp_index) +{ + int packet_decompressed_len; + int type = -1; + + /* Note: this function should never be called with pcomp_index=0, + * since this condition is already filtered + * out by gprs_sndcp_pcomp_expand() */ + + /* Determine the packet type by the PCOMP index */ + switch (pcomp_index) { + case 1: + type = SL_TYPE_UNCOMPRESSED_TCP; + break; + case 2: + type = SL_TYPE_COMPRESSED_TCP; + break; + } + + /* Restore the original version nibble on + * marked uncompressed packets */ + if (type == SL_TYPE_UNCOMPRESSED_TCP) { + LOGP(DSNDCP, LOGL_INFO, + "Uncompressed rfc1144 packet received...\n"); + + + /* Just in case the phone tags uncompressed tcp-packets + * (normally this is handled by pcomp so there is + * no need for tagging the packets) */ + packet[0] &= 0x4F; + packet_decompressed_len = + slhc_remember(comp, packet, packet_len); + return packet_decompressed_len; + } + + /* Uncompress compressed packets */ + else if (type == SL_TYPE_COMPRESSED_TCP) { + LOGP(DSNDCP, LOGL_INFO, + "Compressed rfc1144 packet received...\n"); + packet_decompressed_len = + slhc_uncompress(comp, packet, packet_len); + return packet_decompressed_len; + } + + + /* Regular or unknown packets will not be touched */ + return packet_len; +} + + +/* Expand header compressed packet */ +int gprs_sndcp_pcomp_expand(uint8_t *packet, int packet_len, int pcomp, + const struct llist_head *comp_entities) +{ + int rc; + int pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + /* Skip on pcomp=0 */ + if (pcomp == 0) { + LOGP(DSNDCP, LOGL_INFO, + "Uncompressed packet received (pcomp=0), skipping compression...\n"); + return packet_len; + } + + /* Find out which compression entity handles the packet */ + comp_entity = + gprs_sndcp_comp_by_comp(comp_entities, pcomp); + + /* Skip compression if no suitable compression entity can be found! */ + if (comp_entity == NULL) { + LOGP(DSNDCP, LOGL_ERROR, + "Compressed packet received (pcomp=%i) but no suitable compression entity found, skipping compression...\n", + pcomp); + return packet_len; + } + + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144) + + + /* Find pcomp_index */ + pcomp_index = gprs_sndcp_comp_get_idx(comp_entity, pcomp); + + /* Run decompression algo */ + rc = gprs_sndcp_pcomp_rfc1144_expand((struct slcompress *) + comp_entity->state, packet, + packet_len, pcomp_index); + gprs_sndcp_pcomp_rfc1144_stat((struct slcompress *) comp_entity-> + state); + + + LOGP(DSNDCP, LOGL_DEBUG, + "Header expansion done, old length=%i, new length=%i, pcomp=%i, pcomp_index=%i\n", + packet_len, rc, pcomp, pcomp_index); + + return rc; +} + + +/* Expand header compressed packet */ +int gprs_sndcp_pcomp_compress(uint8_t *packet, int packet_len, + int *pcomp, + const struct llist_head *comp_entities, + int nsapi) +{ + int rc; + int pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + /* Find out which compression entity handles the packet */ + comp_entity = gprs_sndcp_comp_by_nsapi(comp_entities, nsapi); + + /* Skip compression if no suitable compression entity can be found! */ + if (comp_entity == NULL) { + LOGP(DSNDCP, LOGL_INFO, + "No suitable compression entity found for nsapi %i, skipping compression...\n", + nsapi); + *pcomp = 0; + return packet_len; + } + + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144) + + + /* Run compression algo */ + rc = gprs_sndcp_pcomp_rfc1144_compress((struct slcompress *) + comp_entity->state, + packet, packet_len, + &pcomp_index); + gprs_sndcp_pcomp_rfc1144_stat((struct slcompress *) comp_entity-> state); + + /* Find pcomp value */ + *pcomp = gprs_sndcp_comp_get_comp(comp_entity, pcomp_index); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header compression done, old length=%i, new length=%i, pcomp=%i, pcomp_index=%i\n", + packet_len, rc, *pcomp, pcomp_index); + return rc; +} + + diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c index e6dc68d..2cbf002 100644 --- a/openbsc/src/gprs/sgsn_vty.c +++ b/openbsc/src/gprs/sgsn_vty.c @@ -269,6 +269,19 @@ vty_out(vty, " timer t3395 %d%s", g_cfg->timers.T3395, VTY_NEWLINE); vty_out(vty, " timer t3397 %d%s", g_cfg->timers.T3397, VTY_NEWLINE); + if(g_cfg->pcomp_rfc1144.passive && g_cfg->pcomp_rfc1144.active) { + vty_out(vty, " compression rfc1144 negotiation both s01 %d%s", + g_cfg->pcomp_rfc1144.s01, VTY_NEWLINE); + } else if (g_cfg->pcomp_rfc1144.passive) { + vty_out(vty, " compression rfc1144 negotiation passive s01 %d%s", + g_cfg->pcomp_rfc1144.s01, VTY_NEWLINE); + } else if (g_cfg->pcomp_rfc1144.active) { + vty_out(vty, " compression rfc1144 negotiation active s01 %d%s", + g_cfg->pcomp_rfc1144.s01, VTY_NEWLINE); + } else { + vty_out(vty, " no compression rfc1144%s", VTY_NEWLINE); + } + return CMD_SUCCESS; } @@ -1074,6 +1087,41 @@ return CMD_SUCCESS; } +DEFUN(cfg_no_comp_rfc1144, cfg_no_comp_rfc1144_cmd, + "no compression rfc1144", + NO_STR "disable rfc1144 TCP/IP header compression\n") +{ + g_cfg->pcomp_rfc1144.active = 0; + g_cfg->pcomp_rfc1144.passive = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_comp_rfc1144, cfg_comp_rfc1144_cmd, + "compression rfc1144 negotiation (active|passive|both) s01 <0-255>", + NO_STR "GPRS compression scheme\n") +{ + switch (argv[0][0]) { + case 'a': + g_cfg->pcomp_rfc1144.active = 1; + g_cfg->pcomp_rfc1144.passive = 0; + break; + case 'p': + g_cfg->pcomp_rfc1144.active = 0; + g_cfg->pcomp_rfc1144.passive = 1; + break; + case 'b': + g_cfg->pcomp_rfc1144.active = 1; + g_cfg->pcomp_rfc1144.passive = 1; + break; + default: + g_cfg->pcomp_rfc1144.active = 0; + g_cfg->pcomp_rfc1144.passive = 0; + } + + g_cfg->pcomp_rfc1144.s01 = atoi(argv[1]); + return CMD_SUCCESS; +} + int sgsn_vty_init(void) { install_element_ve(&show_sgsn_cmd); @@ -1128,6 +1176,9 @@ install_element(SGSN_NODE, &cfg_sgsn_T3395_cmd); install_element(SGSN_NODE, &cfg_sgsn_T3397_cmd); + install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd); + install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd); + return 0; } diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 3e66978..1804280 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -33,6 +33,8 @@ $(top_builddir)/src/gprs/gprs_llc_xid.o \ $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ $(top_builddir)/src/gprs/slhc.o \ + $(top_builddir)/src/gprs/gprs_sndcp_comp.o \ + $(top_builddir)/src/gprs/gprs_sndcp_pcomp.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ -- To view, visit https://gerrit.osmocom.org/642 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 Gerrit-PatchSet: 12 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Thu Aug 11 16:04:13 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Thu, 11 Aug 2016 16:04:13 +0000 Subject: [PATCH] openbsc[master]: fixup Message-ID: Review at https://gerrit.osmocom.org/686 fixup Change-Id: Ie97c572d61fc34dac415d5be4c10c279d0430d93 --- M openbsc/.gitignore M openbsc/configure.ac M openbsc/tests/Makefile.am R openbsc/tests/sndcp_xid/Makefile.am R openbsc/tests/sndcp_xid/sndcp_xid_test.c R openbsc/tests/sndcp_xid/sndcp_xid_test.ok M openbsc/tests/testsuite.at 7 files changed, 8 insertions(+), 6 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/86/686/1 diff --git a/openbsc/.gitignore b/openbsc/.gitignore index 0a2965d..8ce3b70 100644 --- a/openbsc/.gitignore +++ b/openbsc/.gitignore @@ -81,6 +81,8 @@ tests/oap/oap_test tests/gtphub/gtphub_test tests/mm_auth/mm_auth_test +tests/xid/xid_test +tests/sndcp_xid/sndcp_xid_test tests/atconfig tests/atlocal diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 9cfdc7c..53072bd 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -230,7 +230,7 @@ tests/gtphub/Makefile tests/mm_auth/Makefile tests/xid/Makefile - tests/xid_sndcp/Makefile + tests/sndcp_xid/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index 071166b..1debb2d 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid xid_sndcp +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/xid_sndcp/Makefile.am b/openbsc/tests/sndcp_xid/Makefile.am similarity index 100% rename from openbsc/tests/xid_sndcp/Makefile.am rename to openbsc/tests/sndcp_xid/Makefile.am diff --git a/openbsc/tests/xid_sndcp/sndcp_xid_test.c b/openbsc/tests/sndcp_xid/sndcp_xid_test.c similarity index 100% rename from openbsc/tests/xid_sndcp/sndcp_xid_test.c rename to openbsc/tests/sndcp_xid/sndcp_xid_test.c diff --git a/openbsc/tests/xid_sndcp/sndcp_xid_test.ok b/openbsc/tests/sndcp_xid/sndcp_xid_test.ok similarity index 100% rename from openbsc/tests/xid_sndcp/sndcp_xid_test.ok rename to openbsc/tests/sndcp_xid/sndcp_xid_test.ok diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index 22b3db9..85a81d6 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -130,9 +130,9 @@ AT_CHECK([$abs_top_builddir/tests/xid/xid_test], [], [expout], [ignore]) AT_CLEANUP -AT_SETUP([xid_sndcp]) -AT_KEYWORDS([xid_sndcp]) -cat $abs_srcdir/xid_sndcp/sndcp_xid_test.ok > expout -AT_CHECK([$abs_top_builddir/tests/xid_sndcp/sndcp_xid_test], [], [expout], [ignore]) +AT_SETUP([sndcp_xid]) +AT_KEYWORDS([sndcp_xid]) +cat $abs_srcdir/sndcp_xid/sndcp_xid_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/sndcp_xid/sndcp_xid_test], [], [expout], [ignore]) AT_CLEANUP -- To view, visit https://gerrit.osmocom.org/686 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ie97c572d61fc34dac415d5be4c10c279d0430d93 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter From gerrit-no-reply at lists.osmocom.org Thu Aug 11 16:06:46 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Thu, 11 Aug 2016 16:06:46 +0000 Subject: [ABANDON] openbsc[master]: fixup In-Reply-To: References: Message-ID: dexter has abandoned this change. Change subject: fixup ...................................................................... Abandoned -- To view, visit https://gerrit.osmocom.org/686 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: abandon Gerrit-Change-Id: Ie97c572d61fc34dac415d5be4c10c279d0430d93 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter From gerrit-no-reply at lists.osmocom.org Thu Aug 11 16:28:18 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 11 Aug 2016 16:28:18 +0000 Subject: [PATCH] openbsc[master]: add libiu In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/192 to look at the new patch set (#4). add libiu Co-Authored by dwillmann, laforge, nhofmeyr Change-Id: Iffc26f9c73cb15463948f7435b72ac1747aabdb3 --- M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/iu.h M openbsc/src/Makefile.am A openbsc/src/libiu/Makefile.am A openbsc/src/libiu/iu.c 6 files changed, 844 insertions(+), 3 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/92/192/4 diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 0980413..3d99cb8 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -203,6 +203,7 @@ src/libmgcp/Makefile src/libcommon/Makefile src/libfilter/Makefile + src/libiu/Makefile src/osmo-nitb/Makefile src/osmo-bsc/Makefile src/osmo-bsc_nat/Makefile diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index c272b14..2bca6b7 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,8 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h + gtphub.h \ + iu.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/iu.h b/openbsc/include/openbsc/iu.h new file mode 100644 index 0000000..d0ab540 --- /dev/null +++ b/openbsc/include/openbsc/iu.h @@ -0,0 +1,60 @@ +#pragma once + +#include + +struct sgsn_pdp_ctx; +struct msgb; +struct gprs_ra_id; + +struct RANAP_RAB_SetupOrModifiedItemIEs_s; +struct RANAP_GlobalRNC_ID; + +struct ue_conn_ctx { + struct llist_head list; + struct osmo_sccp_link *link; + uint32_t conn_id; + int integrity_active; + struct gprs_ra_id ra_id; +}; + +enum iu_event_type { + IU_EVENT_RAB_ASSIGN, + IU_EVENT_SECURITY_MODE_COMPLETE, + IU_EVENT_IU_RELEASE, /* An actual Iu Release message was received */ + IU_EVENT_LINK_INVALIDATED, /* A SUA link was lost or closed down */ + /* FIXME: maybe IU_EVENT_IU_RELEASE and IU_EVENT_LINK_INVALIDATED + * should be combined to one generic event that simply means the + * ue_conn_ctx should no longer be used, for whatever reason. */ +}; + +extern const struct value_string iu_event_type_names[]; +static inline const char *iu_event_type_str(enum iu_event_type e) +{ + return get_value_string(iu_event_type_names, e); +} + +/* Implementations of iu_recv_cb_t shall find the ue_conn_ctx in msg->dst. */ +typedef int (* iu_recv_cb_t )(struct msgb *msg, struct gprs_ra_id *ra_id, + /* TODO "gprs_" in generic CS+PS domain ^ */ + uint16_t *sai); + +typedef int (* iu_event_cb_t )(struct ue_conn_ctx *ue_ctx, + enum iu_event_type type, void *data); + +typedef int (* iu_rab_ass_resp_cb_t )(struct ue_conn_ctx *ue_ctx, uint8_t rab_id, + struct RANAP_RAB_SetupOrModifiedItemIEs_s *setup_ies); + +int iu_init(void *ctx, const char *listen_addr, uint16_t listen_port, + iu_recv_cb_t iu_recv_cb, iu_event_cb_t iu_event_cb); + +void iu_link_del(struct osmo_sccp_link *link); + +int iu_tx(struct msgb *msg, uint8_t sapi); + +int iu_page_cs(const char *imsi, const uint32_t *tmsi, uint16_t lac); +int iu_page_ps(const char *imsi, const uint32_t *ptmsi, uint16_t lac, uint8_t rac); + +int iu_rab_act(struct ue_conn_ctx *ue_ctx, struct msgb *msg); +int iu_rab_deact(struct ue_conn_ctx *ue_ctx, uint8_t rab_id); +int iu_tx_sec_mode_cmd(struct ue_conn_ctx *uectx, struct gsm_auth_tuple *tp, + int send_ck, int new_key); diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 6f6174e..4aa880f 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -2,9 +2,18 @@ AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(COVERAGE_CFLAGS) AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(COVERAGE_LDFLAGS) -SUBDIRS = libcommon libmgcp libbsc libmsc libtrau libfilter osmo-nitb osmo-bsc_mgcp utils ipaccess gprs +# Libraries +SUBDIRS = libcommon libmgcp libbsc libmsc libtrau libfilter -# Conditional modules +# Conditional Libraries +if BUILD_IU +SUBDIRS += libiu +endif + +# Programs +SUBDIRS += osmo-nitb osmo-bsc_mgcp utils ipaccess gprs + +# Conditional Programs if BUILD_NAT SUBDIRS += osmo-bsc_nat endif diff --git a/openbsc/src/libiu/Makefile.am b/openbsc/src/libiu/Makefile.am new file mode 100644 index 0000000..7b1ba4d --- /dev/null +++ b/openbsc/src/libiu/Makefile.am @@ -0,0 +1,10 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) +AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) \ + $(LIBOSMOGSM_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) $(LIBCRYPTO_CFLAGS) \ + $(LIBASN1C_CFLAGS) \ + $(LIBOSMOSIGTRAN_CFLAGS) $(LIBOSMORANAP_CFLAGS) + +noinst_LIBRARIES = libiu.a + +libiu_a_SOURCES = iu.c + diff --git a/openbsc/src/libiu/iu.c b/openbsc/src/libiu/iu.c new file mode 100644 index 0000000..15a9d6f --- /dev/null +++ b/openbsc/src/libiu/iu.c @@ -0,0 +1,760 @@ +/* Common parts of IuCS and IuPS interfaces implementation */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +/* Parsed global RNC id. See also struct RANAP_GlobalRNC_ID, and note that the + * PLMN identity is a BCD representation of the MCC and MNC. + * See iu_grnc_id_parse(). */ +struct iu_grnc_id { + uint16_t mcc; + uint16_t mnc; + uint16_t rnc_id; +}; + +/* A remote RNC (Radio Network Controller, like BSC but for UMTS) that has + * called us and is currently reachable at the given osmo_sccp_link. So, when we + * know a LAC for a subscriber, we can page it at the RNC matching that LAC or + * RAC. An HNB-GW typically presents itself as if it were a single RNC, even + * though it may have several RNCs in hNodeBs connected to it. Those will then + * share the same RNC id, which they actually receive and adopt from the HNB-GW + * in the HNBAP HNB REGISTER ACCEPT message. */ +struct iu_rnc { + struct llist_head entry; + + uint16_t rnc_id; + uint16_t lac; /* Location Area Code (used for CS and PS) */ + uint8_t rac; /* Routing Area Code (used for PS only) */ + struct osmo_sccp_link *link; +}; + +void *talloc_iu_ctx; + +int asn1_xer_print = 1; +void *talloc_asn1_ctx; + +iu_recv_cb_t global_iu_recv_cb = NULL; +iu_event_cb_t global_iu_event_cb = NULL; + +static LLIST_HEAD(ue_conn_ctx_list); +static LLIST_HEAD(rnc_list); + +const struct value_string iu_event_type_names[] = { +#define IU_EVT_STR(X) { X, #X } + IU_EVT_STR(IU_EVENT_RAB_ASSIGN), + IU_EVT_STR(IU_EVENT_SECURITY_MODE_COMPLETE), + IU_EVT_STR(IU_EVENT_IU_RELEASE), + IU_EVT_STR(IU_EVENT_LINK_INVALIDATED), +#undef IU_EVT_STR +}; + +struct ue_conn_ctx *ue_conn_ctx_alloc(struct osmo_sccp_link *link, uint32_t conn_id) +{ + struct ue_conn_ctx *ctx = talloc_zero(talloc_iu_ctx, struct ue_conn_ctx); + + ctx->link = link; + ctx->conn_id = conn_id; + llist_add(&ctx->list, &ue_conn_ctx_list); + + return ctx; +} + +struct ue_conn_ctx *ue_conn_ctx_find(struct osmo_sccp_link *link, + uint32_t conn_id) +{ + struct ue_conn_ctx *ctx; + + llist_for_each_entry(ctx, &ue_conn_ctx_list, list) { + if (ctx->link == link && ctx->conn_id == conn_id) + return ctx; + } + return NULL; +} + +static struct iu_rnc *iu_rnc_alloc(uint16_t rnc_id, uint16_t lac, uint8_t rac, + struct osmo_sccp_link *link) +{ + struct iu_rnc *rnc = talloc_zero(talloc_iu_ctx, struct iu_rnc); + + rnc->rnc_id = rnc_id; + rnc->lac = lac; + rnc->rac = rac; + rnc->link = link; + llist_add(&rnc->entry, &rnc_list); + + LOGP(DRANAP, LOGL_NOTICE, "New RNC %d (LAC=%d RAC=%d)\n", + rnc->rnc_id, rnc->lac, rnc->rac); + + return rnc; +} + +static struct iu_rnc *iu_rnc_register(uint16_t rnc_id, uint16_t lac, + uint8_t rac, struct osmo_sccp_link *link) +{ + struct iu_rnc *rnc; + llist_for_each_entry(rnc, &rnc_list, entry) { + if (rnc->rnc_id != rnc_id) + continue; + + /* We have this RNC Id registered already. Make sure that the + * details match. */ + + /* TODO should a mismatch be an error? */ + if (rnc->lac != lac || rnc->rac != rac) + LOGP(DRANAP, LOGL_NOTICE, "RNC %d changes its details:" + " LAC=%d RAC=%d --> LAC=%d RAC=%d\n", + rnc->rnc_id, rnc->lac, rnc->rac, + lac, rac); + rnc->lac = lac; + rnc->rac = rac; + + if (link && rnc->link != link) + LOGP(DRANAP, LOGL_NOTICE, "RNC %d on new link" + " (LAC=%d RAC=%d)\n", + rnc->rnc_id, rnc->lac, rnc->rac); + rnc->link = link; + return rnc; + } + + /* Not found, make a new one. */ + return iu_rnc_alloc(rnc_id, lac, rac, link); +} + +/* Discard/invalidate all ue_conn_ctx and iu_rnc entries that reference the + * given link, since this link is invalid and about to be deallocated. For + * each ue_conn_ctx, invoke the iu_event_cb_t with IU_EVENT_LINK_INVALIDATED. + */ +void iu_link_del(struct osmo_sccp_link *link) +{ + struct iu_rnc *rnc, *rnc_next; + llist_for_each_entry_safe(rnc, rnc_next, &rnc_list, entry) { + if (!rnc->link) + continue; + if (rnc->link != link) + continue; + rnc->link = NULL; + llist_del(&rnc->entry); + talloc_free(rnc); + } + + struct ue_conn_ctx *uec, *uec_next; + llist_for_each_entry_safe(uec, uec_next, &ue_conn_ctx_list, list) { + if (uec->link != link) + continue; + uec->link = NULL; + global_iu_event_cb(uec, IU_EVENT_LINK_INVALIDATED, NULL); + } +} + +/*********************************************************************** + * RANAP handling + ***********************************************************************/ + +int iu_rab_act(struct ue_conn_ctx *ue_ctx, struct msgb *msg) +{ + struct osmo_scu_prim *prim; + + /* wrap RANAP message in SCCP N-DATA.req */ + prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim)); + prim->u.data.conn_id = ue_ctx->conn_id; + osmo_prim_init(&prim->oph, + SCCP_SAP_USER, + OSMO_SCU_PRIM_N_DATA, + PRIM_OP_REQUEST, + msg); + return osmo_sua_user_link_down(ue_ctx->link, &prim->oph); +} + +int iu_rab_deact(struct ue_conn_ctx *ue_ctx, uint8_t rab_id) +{ + /* FIXME */ + return -1; +} + +int iu_tx_sec_mode_cmd(struct ue_conn_ctx *uectx, struct gsm_auth_tuple *tp, + int send_ck, int new_key) +{ + struct osmo_scu_prim *prim; + struct msgb *msg; + uint8_t ik[16]; + uint8_t ck[16]; + unsigned int i; + + /* C5 function to derive IK from Kc */ + for (i = 0; i < 4; i++) + ik[i] = tp->vec.kc[i] ^ tp->vec.kc[i+4]; + memcpy(ik+4, tp->vec.kc, 8); + for (i = 12; i < 16; i++) + ik[i] = ik[i-12]; + + if (send_ck) { + /* C4 function to derive CK from Kc */ + memcpy(ck, tp->vec.kc, 8); + memcpy(ck+8, tp->vec.kc, 8); + } + + /* create RANAP message */ + msg = ranap_new_msg_sec_mod_cmd(ik, send_ck? ck : NULL, new_key ? RANAP_KeyStatus_new : RANAP_KeyStatus_old); + msg->l2h = msg->data; + /* wrap RANAP message in SCCP N-DATA.req */ + prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim)); + prim->u.data.conn_id = uectx->conn_id; + osmo_prim_init(&prim->oph, SCCP_SAP_USER, + OSMO_SCU_PRIM_N_DATA, + PRIM_OP_REQUEST, msg); + osmo_sua_user_link_down(uectx->link, &prim->oph); + + return 0; +} + +static int iu_grnc_id_parse(struct iu_grnc_id *dst, + struct RANAP_GlobalRNC_ID *src) +{ + /* The size is coming from arbitrary sender, check it gracefully */ + if (src->pLMNidentity.size != 3) { + LOGP(DRANAP, LOGL_ERROR, "Invalid PLMN Identity size:" + " should be 3, is %d\n", src->pLMNidentity.size); + return -1; + } + gsm48_mcc_mnc_from_bcd(&src->pLMNidentity.buf[0], + &dst->mcc, &dst->mnc); + dst->rnc_id = (uint16_t)src->rNC_ID; + return 0; +} + +#if 0 + -- not used at present -- +static int iu_grnc_id_compose(struct iu_grnc_id *src, + struct RANAP_GlobalRNC_ID *dst) +{ + /* The caller must ensure proper size */ + OSMO_ASSERT(dst->pLMNidentity.size == 3); + gsm48_mcc_mnc_to_bcd(&dst->pLMNidentity.buf[0], + src->mcc, src->mnc); + dst->rNC_ID = src->rnc_id; + return 0; +} +#endif + +static int ranap_handle_co_initial_ue(void *ctx, RANAP_InitialUE_MessageIEs_t *ies) +{ + struct ue_conn_ctx *ue_conn = ctx; + struct gprs_ra_id ra_id; + struct iu_grnc_id grnc_id; + uint16_t sai; + struct msgb *msg = msgb_alloc(256, "RANAP->NAS"); + + if (ranap_parse_lai(&ra_id, &ies->lai) != 0) { + LOGP(DRANAP, LOGL_ERROR, "Failed to parse RANAP LAI IE\n"); + return -1; + } + + if (ies->presenceMask & INITIALUE_MESSAGEIES_RANAP_RAC_PRESENT) { + ra_id.rac = asn1str_to_u8(&ies->rac); + } + + if (iu_grnc_id_parse(&grnc_id, &ies->globalRNC_ID) != 0) { + LOGP(DRANAP, LOGL_ERROR, + "Failed to parse RANAP Global-RNC-ID IE\n"); + return -1; + } + + sai = asn1str_to_u16(&ies->sai.sAC); + msgb_gmmh(msg) = msgb_put(msg, ies->nas_pdu.size); + memcpy(msgb_gmmh(msg), ies->nas_pdu.buf, ies->nas_pdu.size); + + /* Make sure we know the RNC Id and LAC+RAC coming in on this connection. */ + iu_rnc_register(grnc_id.rnc_id, ra_id.lac, ra_id.rac, ue_conn->link); + ue_conn->ra_id = ra_id; + + /* Feed into the MM layer */ + msg->dst = ctx; + global_iu_recv_cb(msg, &ra_id, &sai); + + msgb_free(msg); + + return 0; +} + +static int ranap_handle_co_dt(void *ctx, RANAP_DirectTransferIEs_t *ies) +{ + struct gprs_ra_id _ra_id, *ra_id = NULL; + uint16_t _sai, *sai = NULL; + struct msgb *msg = msgb_alloc(256, "RANAP->NAS"); + + if (ies->presenceMask & DIRECTTRANSFERIES_RANAP_LAI_PRESENT) { + if (ranap_parse_lai(&_ra_id, &ies->lai) != 0) { + LOGP(DRANAP, LOGL_ERROR, "Failed to parse RANAP LAI IE\n"); + return -1; + } + ra_id = &_ra_id; + if (ies->presenceMask & DIRECTTRANSFERIES_RANAP_RAC_PRESENT) { + _ra_id.rac = asn1str_to_u8(&ies->rac); + } + if (ies->presenceMask & DIRECTTRANSFERIES_RANAP_SAI_PRESENT) { + _sai = asn1str_to_u16(&ies->sai.sAC); + sai = &_sai; + } + } + + msgb_gmmh(msg) = msgb_put(msg, ies->nas_pdu.size); + memcpy(msgb_gmmh(msg), ies->nas_pdu.buf, ies->nas_pdu.size); + + /* Feed into the MM/CC/SMS-CP layer */ + msg->dst = ctx; + global_iu_recv_cb(msg, ra_id, sai); + + msgb_free(msg); + + return 0; +} + +static int ranap_handle_co_err_ind(void *ctx, RANAP_ErrorIndicationIEs_t *ies) +{ + if (ies->presenceMask & ERRORINDICATIONIES_RANAP_CAUSE_PRESENT) + LOGP(DRANAP, LOGL_ERROR, "Rx Error Indication (%s)\n", + ranap_cause_str(&ies->cause)); + else + LOGP(DRANAP, LOGL_ERROR, "Rx Error Indication\n"); + + return 0; +} + +int iu_tx(struct msgb *msg_nas, uint8_t sapi) +{ + struct ue_conn_ctx *uectx = msg_nas->dst; + struct msgb *msg; + struct osmo_scu_prim *prim; + + LOGP(DRANAP, LOGL_INFO, "Transmitting L3 Message as RANAP DT (SUA link %p conn_id %u)\n", + uectx->link, uectx->conn_id); + + msg = ranap_new_msg_dt(sapi, msg_nas->data, msgb_length(msg_nas)); + msgb_free(msg_nas); + msg->l2h = msg->data; + prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim)); + prim->u.data.conn_id = uectx->conn_id; + osmo_prim_init(&prim->oph, SCCP_SAP_USER, + OSMO_SCU_PRIM_N_DATA, + PRIM_OP_REQUEST, msg); + osmo_sua_user_link_down(uectx->link, &prim->oph); + return 0; +} + +static int ranap_handle_co_iu_rel_req(struct ue_conn_ctx *ctx, RANAP_Iu_ReleaseRequestIEs_t *ies) +{ + struct msgb *msg; + struct osmo_scu_prim *prim; + + LOGP(DRANAP, LOGL_INFO, "Received Iu Release Request, Sending Release Command\n"); + msg = ranap_new_msg_iu_rel_cmd(&ies->cause); + msg->l2h = msg->data; + prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim)); + prim->u.data.conn_id = ctx->conn_id; + osmo_prim_init(&prim->oph, SCCP_SAP_USER, + OSMO_SCU_PRIM_N_DATA, + PRIM_OP_REQUEST, msg); + osmo_sua_user_link_down(ctx->link, &prim->oph); + return 0; +} + +static int ranap_handle_co_rab_ass_resp(struct ue_conn_ctx *ctx, RANAP_RAB_AssignmentResponseIEs_t *ies) +{ + int rc = -1; + + LOGP(DRANAP, LOGL_INFO, "RAB Asignment Response:"); + if (ies->presenceMask & RAB_ASSIGNMENTRESPONSEIES_RANAP_RAB_SETUPORMODIFIEDLIST_PRESENT) { + /* TODO: Iterate over list of SetupOrModifiedList IEs and handle each one */ + RANAP_IE_t *ranap_ie = ies->raB_SetupOrModifiedList.raB_SetupOrModifiedList_ies.list.array[0]; + RANAP_RAB_SetupOrModifiedItemIEs_t setup_ies; + + rc = ranap_decode_rab_setupormodifieditemies_fromlist(&setup_ies, &ranap_ie->value); + if (rc) { + LOGP(DRANAP, LOGL_ERROR, "Error in ranap_decode_rab_setupormodifieditemies()\n"); + return rc; + } + + rc = global_iu_event_cb(ctx, IU_EVENT_RAB_ASSIGN, &setup_ies); + + ranap_free_rab_setupormodifieditemies(&setup_ies); + } + + LOGPC(DRANAP, LOGL_INFO, "\n"); + + return rc; +} + +/* Entry point for connection-oriented RANAP message */ +static void cn_ranap_handle_co(void *ctx, ranap_message *message) +{ + int rc; + + LOGP(DRANAP, LOGL_NOTICE, "handle_co(dir=%u, proc=%u)\n", message->direction, message->procedureCode); + + switch (message->direction) { + case RANAP_RANAP_PDU_PR_initiatingMessage: + switch (message->procedureCode) { + case RANAP_ProcedureCode_id_InitialUE_Message: + rc = ranap_handle_co_initial_ue(ctx, &message->msg.initialUE_MessageIEs); + break; + case RANAP_ProcedureCode_id_DirectTransfer: + rc = ranap_handle_co_dt(ctx, &message->msg.directTransferIEs); + break; + case RANAP_ProcedureCode_id_ErrorIndication: + rc = ranap_handle_co_err_ind(ctx, &message->msg.errorIndicationIEs); + break; + case RANAP_ProcedureCode_id_Iu_ReleaseRequest: + /* Iu Release Request */ + rc = ranap_handle_co_iu_rel_req(ctx, &message->msg.iu_ReleaseRequestIEs); + break; + default: + LOGP(DRANAP, LOGL_ERROR, "Received Initiating Message: unknown Procedure Code %d\n", + message->procedureCode); + rc = -1; + break; + } + break; + case RANAP_RANAP_PDU_PR_successfulOutcome: + switch (message->procedureCode) { + case RANAP_ProcedureCode_id_SecurityModeControl: + /* Security Mode Complete */ + rc = global_iu_event_cb(ctx, IU_EVENT_SECURITY_MODE_COMPLETE, NULL); + break; + case RANAP_ProcedureCode_id_Iu_Release: + /* Iu Release Complete */ + rc = global_iu_event_cb(ctx, IU_EVENT_IU_RELEASE, NULL); + if (rc) { + LOGP(DRANAP, LOGL_ERROR, "Iu Release event: Iu Event callback returned %d\n", + rc); + } + break; + default: + LOGP(DRANAP, LOGL_ERROR, "Received Successful Outcome: unknown Procedure Code %d\n", + message->procedureCode); + rc = -1; + break; + } + break; + case RANAP_RANAP_PDU_PR_outcome: + switch (message->procedureCode) { + case RANAP_ProcedureCode_id_RAB_Assignment: + /* RAB Assignment Response */ + rc = ranap_handle_co_rab_ass_resp(ctx, &message->msg.raB_AssignmentResponseIEs); + break; + default: + LOGP(DRANAP, LOGL_ERROR, "Received Outcome: unknown Procedure Code %d\n", + message->procedureCode); + rc = -1; + break; + } + break; + case RANAP_RANAP_PDU_PR_unsuccessfulOutcome: + default: + LOGP(DRANAP, LOGL_ERROR, "Received Unsuccessful Outcome: Procedure Code %d\n", + message->procedureCode); + rc = -1; + break; + } + + if (rc) { + LOGP(DRANAP, LOGL_ERROR, "Error in cn_ranap_handle_co (%d)\n", + rc); + /* TODO handling of the error? */ + } +} + +static int ranap_handle_cl_reset_req(void *ctx, RANAP_ResetIEs_t *ies) +{ + /* FIXME: send reset response */ + return -1; +} + +static int ranap_handle_cl_err_ind(void *ctx, RANAP_ErrorIndicationIEs_t *ies) +{ + if (ies->presenceMask & ERRORINDICATIONIES_RANAP_CAUSE_PRESENT) + LOGP(DRANAP, LOGL_ERROR, "Rx Error Indication (%s)\n", + ranap_cause_str(&ies->cause)); + else + LOGP(DRANAP, LOGL_ERROR, "Rx Error Indication\n"); + + return 0; +} + +/* Entry point for connection-less RANAP message */ +static void cn_ranap_handle_cl(void *ctx, ranap_message *message) +{ + int rc; + + switch (message->direction) { + case RANAP_RANAP_PDU_PR_initiatingMessage: + switch (message->procedureCode) { + case RANAP_ProcedureCode_id_Reset: + /* received reset.req, send reset.resp */ + rc = ranap_handle_cl_reset_req(ctx, &message->msg.resetIEs); + break; + case RANAP_ProcedureCode_id_ErrorIndication: + rc = ranap_handle_cl_err_ind(ctx, &message->msg.errorIndicationIEs); + break; + default: + rc = -1; + break; + } + break; + case RANAP_RANAP_PDU_PR_successfulOutcome: + case RANAP_RANAP_PDU_PR_unsuccessfulOutcome: + case RANAP_RANAP_PDU_PR_outcome: + default: + rc = -1; + break; + } + + if (rc) { + LOGP(DRANAP, LOGL_ERROR, "Error in cn_ranap_handle_cl (%d)\n", + rc); + /* TODO handling of the error? */ + } +} + +/*********************************************************************** + * Paging + ***********************************************************************/ + +/* Send a paging command down a given SUA link. tmsi and paging_cause are + * optional and may be passed NULL and 0, respectively, to disable their use. + * See enum RANAP_PagingCause. + * + * If TMSI is given, the IMSI is not sent over the air interface. Nevertheless, + * the IMSI is still required for resolution in the HNB-GW and/or(?) RNC. */ +static int iu_tx_paging_cmd(struct osmo_sccp_link *link, + const char *imsi, const uint32_t *tmsi, + bool is_ps, uint32_t paging_cause) +{ + struct msgb *msg; + msg = ranap_new_msg_paging_cmd(imsi, tmsi, is_ps? 1 : 0, paging_cause); + msg->l2h = msg->data; + return osmo_sccp_tx_unitdata_ranap(link, 1, 2, msg->data, + msgb_length(msg)); +} + +static int iu_page(const char *imsi, const uint32_t *tmsi_or_ptimsi, + uint16_t lac, uint8_t rac, bool is_ps) +{ + struct iu_rnc *rnc; + int pagings_sent = 0; + + if (tmsi_or_ptimsi) { + LOGP(DRANAP, LOGL_DEBUG, "%s: Looking for RNCs to page for IMSI %s" + " (paging will use %s %x)\n", + is_ps? "IuPS" : "IuCS", + imsi, + is_ps? "PTMSI" : "TMSI", + *tmsi_or_ptimsi); + } else { + LOGP(DRANAP, LOGL_DEBUG, "%s: Looking for RNCs to page for IMSI %s" + " (paging will use IMSI)\n", + is_ps? "IuPS" : "IuCS", + imsi + ); + } + + llist_for_each_entry(rnc, &rnc_list, entry) { + if (!rnc->link) { + /* Not actually connected, don't count it. */ + continue; + } + if (rnc->lac != lac) + continue; + if (is_ps && rnc->rac != rac) + continue; + + /* Found a match! */ + if (iu_tx_paging_cmd(rnc->link, imsi, tmsi_or_ptimsi, is_ps, 0) + == 0) { + LOGP(DRANAP, LOGL_DEBUG, + "%s: Paged for IMSI %s on RNC %d, on SUA link %p\n", + is_ps? "IuPS" : "IuCS", + imsi, rnc->rnc_id, rnc->link); + pagings_sent ++; + } + } + + /* Some logging... */ + if (pagings_sent > 0) { + LOGP(DRANAP, LOGL_DEBUG, + "%s: %d RNCs were paged for IMSI %s.\n", + is_ps? "IuPS" : "IuCS", + pagings_sent, imsi); + } + else { + if (is_ps) { + LOGP(DRANAP, LOGL_ERROR, "IuPS: Found no RNC to page for" + " LAC %d RAC %d (would have paged IMSI %s)\n", + lac, rac, imsi); + } + else { + LOGP(DRANAP, LOGL_ERROR, "IuCS: Found no RNC to page for" + " LAC %d (would have paged IMSI %s)\n", + lac, imsi); + } + } + + return pagings_sent; +} + +int iu_page_cs(const char *imsi, const uint32_t *tmsi, uint16_t lac) +{ + return iu_page(imsi, tmsi, lac, 0, false); +} + +int iu_page_ps(const char *imsi, const uint32_t *ptmsi, uint16_t lac, uint8_t rac) +{ + return iu_page(imsi, ptmsi, lac, rac, true); +} + + +/*********************************************************************** + * + ***********************************************************************/ + +int tx_unitdata(struct osmo_sccp_link *link); +int tx_conn_req(struct osmo_sccp_link *link, uint32_t conn_id); + +struct osmo_prim_hdr *make_conn_req(uint32_t conn_id); +struct osmo_prim_hdr *make_dt1_req(uint32_t conn_id, const uint8_t *data, unsigned int len); + +struct osmo_prim_hdr *make_conn_resp(struct osmo_scu_connect_param *param) +{ + struct msgb *msg = msgb_alloc(1024, "conn_resp"); + struct osmo_scu_prim *prim; + + prim = (struct osmo_scu_prim *) msgb_put(msg, sizeof(*prim)); + osmo_prim_init(&prim->oph, SCCP_SAP_USER, + OSMO_SCU_PRIM_N_CONNECT, + PRIM_OP_RESPONSE, msg); + memcpy(&prim->u.connect, param, sizeof(prim->u.connect)); + return &prim->oph; +} + +static int sccp_sap_up(struct osmo_prim_hdr *oph, void *link) +{ + struct osmo_scu_prim *prim = (struct osmo_scu_prim *) oph; + struct osmo_prim_hdr *resp = NULL; + int rc; + struct ue_conn_ctx *ue; + + DEBUGP(DIU, "sccp_sap_up(%s)\n", osmo_scu_prim_name(oph)); + + switch (OSMO_PRIM_HDR(oph)) { + case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_CONFIRM): + /* confirmation of outbound connection */ + rc = -1; + break; + case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_INDICATION): + /* indication of new inbound connection request*/ + DEBUGP(DIU, "N-CONNECT.ind(X->%u)\n", prim->u.connect.conn_id); + if (/* prim->u.connect.called_addr.ssn != OSMO_SCCP_SSN_RANAP || */ + !msgb_l2(oph->msg) || msgb_l2len(oph->msg) == 0) { + LOGP(DIU, LOGL_NOTICE, + "Received invalid N-CONNECT.ind\n"); + return 0; + } + ue = ue_conn_ctx_alloc(link, prim->u.connect.conn_id); + /* first ensure the local SUA/SCCP socket is ACTIVE */ + resp = make_conn_resp(&prim->u.connect); + osmo_sua_user_link_down(link, resp); + /* then handle the RANAP payload */ + rc = ranap_cn_rx_co(cn_ranap_handle_co, ue, msgb_l2(oph->msg), msgb_l2len(oph->msg)); + break; + case OSMO_PRIM(OSMO_SCU_PRIM_N_DISCONNECT, PRIM_OP_INDICATION): + /* indication of disconnect */ + DEBUGP(DIU, "N-DISCONNECT.ind(%u)\n", + prim->u.disconnect.conn_id); + ue = ue_conn_ctx_find(link, prim->u.disconnect.conn_id); + rc = ranap_cn_rx_co(cn_ranap_handle_co, ue, msgb_l2(oph->msg), msgb_l2len(oph->msg)); + break; + case OSMO_PRIM(OSMO_SCU_PRIM_N_DATA, PRIM_OP_INDICATION): + /* connection-oriented data received */ + DEBUGP(DIU, "N-DATA.ind(%u, %s)\n", prim->u.data.conn_id, + osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg))); + /* resolve UE context */ + ue = ue_conn_ctx_find(link, prim->u.data.conn_id); + rc = ranap_cn_rx_co(cn_ranap_handle_co, ue, msgb_l2(oph->msg), msgb_l2len(oph->msg)); + break; + case OSMO_PRIM(OSMO_SCU_PRIM_N_UNITDATA, PRIM_OP_INDICATION): + /* connection-less data received */ + DEBUGP(DIU, "N-UNITDATA.ind(%s)\n", + osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg))); + rc = ranap_cn_rx_cl(cn_ranap_handle_cl, link, msgb_l2(oph->msg), msgb_l2len(oph->msg)); + break; + default: + rc = -1; + break; + } + + msgb_free(oph->msg); + return rc; +} + +int iu_init(void *ctx, const char *listen_addr, uint16_t listen_port, + iu_recv_cb_t iu_recv_cb, iu_event_cb_t iu_event_cb) +{ + struct osmo_sccp_user *user; + talloc_iu_ctx = talloc_named_const(ctx, 1, "iu"); + talloc_asn1_ctx = talloc_named_const(talloc_iu_ctx, 1, "asn1"); + + global_iu_recv_cb = iu_recv_cb; + global_iu_event_cb = iu_event_cb; + osmo_sua_set_log_area(DSUA); + user = osmo_sua_user_create(talloc_iu_ctx, sccp_sap_up, talloc_iu_ctx); + return osmo_sua_server_listen(user, listen_addr, listen_port); +} + -- To view, visit https://gerrit.osmocom.org/192 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Iffc26f9c73cb15463948f7435b72ac1747aabdb3 Gerrit-PatchSet: 4 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Thu Aug 11 16:28:18 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 11 Aug 2016 16:28:18 +0000 Subject: [PATCH] openbsc[master]: add DIU logging category Message-ID: Review at https://gerrit.osmocom.org/687 add DIU logging category Will be used by upcoming iu.c Change-Id: Ic2f6bb1023377c24247521dde2d2bcf14f04cfe2 --- M openbsc/include/openbsc/debug.h M openbsc/src/libcommon/debug.c 2 files changed, 6 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/87/687/1 diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 43ebb19..58257df 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -36,6 +36,7 @@ DGTPHUB, DRANAP, DSUA, + DIU, Debug_LastEntry, }; diff --git a/openbsc/src/libcommon/debug.c b/openbsc/src/libcommon/debug.c index cf5beeb..18a8d37 100644 --- a/openbsc/src/libcommon/debug.c +++ b/openbsc/src/libcommon/debug.c @@ -175,6 +175,11 @@ .description = "SCCP User Adaptation Protocol", .enabled = 1, .loglevel = LOGL_DEBUG, }, + [DIU] = { + .name = "DIU", + .description = "Iu Protocol", + .enabled = 1, .loglevel = LOGL_DEBUG, + }, }; enum log_filter { -- To view, visit https://gerrit.osmocom.org/687 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ic2f6bb1023377c24247521dde2d2bcf14f04cfe2 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Thu Aug 11 16:28:44 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 11 Aug 2016 16:28:44 +0000 Subject: openbsc[master]: add libiu In-Reply-To: References: Message-ID: Patch Set 4: -Code-Review (1 comment) new patch set, removing -2 marking https://gerrit.osmocom.org/#/c/192/2/openbsc/src/libiu/iu.c File openbsc/src/libiu/iu.c: Line 57: * See iu_grnc_id_parse(). */ > i.e. add struct osmo_sccp_link to libosmo-sccp? let's look at this in perso As this drifts into the past, maybe we should take a look at this rather sooner than later? -- To view, visit https://gerrit.osmocom.org/192 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Iffc26f9c73cb15463948f7435b72ac1747aabdb3 Gerrit-PatchSet: 4 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 11 16:35:28 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 11 Aug 2016 16:35:28 +0000 Subject: [PATCH] openbsc[master]: add libiu In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/192 to look at the new patch set (#5). add libiu Co-Authored by dwillmann, laforge, nhofmeyr Change-Id: Iffc26f9c73cb15463948f7435b72ac1747aabdb3 --- M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/iu.h M openbsc/src/Makefile.am A openbsc/src/libiu/Makefile.am A openbsc/src/libiu/iu.c 6 files changed, 844 insertions(+), 3 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/92/192/5 diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 0980413..3d99cb8 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -203,6 +203,7 @@ src/libmgcp/Makefile src/libcommon/Makefile src/libfilter/Makefile + src/libiu/Makefile src/osmo-nitb/Makefile src/osmo-bsc/Makefile src/osmo-bsc_nat/Makefile diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index c272b14..2bca6b7 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,8 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h + gtphub.h \ + iu.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/iu.h b/openbsc/include/openbsc/iu.h new file mode 100644 index 0000000..d0ab540 --- /dev/null +++ b/openbsc/include/openbsc/iu.h @@ -0,0 +1,60 @@ +#pragma once + +#include + +struct sgsn_pdp_ctx; +struct msgb; +struct gprs_ra_id; + +struct RANAP_RAB_SetupOrModifiedItemIEs_s; +struct RANAP_GlobalRNC_ID; + +struct ue_conn_ctx { + struct llist_head list; + struct osmo_sccp_link *link; + uint32_t conn_id; + int integrity_active; + struct gprs_ra_id ra_id; +}; + +enum iu_event_type { + IU_EVENT_RAB_ASSIGN, + IU_EVENT_SECURITY_MODE_COMPLETE, + IU_EVENT_IU_RELEASE, /* An actual Iu Release message was received */ + IU_EVENT_LINK_INVALIDATED, /* A SUA link was lost or closed down */ + /* FIXME: maybe IU_EVENT_IU_RELEASE and IU_EVENT_LINK_INVALIDATED + * should be combined to one generic event that simply means the + * ue_conn_ctx should no longer be used, for whatever reason. */ +}; + +extern const struct value_string iu_event_type_names[]; +static inline const char *iu_event_type_str(enum iu_event_type e) +{ + return get_value_string(iu_event_type_names, e); +} + +/* Implementations of iu_recv_cb_t shall find the ue_conn_ctx in msg->dst. */ +typedef int (* iu_recv_cb_t )(struct msgb *msg, struct gprs_ra_id *ra_id, + /* TODO "gprs_" in generic CS+PS domain ^ */ + uint16_t *sai); + +typedef int (* iu_event_cb_t )(struct ue_conn_ctx *ue_ctx, + enum iu_event_type type, void *data); + +typedef int (* iu_rab_ass_resp_cb_t )(struct ue_conn_ctx *ue_ctx, uint8_t rab_id, + struct RANAP_RAB_SetupOrModifiedItemIEs_s *setup_ies); + +int iu_init(void *ctx, const char *listen_addr, uint16_t listen_port, + iu_recv_cb_t iu_recv_cb, iu_event_cb_t iu_event_cb); + +void iu_link_del(struct osmo_sccp_link *link); + +int iu_tx(struct msgb *msg, uint8_t sapi); + +int iu_page_cs(const char *imsi, const uint32_t *tmsi, uint16_t lac); +int iu_page_ps(const char *imsi, const uint32_t *ptmsi, uint16_t lac, uint8_t rac); + +int iu_rab_act(struct ue_conn_ctx *ue_ctx, struct msgb *msg); +int iu_rab_deact(struct ue_conn_ctx *ue_ctx, uint8_t rab_id); +int iu_tx_sec_mode_cmd(struct ue_conn_ctx *uectx, struct gsm_auth_tuple *tp, + int send_ck, int new_key); diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 6f6174e..4aa880f 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -2,9 +2,18 @@ AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(COVERAGE_CFLAGS) AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(COVERAGE_LDFLAGS) -SUBDIRS = libcommon libmgcp libbsc libmsc libtrau libfilter osmo-nitb osmo-bsc_mgcp utils ipaccess gprs +# Libraries +SUBDIRS = libcommon libmgcp libbsc libmsc libtrau libfilter -# Conditional modules +# Conditional Libraries +if BUILD_IU +SUBDIRS += libiu +endif + +# Programs +SUBDIRS += osmo-nitb osmo-bsc_mgcp utils ipaccess gprs + +# Conditional Programs if BUILD_NAT SUBDIRS += osmo-bsc_nat endif diff --git a/openbsc/src/libiu/Makefile.am b/openbsc/src/libiu/Makefile.am new file mode 100644 index 0000000..7b1ba4d --- /dev/null +++ b/openbsc/src/libiu/Makefile.am @@ -0,0 +1,10 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) +AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) \ + $(LIBOSMOGSM_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) $(LIBCRYPTO_CFLAGS) \ + $(LIBASN1C_CFLAGS) \ + $(LIBOSMOSIGTRAN_CFLAGS) $(LIBOSMORANAP_CFLAGS) + +noinst_LIBRARIES = libiu.a + +libiu_a_SOURCES = iu.c + diff --git a/openbsc/src/libiu/iu.c b/openbsc/src/libiu/iu.c new file mode 100644 index 0000000..a725346 --- /dev/null +++ b/openbsc/src/libiu/iu.c @@ -0,0 +1,760 @@ +/* Common parts of IuCS and IuPS interfaces implementation */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +/* Parsed global RNC id. See also struct RANAP_GlobalRNC_ID, and note that the + * PLMN identity is a BCD representation of the MCC and MNC. + * See iu_grnc_id_parse(). */ +struct iu_grnc_id { + uint16_t mcc; + uint16_t mnc; + uint16_t rnc_id; +}; + +/* A remote RNC (Radio Network Controller, like BSC but for UMTS) that has + * called us and is currently reachable at the given osmo_sccp_link. So, when we + * know a LAC for a subscriber, we can page it at the RNC matching that LAC or + * RAC. An HNB-GW typically presents itself as if it were a single RNC, even + * though it may have several RNCs in hNodeBs connected to it. Those will then + * share the same RNC id, which they actually receive and adopt from the HNB-GW + * in the HNBAP HNB REGISTER ACCEPT message. */ +struct iu_rnc { + struct llist_head entry; + + uint16_t rnc_id; + uint16_t lac; /* Location Area Code (used for CS and PS) */ + uint8_t rac; /* Routing Area Code (used for PS only) */ + struct osmo_sccp_link *link; +}; + +void *talloc_iu_ctx; + +int asn1_xer_print = 1; +void *talloc_asn1_ctx; + +iu_recv_cb_t global_iu_recv_cb = NULL; +iu_event_cb_t global_iu_event_cb = NULL; + +static LLIST_HEAD(ue_conn_ctx_list); +static LLIST_HEAD(rnc_list); + +const struct value_string iu_event_type_names[] = { +#define IU_EVT_STR(X) { X, #X } + IU_EVT_STR(IU_EVENT_RAB_ASSIGN), + IU_EVT_STR(IU_EVENT_SECURITY_MODE_COMPLETE), + IU_EVT_STR(IU_EVENT_IU_RELEASE), + IU_EVT_STR(IU_EVENT_LINK_INVALIDATED), +#undef IU_EVT_STR +}; + +struct ue_conn_ctx *ue_conn_ctx_alloc(struct osmo_sccp_link *link, uint32_t conn_id) +{ + struct ue_conn_ctx *ctx = talloc_zero(talloc_iu_ctx, struct ue_conn_ctx); + + ctx->link = link; + ctx->conn_id = conn_id; + llist_add(&ctx->list, &ue_conn_ctx_list); + + return ctx; +} + +struct ue_conn_ctx *ue_conn_ctx_find(struct osmo_sccp_link *link, + uint32_t conn_id) +{ + struct ue_conn_ctx *ctx; + + llist_for_each_entry(ctx, &ue_conn_ctx_list, list) { + if (ctx->link == link && ctx->conn_id == conn_id) + return ctx; + } + return NULL; +} + +static struct iu_rnc *iu_rnc_alloc(uint16_t rnc_id, uint16_t lac, uint8_t rac, + struct osmo_sccp_link *link) +{ + struct iu_rnc *rnc = talloc_zero(talloc_iu_ctx, struct iu_rnc); + + rnc->rnc_id = rnc_id; + rnc->lac = lac; + rnc->rac = rac; + rnc->link = link; + llist_add(&rnc->entry, &rnc_list); + + LOGP(DRANAP, LOGL_NOTICE, "New RNC %d (LAC=%d RAC=%d)\n", + rnc->rnc_id, rnc->lac, rnc->rac); + + return rnc; +} + +static struct iu_rnc *iu_rnc_register(uint16_t rnc_id, uint16_t lac, + uint8_t rac, struct osmo_sccp_link *link) +{ + struct iu_rnc *rnc; + llist_for_each_entry(rnc, &rnc_list, entry) { + if (rnc->rnc_id != rnc_id) + continue; + + /* We have this RNC Id registered already. Make sure that the + * details match. */ + + /* TODO should a mismatch be an error? */ + if (rnc->lac != lac || rnc->rac != rac) + LOGP(DRANAP, LOGL_NOTICE, "RNC %d changes its details:" + " LAC=%d RAC=%d --> LAC=%d RAC=%d\n", + rnc->rnc_id, rnc->lac, rnc->rac, + lac, rac); + rnc->lac = lac; + rnc->rac = rac; + + if (link && rnc->link != link) + LOGP(DRANAP, LOGL_NOTICE, "RNC %d on new link" + " (LAC=%d RAC=%d)\n", + rnc->rnc_id, rnc->lac, rnc->rac); + rnc->link = link; + return rnc; + } + + /* Not found, make a new one. */ + return iu_rnc_alloc(rnc_id, lac, rac, link); +} + +/* Discard/invalidate all ue_conn_ctx and iu_rnc entries that reference the + * given link, since this link is invalid and about to be deallocated. For + * each ue_conn_ctx, invoke the iu_event_cb_t with IU_EVENT_LINK_INVALIDATED. + */ +void iu_link_del(struct osmo_sccp_link *link) +{ + struct iu_rnc *rnc, *rnc_next; + llist_for_each_entry_safe(rnc, rnc_next, &rnc_list, entry) { + if (!rnc->link) + continue; + if (rnc->link != link) + continue; + rnc->link = NULL; + llist_del(&rnc->entry); + talloc_free(rnc); + } + + struct ue_conn_ctx *uec, *uec_next; + llist_for_each_entry_safe(uec, uec_next, &ue_conn_ctx_list, list) { + if (uec->link != link) + continue; + uec->link = NULL; + global_iu_event_cb(uec, IU_EVENT_LINK_INVALIDATED, NULL); + } +} + +/*********************************************************************** + * RANAP handling + ***********************************************************************/ + +int iu_rab_act(struct ue_conn_ctx *ue_ctx, struct msgb *msg) +{ + struct osmo_scu_prim *prim; + + /* wrap RANAP message in SCCP N-DATA.req */ + prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim)); + prim->u.data.conn_id = ue_ctx->conn_id; + osmo_prim_init(&prim->oph, + SCCP_SAP_USER, + OSMO_SCU_PRIM_N_DATA, + PRIM_OP_REQUEST, + msg); + return osmo_sua_user_link_down(ue_ctx->link, &prim->oph); +} + +int iu_rab_deact(struct ue_conn_ctx *ue_ctx, uint8_t rab_id) +{ + /* FIXME */ + return -1; +} + +int iu_tx_sec_mode_cmd(struct ue_conn_ctx *uectx, struct gsm_auth_tuple *tp, + int send_ck, int new_key) +{ + struct osmo_scu_prim *prim; + struct msgb *msg; + uint8_t ik[16]; + uint8_t ck[16]; + unsigned int i; + + /* C5 function to derive IK from Kc */ + for (i = 0; i < 4; i++) + ik[i] = tp->vec.kc[i] ^ tp->vec.kc[i+4]; + memcpy(ik+4, tp->vec.kc, 8); + for (i = 12; i < 16; i++) + ik[i] = ik[i-12]; + + if (send_ck) { + /* C4 function to derive CK from Kc */ + memcpy(ck, tp->vec.kc, 8); + memcpy(ck+8, tp->vec.kc, 8); + } + + /* create RANAP message */ + msg = ranap_new_msg_sec_mod_cmd(ik, send_ck? ck : NULL, new_key ? RANAP_KeyStatus_new : RANAP_KeyStatus_old); + msg->l2h = msg->data; + /* wrap RANAP message in SCCP N-DATA.req */ + prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim)); + prim->u.data.conn_id = uectx->conn_id; + osmo_prim_init(&prim->oph, SCCP_SAP_USER, + OSMO_SCU_PRIM_N_DATA, + PRIM_OP_REQUEST, msg); + osmo_sua_user_link_down(uectx->link, &prim->oph); + + return 0; +} + +static int iu_grnc_id_parse(struct iu_grnc_id *dst, + struct RANAP_GlobalRNC_ID *src) +{ + /* The size is coming from arbitrary sender, check it gracefully */ + if (src->pLMNidentity.size != 3) { + LOGP(DRANAP, LOGL_ERROR, "Invalid PLMN Identity size:" + " should be 3, is %d\n", src->pLMNidentity.size); + return -1; + } + gsm48_mcc_mnc_from_bcd(&src->pLMNidentity.buf[0], + &dst->mcc, &dst->mnc); + dst->rnc_id = (uint16_t)src->rNC_ID; + return 0; +} + +#if 0 + -- not used at present -- +static int iu_grnc_id_compose(struct iu_grnc_id *src, + struct RANAP_GlobalRNC_ID *dst) +{ + /* The caller must ensure proper size */ + OSMO_ASSERT(dst->pLMNidentity.size == 3); + gsm48_mcc_mnc_to_bcd(&dst->pLMNidentity.buf[0], + src->mcc, src->mnc); + dst->rNC_ID = src->rnc_id; + return 0; +} +#endif + +static int ranap_handle_co_initial_ue(void *ctx, RANAP_InitialUE_MessageIEs_t *ies) +{ + struct ue_conn_ctx *ue_conn = ctx; + struct gprs_ra_id ra_id; + struct iu_grnc_id grnc_id; + uint16_t sai; + struct msgb *msg = msgb_alloc(256, "RANAP->NAS"); + + if (ranap_parse_lai(&ra_id, &ies->lai) != 0) { + LOGP(DRANAP, LOGL_ERROR, "Failed to parse RANAP LAI IE\n"); + return -1; + } + + if (ies->presenceMask & INITIALUE_MESSAGEIES_RANAP_RAC_PRESENT) { + ra_id.rac = asn1str_to_u8(&ies->rac); + } + + if (iu_grnc_id_parse(&grnc_id, &ies->globalRNC_ID) != 0) { + LOGP(DRANAP, LOGL_ERROR, + "Failed to parse RANAP Global-RNC-ID IE\n"); + return -1; + } + + sai = asn1str_to_u16(&ies->sai.sAC); + msgb_gmmh(msg) = msgb_put(msg, ies->nas_pdu.size); + memcpy(msgb_gmmh(msg), ies->nas_pdu.buf, ies->nas_pdu.size); + + /* Make sure we know the RNC Id and LAC+RAC coming in on this connection. */ + iu_rnc_register(grnc_id.rnc_id, ra_id.lac, ra_id.rac, ue_conn->link); + ue_conn->ra_id = ra_id; + + /* Feed into the MM layer */ + msg->dst = ctx; + global_iu_recv_cb(msg, &ra_id, &sai); + + msgb_free(msg); + + return 0; +} + +static int ranap_handle_co_dt(void *ctx, RANAP_DirectTransferIEs_t *ies) +{ + struct gprs_ra_id _ra_id, *ra_id = NULL; + uint16_t _sai, *sai = NULL; + struct msgb *msg = msgb_alloc(256, "RANAP->NAS"); + + if (ies->presenceMask & DIRECTTRANSFERIES_RANAP_LAI_PRESENT) { + if (ranap_parse_lai(&_ra_id, &ies->lai) != 0) { + LOGP(DRANAP, LOGL_ERROR, "Failed to parse RANAP LAI IE\n"); + return -1; + } + ra_id = &_ra_id; + if (ies->presenceMask & DIRECTTRANSFERIES_RANAP_RAC_PRESENT) { + _ra_id.rac = asn1str_to_u8(&ies->rac); + } + if (ies->presenceMask & DIRECTTRANSFERIES_RANAP_SAI_PRESENT) { + _sai = asn1str_to_u16(&ies->sai.sAC); + sai = &_sai; + } + } + + msgb_gmmh(msg) = msgb_put(msg, ies->nas_pdu.size); + memcpy(msgb_gmmh(msg), ies->nas_pdu.buf, ies->nas_pdu.size); + + /* Feed into the MM/CC/SMS-CP layer */ + msg->dst = ctx; + global_iu_recv_cb(msg, ra_id, sai); + + msgb_free(msg); + + return 0; +} + +static int ranap_handle_co_err_ind(void *ctx, RANAP_ErrorIndicationIEs_t *ies) +{ + if (ies->presenceMask & ERRORINDICATIONIES_RANAP_CAUSE_PRESENT) + LOGP(DRANAP, LOGL_ERROR, "Rx Error Indication (%s)\n", + ranap_cause_str(&ies->cause)); + else + LOGP(DRANAP, LOGL_ERROR, "Rx Error Indication\n"); + + return 0; +} + +int iu_tx(struct msgb *msg_nas, uint8_t sapi) +{ + struct ue_conn_ctx *uectx = msg_nas->dst; + struct msgb *msg; + struct osmo_scu_prim *prim; + + LOGP(DRANAP, LOGL_INFO, "Transmitting L3 Message as RANAP DT (SUA link %p conn_id %u)\n", + uectx->link, uectx->conn_id); + + msg = ranap_new_msg_dt(sapi, msg_nas->data, msgb_length(msg_nas)); + msgb_free(msg_nas); + msg->l2h = msg->data; + prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim)); + prim->u.data.conn_id = uectx->conn_id; + osmo_prim_init(&prim->oph, SCCP_SAP_USER, + OSMO_SCU_PRIM_N_DATA, + PRIM_OP_REQUEST, msg); + osmo_sua_user_link_down(uectx->link, &prim->oph); + return 0; +} + +static int ranap_handle_co_iu_rel_req(struct ue_conn_ctx *ctx, RANAP_Iu_ReleaseRequestIEs_t *ies) +{ + struct msgb *msg; + struct osmo_scu_prim *prim; + + LOGP(DRANAP, LOGL_INFO, "Received Iu Release Request, Sending Release Command\n"); + msg = ranap_new_msg_iu_rel_cmd(&ies->cause); + msg->l2h = msg->data; + prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim)); + prim->u.data.conn_id = ctx->conn_id; + osmo_prim_init(&prim->oph, SCCP_SAP_USER, + OSMO_SCU_PRIM_N_DATA, + PRIM_OP_REQUEST, msg); + osmo_sua_user_link_down(ctx->link, &prim->oph); + return 0; +} + +static int ranap_handle_co_rab_ass_resp(struct ue_conn_ctx *ctx, RANAP_RAB_AssignmentResponseIEs_t *ies) +{ + int rc = -1; + + LOGP(DRANAP, LOGL_INFO, "RAB Asignment Response:"); + if (ies->presenceMask & RAB_ASSIGNMENTRESPONSEIES_RANAP_RAB_SETUPORMODIFIEDLIST_PRESENT) { + /* TODO: Iterate over list of SetupOrModifiedList IEs and handle each one */ + RANAP_IE_t *ranap_ie = ies->raB_SetupOrModifiedList.raB_SetupOrModifiedList_ies.list.array[0]; + RANAP_RAB_SetupOrModifiedItemIEs_t setup_ies; + + rc = ranap_decode_rab_setupormodifieditemies_fromlist(&setup_ies, &ranap_ie->value); + if (rc) { + LOGP(DRANAP, LOGL_ERROR, "Error in ranap_decode_rab_setupormodifieditemies()\n"); + return rc; + } + + rc = global_iu_event_cb(ctx, IU_EVENT_RAB_ASSIGN, &setup_ies); + + ranap_free_rab_setupormodifieditemies(&setup_ies); + } + + LOGPC(DRANAP, LOGL_INFO, "\n"); + + return rc; +} + +/* Entry point for connection-oriented RANAP message */ +static void cn_ranap_handle_co(void *ctx, ranap_message *message) +{ + int rc; + + LOGP(DRANAP, LOGL_NOTICE, "handle_co(dir=%u, proc=%u)\n", message->direction, message->procedureCode); + + switch (message->direction) { + case RANAP_RANAP_PDU_PR_initiatingMessage: + switch (message->procedureCode) { + case RANAP_ProcedureCode_id_InitialUE_Message: + rc = ranap_handle_co_initial_ue(ctx, &message->msg.initialUE_MessageIEs); + break; + case RANAP_ProcedureCode_id_DirectTransfer: + rc = ranap_handle_co_dt(ctx, &message->msg.directTransferIEs); + break; + case RANAP_ProcedureCode_id_ErrorIndication: + rc = ranap_handle_co_err_ind(ctx, &message->msg.errorIndicationIEs); + break; + case RANAP_ProcedureCode_id_Iu_ReleaseRequest: + /* Iu Release Request */ + rc = ranap_handle_co_iu_rel_req(ctx, &message->msg.iu_ReleaseRequestIEs); + break; + default: + LOGP(DRANAP, LOGL_ERROR, "Received Initiating Message: unknown Procedure Code %d\n", + message->procedureCode); + rc = -1; + break; + } + break; + case RANAP_RANAP_PDU_PR_successfulOutcome: + switch (message->procedureCode) { + case RANAP_ProcedureCode_id_SecurityModeControl: + /* Security Mode Complete */ + rc = global_iu_event_cb(ctx, IU_EVENT_SECURITY_MODE_COMPLETE, NULL); + break; + case RANAP_ProcedureCode_id_Iu_Release: + /* Iu Release Complete */ + rc = global_iu_event_cb(ctx, IU_EVENT_IU_RELEASE, NULL); + if (rc) { + LOGP(DRANAP, LOGL_ERROR, "Iu Release event: Iu Event callback returned %d\n", + rc); + } + break; + default: + LOGP(DRANAP, LOGL_ERROR, "Received Successful Outcome: unknown Procedure Code %d\n", + message->procedureCode); + rc = -1; + break; + } + break; + case RANAP_RANAP_PDU_PR_outcome: + switch (message->procedureCode) { + case RANAP_ProcedureCode_id_RAB_Assignment: + /* RAB Assignment Response */ + rc = ranap_handle_co_rab_ass_resp(ctx, &message->msg.raB_AssignmentResponseIEs); + break; + default: + LOGP(DRANAP, LOGL_ERROR, "Received Outcome: unknown Procedure Code %d\n", + message->procedureCode); + rc = -1; + break; + } + break; + case RANAP_RANAP_PDU_PR_unsuccessfulOutcome: + default: + LOGP(DRANAP, LOGL_ERROR, "Received Unsuccessful Outcome: Procedure Code %d\n", + message->procedureCode); + rc = -1; + break; + } + + if (rc) { + LOGP(DRANAP, LOGL_ERROR, "Error in cn_ranap_handle_co (%d)\n", + rc); + /* TODO handling of the error? */ + } +} + +static int ranap_handle_cl_reset_req(void *ctx, RANAP_ResetIEs_t *ies) +{ + /* FIXME: send reset response */ + return -1; +} + +static int ranap_handle_cl_err_ind(void *ctx, RANAP_ErrorIndicationIEs_t *ies) +{ + if (ies->presenceMask & ERRORINDICATIONIES_RANAP_CAUSE_PRESENT) + LOGP(DRANAP, LOGL_ERROR, "Rx Error Indication (%s)\n", + ranap_cause_str(&ies->cause)); + else + LOGP(DRANAP, LOGL_ERROR, "Rx Error Indication\n"); + + return 0; +} + +/* Entry point for connection-less RANAP message */ +static void cn_ranap_handle_cl(void *ctx, ranap_message *message) +{ + int rc; + + switch (message->direction) { + case RANAP_RANAP_PDU_PR_initiatingMessage: + switch (message->procedureCode) { + case RANAP_ProcedureCode_id_Reset: + /* received reset.req, send reset.resp */ + rc = ranap_handle_cl_reset_req(ctx, &message->msg.resetIEs); + break; + case RANAP_ProcedureCode_id_ErrorIndication: + rc = ranap_handle_cl_err_ind(ctx, &message->msg.errorIndicationIEs); + break; + default: + rc = -1; + break; + } + break; + case RANAP_RANAP_PDU_PR_successfulOutcome: + case RANAP_RANAP_PDU_PR_unsuccessfulOutcome: + case RANAP_RANAP_PDU_PR_outcome: + default: + rc = -1; + break; + } + + if (rc) { + LOGP(DRANAP, LOGL_ERROR, "Error in cn_ranap_handle_cl (%d)\n", + rc); + /* TODO handling of the error? */ + } +} + +/*********************************************************************** + * Paging + ***********************************************************************/ + +/* Send a paging command down a given SUA link. tmsi and paging_cause are + * optional and may be passed NULL and 0, respectively, to disable their use. + * See enum RANAP_PagingCause. + * + * If TMSI is given, the IMSI is not sent over the air interface. Nevertheless, + * the IMSI is still required for resolution in the HNB-GW and/or(?) RNC. */ +static int iu_tx_paging_cmd(struct osmo_sccp_link *link, + const char *imsi, const uint32_t *tmsi, + bool is_ps, uint32_t paging_cause) +{ + struct msgb *msg; + msg = ranap_new_msg_paging_cmd(imsi, tmsi, is_ps? 1 : 0, paging_cause); + msg->l2h = msg->data; + return osmo_sccp_tx_unitdata_ranap(link, 1, 2, msg->data, + msgb_length(msg)); +} + +static int iu_page(const char *imsi, const uint32_t *tmsi_or_ptimsi, + uint16_t lac, uint8_t rac, bool is_ps) +{ + struct iu_rnc *rnc; + int pagings_sent = 0; + + if (tmsi_or_ptimsi) { + LOGP(DRANAP, LOGL_DEBUG, "%s: Looking for RNCs to page for IMSI %s" + " (paging will use %s %x)\n", + is_ps? "IuPS" : "IuCS", + imsi, + is_ps? "PTMSI" : "TMSI", + *tmsi_or_ptimsi); + } else { + LOGP(DRANAP, LOGL_DEBUG, "%s: Looking for RNCs to page for IMSI %s" + " (paging will use IMSI)\n", + is_ps? "IuPS" : "IuCS", + imsi + ); + } + + llist_for_each_entry(rnc, &rnc_list, entry) { + if (!rnc->link) { + /* Not actually connected, don't count it. */ + continue; + } + if (rnc->lac != lac) + continue; + if (is_ps && rnc->rac != rac) + continue; + + /* Found a match! */ + if (iu_tx_paging_cmd(rnc->link, imsi, tmsi_or_ptimsi, is_ps, 0) + == 0) { + LOGP(DRANAP, LOGL_DEBUG, + "%s: Paged for IMSI %s on RNC %d, on SUA link %p\n", + is_ps? "IuPS" : "IuCS", + imsi, rnc->rnc_id, rnc->link); + pagings_sent ++; + } + } + + /* Some logging... */ + if (pagings_sent > 0) { + LOGP(DRANAP, LOGL_DEBUG, + "%s: %d RNCs were paged for IMSI %s.\n", + is_ps? "IuPS" : "IuCS", + pagings_sent, imsi); + } + else { + if (is_ps) { + LOGP(DRANAP, LOGL_ERROR, "IuPS: Found no RNC to page for" + " LAC %d RAC %d (would have paged IMSI %s)\n", + lac, rac, imsi); + } + else { + LOGP(DRANAP, LOGL_ERROR, "IuCS: Found no RNC to page for" + " LAC %d (would have paged IMSI %s)\n", + lac, imsi); + } + } + + return pagings_sent; +} + +int iu_page_cs(const char *imsi, const uint32_t *tmsi, uint16_t lac) +{ + return iu_page(imsi, tmsi, lac, 0, false); +} + +int iu_page_ps(const char *imsi, const uint32_t *ptmsi, uint16_t lac, uint8_t rac) +{ + return iu_page(imsi, ptmsi, lac, rac, true); +} + + +/*********************************************************************** + * + ***********************************************************************/ + +int tx_unitdata(struct osmo_sccp_link *link); +int tx_conn_req(struct osmo_sccp_link *link, uint32_t conn_id); + +struct osmo_prim_hdr *make_conn_req(uint32_t conn_id); +struct osmo_prim_hdr *make_dt1_req(uint32_t conn_id, const uint8_t *data, unsigned int len); + +struct osmo_prim_hdr *make_conn_resp(struct osmo_scu_connect_param *param) +{ + struct msgb *msg = msgb_alloc(1024, "conn_resp"); + struct osmo_scu_prim *prim; + + prim = (struct osmo_scu_prim *) msgb_put(msg, sizeof(*prim)); + osmo_prim_init(&prim->oph, SCCP_SAP_USER, + OSMO_SCU_PRIM_N_CONNECT, + PRIM_OP_RESPONSE, msg); + memcpy(&prim->u.connect, param, sizeof(prim->u.connect)); + return &prim->oph; +} + +static int sccp_sap_up(struct osmo_prim_hdr *oph, void *link) +{ + struct osmo_scu_prim *prim = (struct osmo_scu_prim *) oph; + struct osmo_prim_hdr *resp = NULL; + int rc; + struct ue_conn_ctx *ue; + + DEBUGP(DIU, "sccp_sap_up(%s)\n", osmo_scu_prim_name(oph)); + + switch (OSMO_PRIM_HDR(oph)) { + case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_CONFIRM): + /* confirmation of outbound connection */ + rc = -1; + break; + case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_INDICATION): + /* indication of new inbound connection request*/ + DEBUGP(DIU, "N-CONNECT.ind(X->%u)\n", prim->u.connect.conn_id); + if (/* prim->u.connect.called_addr.ssn != OSMO_SCCP_SSN_RANAP || */ + !msgb_l2(oph->msg) || msgb_l2len(oph->msg) == 0) { + LOGP(DIU, LOGL_NOTICE, + "Received invalid N-CONNECT.ind\n"); + return 0; + } + ue = ue_conn_ctx_alloc(link, prim->u.connect.conn_id); + /* first ensure the local SUA/SCCP socket is ACTIVE */ + resp = make_conn_resp(&prim->u.connect); + osmo_sua_user_link_down(link, resp); + /* then handle the RANAP payload */ + rc = ranap_cn_rx_co(cn_ranap_handle_co, ue, msgb_l2(oph->msg), msgb_l2len(oph->msg)); + break; + case OSMO_PRIM(OSMO_SCU_PRIM_N_DISCONNECT, PRIM_OP_INDICATION): + /* indication of disconnect */ + DEBUGP(DIU, "N-DISCONNECT.ind(%u)\n", + prim->u.disconnect.conn_id); + ue = ue_conn_ctx_find(link, prim->u.disconnect.conn_id); + rc = ranap_cn_rx_co(cn_ranap_handle_co, ue, msgb_l2(oph->msg), msgb_l2len(oph->msg)); + break; + case OSMO_PRIM(OSMO_SCU_PRIM_N_DATA, PRIM_OP_INDICATION): + /* connection-oriented data received */ + DEBUGP(DIU, "N-DATA.ind(%u, %s)\n", prim->u.data.conn_id, + osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg))); + /* resolve UE context */ + ue = ue_conn_ctx_find(link, prim->u.data.conn_id); + rc = ranap_cn_rx_co(cn_ranap_handle_co, ue, msgb_l2(oph->msg), msgb_l2len(oph->msg)); + break; + case OSMO_PRIM(OSMO_SCU_PRIM_N_UNITDATA, PRIM_OP_INDICATION): + /* connection-less data received */ + DEBUGP(DIU, "N-UNITDATA.ind(%s)\n", + osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg))); + rc = ranap_cn_rx_cl(cn_ranap_handle_cl, link, msgb_l2(oph->msg), msgb_l2len(oph->msg)); + break; + default: + rc = -1; + break; + } + + msgb_free(oph->msg); + return rc; +} + +int iu_init(void *ctx, const char *listen_addr, uint16_t listen_port, + iu_recv_cb_t iu_recv_cb, iu_event_cb_t iu_event_cb) +{ + struct osmo_sccp_user *user; + talloc_iu_ctx = talloc_named_const(ctx, 1, "iu"); + talloc_asn1_ctx = talloc_named_const(talloc_iu_ctx, 1, "asn1"); + + global_iu_recv_cb = iu_recv_cb; + global_iu_event_cb = iu_event_cb; + osmo_sua_set_log_area(DSUA); + user = osmo_sua_user_create(talloc_iu_ctx, sccp_sap_up, talloc_iu_ctx); + return osmo_sua_server_listen(user, listen_addr, listen_port); +} + -- To view, visit https://gerrit.osmocom.org/192 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Iffc26f9c73cb15463948f7435b72ac1747aabdb3 Gerrit-PatchSet: 5 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Fri Aug 12 05:33:50 2016 From: gerrit-no-reply at lists.osmocom.org (pravin) Date: Fri, 12 Aug 2016 05:33:50 +0000 Subject: osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Patch Set 16: (1 comment) https://gerrit.osmocom.org/#/c/416/15/tests/bitcomp/BitcompTest.cpp File tests/bitcomp/BitcompTest.cpp: Line 35: int verify; > Use C99 initializers I am about to change like this( {.crbb_len = 67, .cc = 1, .crbb_data = {0x02, 0x0c, 0xa0, 0x30, 0xcb, 0x1a, 0x0c, 0xe3, 0x6c} ) IS this what you meant? -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 16 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: pravin Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Fri Aug 12 10:06:52 2016 From: gerrit-no-reply at lists.osmocom.org (pravin) Date: Fri, 12 Aug 2016 10:06:52 +0000 Subject: [PATCH] osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Hello Max, Neels Hofmeyr, Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/416 to look at the new patch set (#17). Add decoding of compressed bitmap in EPDAN Implemented tree based algorithm to decode compressed bitmap in EPDAN as described in section 9.1.10 of 3GPP 44.060. This algorithm intends to improve the performance over existing method. New Regression test is added under bitcomp directory. Test case is added to validate decompressed result of the bitmap Present in EPDAN. Test is done for multiple bitmaps of varying length. Invalid inputs are also part of the test vector. Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce --- M src/Makefile.am M src/decoding.cpp A src/egprs_rlc_compression.cpp A src/egprs_rlc_compression.h M tests/Makefile.am A tests/bitcomp/BitcompTest A tests/bitcomp/BitcompTest.cpp A tests/bitcomp/BitcompTest.err A tests/bitcomp/BitcompTest.ok M tests/testsuite.at 10 files changed, 731 insertions(+), 18 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/16/416/17 diff --git a/src/Makefile.am b/src/Makefile.am index 9bdec2f..9b047e7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -62,7 +62,8 @@ rlc.cpp \ osmobts_sock.cpp \ gprs_codel.c \ - gprs_coding_scheme.cpp + gprs_coding_scheme.cpp \ + egprs_rlc_compression.cpp bin_PROGRAMS = \ osmo-pcu @@ -94,7 +95,8 @@ pcu_utils.h \ cxx_linuxlist.h \ gprs_codel.h \ - gprs_coding_scheme.h + gprs_coding_scheme.h \ + egprs_rlc_compression.h osmo_pcu_SOURCES = pcu_main.cpp diff --git a/src/decoding.cpp b/src/decoding.cpp index 7c00ff7..2b00a07 100644 --- a/src/decoding.cpp +++ b/src/decoding.cpp @@ -20,6 +20,7 @@ #include #include #include +#include extern "C" { #include @@ -652,10 +653,10 @@ int num_blocks = 0; struct bitvec urbb; int i; + int rc; bool have_bitmap; int implicitly_acked_blocks; int ssn = desc->STARTING_SEQUENCE_NUMBER; - int rc; if (desc->FINAL_ACK_INDICATION) return handle_final_ack(bits, bsn_begin, bsn_end, window); @@ -695,24 +696,20 @@ if (crbb_len > 0) { int old_len = bits->cur_bit; - struct bitvec crbb; - crbb.data = (uint8_t *)desc->CRBB; - crbb.data_len = sizeof(desc->CRBB); - crbb.cur_bit = desc->CRBB_LENGTH; - - rc = osmo_t4_decode(&crbb, desc->CRBB_STARTING_COLOR_CODE, - bits); - + LOGP(DRLCMACDL, LOGL_DEBUG, "Compress bitmap exist," + "CRBB LEN =%d and Starting color code =%d", + desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE); + rc = decompress_crbb(desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE, + desc->CRBB, bits); if (rc < 0) { LOGP(DRLCMACUL, LOGL_NOTICE, - "Failed to decode CRBB: " - "length %d, data '%s'\n", - desc->CRBB_LENGTH, - osmo_hexdump(crbb.data, crbb.data_len)); + "Failed to decode CRBB: length %d, data '%s'\n", + desc->CRBB_LENGTH, osmo_hexdump( + desc->CRBB, (desc->CRBB_LENGTH + 7)/8)); /* We don't know the SSN offset for the URBB, - * return what we have so far and assume the - * bitmap has stopped here */ + * return what we have so far and assume the + * bitmap has stopped here */ goto aborted; } diff --git a/src/egprs_rlc_compression.cpp b/src/egprs_rlc_compression.cpp new file mode 100644 index 0000000..e18dc20 --- /dev/null +++ b/src/egprs_rlc_compression.cpp @@ -0,0 +1,340 @@ +/* egprs_rlc_compression.h +* Routines for EGPRS RLC bitmap compression handling +*/ +#include +#include +#include + +extern "C" { +#include +#include +#include +} + +egprs_compress *egprs_compress::s_instance = 0; + +/* Function to create tree node */ +Node *egprs_compress::create_tree_node() +{ + Node *new_node; + + new_node = talloc_zero(tall_tree_ctx, Node); + new_node->left = NULL; + new_node->right = NULL; + new_node->run_length = -1; + return new_node; +} + +/* Function to build the codeword tree + * \param iter[in] Iterate the node on the tree + * \param len[in] Length of the code word + * \param i[in] Iterator + * \param idx[in] Iterate index of the code word table + */ +void egprs_compress::build_codeword(Node *root, const char *cdwd[]) +{ + Node *iter; + int len; + int i; + int idx; + + root->left = NULL; + root->right = NULL; + root->run_length = -1; + + for (idx = 0; idx < MAX_CDWDTBL_LEN; idx++) { + len = strlen((const char *)cdwd[idx]); + iter = root; + for (i = 0; i < len; i++) { + if (cdwd[idx][i] == '0') { + if (!iter->left) + iter->left = create_tree_node(); + iter = iter->left; + } else if (cdwd[idx][i] == '1') { + if (!iter->right) + iter->right = create_tree_node(); + iter = iter->right; + } + } + if (iter) { + if (idx < 64) + (iter->run_length) = idx; + else + (iter->run_length) = (idx - 63) * 64; + } + } +} + +const char *one_run_len_code_list[MAX_CDWDTBL_LEN] = { + "00110101", + "000111", + "0111", + "1000", + "1011", + "1100", + "1110", + "1111", + "10011", + "10100", + "00111", + "01000", + "001000", + "000011", + "110100", + "110101", + "101010", + "101011", + "0100111", + "0001100", + "0001000", + "0010111", + "0000011", + "0000100", + "0101000", + "0101011", + "0010011", + "0100100", + "0011000", + "00000010", + "00000011", + "00011010", + "00011011", + "00010010", + "00010011", + "00010100", + "00010101", + "00010110", + "00010111", + "00101000", + "00101001", + "00101010", + "00101011", + "00101100", + "00101101", + "00000100", + "00000101", + "00001010", + "00001011", + "01010010", + "01010011", + "01010100", + "01010101", + "00100100", + "00100101", + "01011000", + "01011001", + "01011010", + "01011011", + "01001010", + "01001011", + "00110010", + "00110011", + "00110100", + "11011", + "10010", + "010111", + "0110111", + "00110110", + "00110111", + "01100100", + "01100101", + "01101000", + "01100111", + "011001100", + "011001101", + "011010010", + "011010011", + "011010100" +}; + +const char *zero_run_len_code_list[MAX_CDWDTBL_LEN] = { + "0000110111", + "10", + "11", + "010", + "011", + "0011", + "0010", + "00011", + "000101", + "000100", + "0000100", + "0000101", + "0000111", + "00000100", + "00000111", + "000011000", + "0000010111", + "0000011000", + "0000001000", + "00001100111", + "00001101000", + "00001101100", + "00000110111", + "00000101000", + "00000010111", + "00000011000", + "000011001010", + "000011001011", + "000011001100", + "000011001101", + "000001101000", + "000001101001", + "000001101010", + "000001101011", + "000011010010", + "000011010011", + "000011010100", + "000011010101", + "000011010110", + "000011010111", + "000001101100", + "000001101101", + "000011011010", + "000011011011", + "000001010100", + "000001010101", + "000001010110", + "000001010111", + "000001100100", + "000001100101", + "000001010010", + "000001010011", + "000000100100", + "000000110111", + "000000111000", + "000000100111", + "000000101000", + "000001011000", + "000001011001", + "000000101011", + "000000101100", + "000001011010", + "000001100110", + "000001100111", + "0000001111", + "000011001000", + "000011001001", + "000001011011", + "000000110011", + "000000110100", + "000000110101", + "0000001101100", + "0000001101101", + "0000001001010", + "0000001001011", + "0000001001100", + "0000001001101", + "0000001110010", + "0000001110011" +}; + +/* search_runlen function will return the runlength for the codeword + * \param root[in] Root of Ones or Zeros tree + * \param bmbuf[in] Recevied compressed bitmap buf + * \param bit_pos[in] The start bit pos to read codeword + * \param len_codewd[in] Length of code word + * \param rlen[out] Run length value + */ +static int search_runlen( + Node *root, + const uint8_t *bmbuf, + uint8_t bit_pos, + uint8_t *len_codewd, + uint16_t *rlen) +{ + Node *iter; + uint8_t dir; + + iter = root; + *len_codewd = 0; + + while (iter->run_length == -1) { + if ((!iter->left) && (!iter->right)) + return -1; + /* get the bit value at the bitpos and put it in right most of dir */ + dir = ((bmbuf[BITS_TO_BYTES(bit_pos)-1] + >>(7-(MOD8(bit_pos)))) & 0x01); + (bit_pos)++; + (*len_codewd)++; + if (((dir&0x01) == 0) && (iter->left != NULL)) + iter = iter->left; + else if (((dir&0x01) == 1) && (iter->right != NULL)) + iter = iter->right; + else + return -1; + } + (*rlen) = (iter->run_length); + return 1; +} + +/* Function to decompress crbb + * \param[in] Compressed bitmap length + * \clr_code_bit[in] Color code 1 for Ones runlength 0 for Zero runlength + * \orig_crbb_buf[in] Received block crbb bitmap + * \dest[out] Uncompressed bitvector + */ +int decompress_crbb( + int8_t compress_bmap_len, + uint8_t clr_code_bit, + const uint8_t *orig_crbb_buf, + bitvec *dest) +{ + + uint8_t bit_pos = 0; + uint8_t data = 0x0; + node *list = NULL; + uint8_t nbits = 0; /* number of bits of codeword */ + uint16_t run_length = 0; + uint16_t cbmaplen = 0; /* compressed bitmap part after decompression */ + unsigned wp = dest->cur_bit; + int rc = 0; + egprs_compress *compress = egprs_compress::instance(); + + while (compress_bmap_len > 0) { + if (clr_code_bit == 1) { + data = 0xff; + list = compress->ones_list; + } else { + data = 0x00; + list = compress->zeros_list; + } + rc = search_runlen(list, orig_crbb_buf, + bit_pos, &nbits, &run_length); + if (rc == -1) + return -1; + /* If run length > 64, need makeup and terminating code */ + if (run_length < 64) + clr_code_bit ? clr_code_bit = 0 : clr_code_bit = 1; + cbmaplen = cbmaplen + run_length; + /* put run length of Ones in uncompressed bitmap */ + while (run_length != 0) { + if (run_length > 8) { + bitvec_write_field(dest, wp, data, 8); + run_length = run_length - 8; + } else { + bitvec_write_field(dest, wp, data, run_length); + run_length = 0; + } + } + bit_pos = bit_pos + nbits; + compress_bmap_len = compress_bmap_len - nbits; + } + return 0; +} + +/* init function to build codeword */ +int egprs_compress::decode_tree_init() +{ + tall_tree_ctx = talloc_named_const(tall_pcu_ctx, 0, + "decode-tree context"); + if (!tall_tree_ctx) + return -ENOMEM; + ones_list = talloc(tall_tree_ctx, Node); + zeros_list = talloc(tall_tree_ctx, Node); + build_codeword( + ones_list, one_run_len_code_list); + build_codeword( + zeros_list, zero_run_len_code_list); + return 0; +} diff --git a/src/egprs_rlc_compression.h b/src/egprs_rlc_compression.h new file mode 100644 index 0000000..de1b2d2 --- /dev/null +++ b/src/egprs_rlc_compression.h @@ -0,0 +1,62 @@ +/* egprs_rlc_compression.h + * Routines for EGPRS RLC bitmap compression handling + */ +#include +#include + +extern "C" { +#include +} + +#include +#include +#include + +#define MAX_CDWDTBL_LEN 79 /* total number of codewords */ +#define BITS_TO_BYTES(X) ((X ? (X/8):0)+1) +#define MOD8(X) (((X)+8) & (0x07)) + +typedef struct node { + struct node *left; + struct node *right; + int run_length; +} Node; + +extern const char *one_run_len_code_list[MAX_CDWDTBL_LEN]; +extern const char *zero_run_len_code_list[MAX_CDWDTBL_LEN]; +extern void *tall_pcu_ctx; + +int decompress_crbb(int8_t compress_bmap_len, uint8_t clr_code_bit, + const uint8_t *orig_buf, bitvec *dest); + +/* Creating singleton class + */ +class egprs_compress +{ + void *tall_tree_ctx; + static egprs_compress *s_instance; + + egprs_compress() + { + if (decode_tree_init() < 0) { + fprintf(stderr, "Error initializing tree\n"); + exit(1); + } + } + Node *create_tree_node(); + void build_codeword(Node *root, const char *cdwd[]); + ~egprs_compress(); +public: + Node *ones_list; + Node *zeros_list; + + int decode_tree_init(void); + + static egprs_compress *instance() + { + if (!s_instance) + s_instance = new egprs_compress; + + return s_instance; + } +}; diff --git a/tests/Makefile.am b/tests/Makefile.am index 2a3415e..6325164 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,7 +1,7 @@ AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGB_CFLAGS) $(LIBOSMOGSM_CFLAGS) -I$(top_srcdir)/src/ AM_LDFLAGS = -lrt -check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest llc/LlcTest codel/codel_test edge/EdgeTest +check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest llc/LlcTest codel/codel_test edge/EdgeTest bitcomp/BitcompTest noinst_PROGRAMS = emu/pcu_emu rlcmac_RLCMACTest_SOURCES = rlcmac/RLCMACTest.cpp @@ -25,6 +25,18 @@ $(LIBOSMOGSM_LIBS) \ $(LIBOSMOCORE_LIBS) \ $(COMMON_LA) + +bitcomp_BitcompTest_SOURCES = bitcomp/BitcompTest.cpp +bitcomp_BitcompTest_LDADD = \ + $(top_builddir)/src/libgprs.la \ + $(LIBOSMOGB_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(COMMON_LA) + +bitcomp_BitcompTest_LDFLAGS = \ + -Wl,-u,bssgp_prim_cb + edge_EdgeTest_SOURCES = edge/EdgeTest.cpp edge_EdgeTest_LDADD = \ @@ -108,6 +120,7 @@ rlcmac/RLCMACTest.ok rlcmac/RLCMACTest.err \ alloc/AllocTest.ok alloc/AllocTest.err \ tbf/TbfTest.ok tbf/TbfTest.err \ + bitcomp/BitcompTest.ok bitcomp/BitcompTest.err \ types/TypesTest.ok types/TypesTest.err \ ms/MsTest.ok ms/MsTest.err \ llc/LlcTest.ok llc/LlcTest.err \ diff --git a/tests/bitcomp/BitcompTest b/tests/bitcomp/BitcompTest new file mode 100755 index 0000000..e601cc9 --- /dev/null +++ b/tests/bitcomp/BitcompTest Binary files differ diff --git a/tests/bitcomp/BitcompTest.cpp b/tests/bitcomp/BitcompTest.cpp new file mode 100644 index 0000000..40512f8 --- /dev/null +++ b/tests/bitcomp/BitcompTest.cpp @@ -0,0 +1,242 @@ +#include "egprs_rlc_compression.h" +#include "decoding.h" +#include "bts.h" +#include "tbf.h" +#include "gprs_debug.h" +#include "pcu_utils.h" +#include "gprs_bssgp_pcu.h" +#include "pcu_l1_if.h" + +extern "C" { +#include "pcu_vty.h" + +#include +#include +#include +#include +#include +#include +} + +#define NEW 1 +#define MASK(n) (0xFF << (8-n)) +#define MAX_CRBB_LEN 23 +#define MAX_URBB_LEN 40 + +void *tall_pcu_ctx; +int16_t spoof_mnc = 0, spoof_mcc = 0; + +struct test_data { + int8_t crbb_len; + uint8_t cc; + uint8_t crbb_data[MAX_CRBB_LEN]; /* compressed data */ + uint8_t ucmp_data[MAX_URBB_LEN]; /* uncompressed data */ + int ucmp_len; + int verify; +} test[] = { + { .crbb_len = 67, .cc = 1, + .crbb_data = { + 0x02, 0x0c, 0xa0, 0x30, 0xcb, 0x1a, 0x0c, 0xe3, 0x6c + }, + .ucmp_data = { + 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x01, 0xff, 0xff, + 0xff, 0xf8, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, + 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xdb + }, + .ucmp_len = 194, .verify = 1 + }, + { .crbb_len = 40, .cc = 1, + .crbb_data = { + 0x53, 0x06, 0xc5, 0x40, 0x6d + }, + .ucmp_data = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x03 + }, + .ucmp_len = 182, .verify = 1 + }, + { .crbb_len = 8, .cc = 1, + .crbb_data = {0x02}, + .ucmp_data = {0xff, 0xff, 0xff, 0xf8}, + .ucmp_len = 29, .verify = 1 + }, + { .crbb_len = 103, .cc = 1, + .crbb_data = { + 0x02, 0x0c, 0xe0, 0x41, 0xa0, 0x0c, 0x36, 0x0d, 0x03, + 0x71, 0xb0, 0x6e, 0x24 + }, + .ucmp_data = { + 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xf8, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, + 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff + }, + .ucmp_len = 288, .verify = 1 + }, + /* Test vector from libosmocore test */ + { .crbb_len = 35, .cc = 0, + .crbb_data = {0xde, 0x88, 0x75, 0x65, 0x80}, + .ucmp_data = {0x37, 0x47, 0x81, 0xf0}, + .ucmp_len = 28, .verify = 1 + }, + { .crbb_len = 18, .cc = 1, + .crbb_data = {0xdd, 0x41, 0x00}, + .ucmp_data = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00 + }, + .ucmp_len = 90, .verify = 1 + }, + /*Invalid inputs*/ + { .crbb_len = 18, .cc = 1, + .crbb_data = {0x1E, 0x70, 0xc0}, + .ucmp_data = {0x0}, + .ucmp_len = 0, .verify = 0 + }, + { .crbb_len = 14, .cc = 1, + .crbb_data = {0x00, 0x1E, 0x7c}, + .ucmp_data = {0x0}, + .ucmp_len = 0, .verify = 0 + }, + { .crbb_len = 24, .cc = 0, + .crbb_data = {0x00, 0x00, 0x00}, + .ucmp_data = {0x0}, + .ucmp_len = 0, .verify = 0 + } + }; + +static const struct log_info_cat default_categories[] = { + {"DCSN1", "\033[1;31m", "Concrete Syntax Notation One (CSN1)", LOGL_INFO, 0}, + {"DL1IF", "\033[1;32m", "GPRS PCU L1 interface (L1IF)", LOGL_DEBUG, 1}, + {"DRLCMAC", "\033[0;33m", "GPRS RLC/MAC layer (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACDATA", "\033[0;33m", "GPRS RLC/MAC layer Data (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACDL", "\033[1;33m", "GPRS RLC/MAC layer Downlink (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACUL", "\033[1;36m", "GPRS RLC/MAC layer Uplink (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACSCHED", "\033[0;36m", "GPRS RLC/MAC layer Scheduling (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACMEAS", "\033[1;31m", "GPRS RLC/MAC layer Measurements (RLCMAC)", LOGL_INFO, 1}, + {"DNS", "\033[1;34m", "GPRS Network Service Protocol (NS)", LOGL_INFO, 1}, + {"DBSSGP", "\033[1;34m", "GPRS BSS Gateway Protocol (BSSGP)", LOGL_INFO, 1}, + {"DPCU", "\033[1;35m", "GPRS Packet Control Unit (PCU)", LOGL_NOTICE, 1}, +}; + +static int filter_fn(const struct log_context *ctx, + struct log_target *tar) +{ + return 1; +} + +/* To verify the result with expected result */ +int check_result(bitvec bits, uint8_t *exp_data, int exp_len) +{ + if (bits.cur_bit != exp_len) + return 0; + size_t n = (exp_len / 8); + int rem = (exp_len % 8); + + if (memcmp(exp_data, bits.data, n) == 0) { + if (rem == 0) + return 1; + if ((bits.data[n] & MASK(rem)) == ((*(exp_data + n)) & MASK(rem))) + return 1; + else + return 0; + } else + return 0; +} + +/* To test decoding of compressed bitmap by Tree based method + * and to verify the result with expected result + * for invalid input verfication is suppressed + */ +static void test_EPDAN_decode_tree(void) +{ + bitvec dest; + int init_flag = 1; + int itr; + int rc; + uint8_t bits_data[RLC_EGPRS_MAX_WS/8]; + + printf("=== start %s ===\n", __func__); + + for (itr = 0 ; itr < (sizeof(test) / sizeof(test_data)) ; itr++) { + LOGP(DRLCMACDL, LOGL_DEBUG, "Tree based decoding " + "\nexpected data = %s\nexpected " + "len = %d\ndecoded data = %s\ndecoded len = %d\n", + osmo_hexdump(test[itr].ucmp_data, + (test[itr].ucmp_len + 7)/8), + test[itr].ucmp_len, osmo_hexdump(dest.data, + (dest.cur_bit + 7)/8), dest.cur_bit + ); + dest.data = bits_data; + dest.data_len = sizeof(bits_data); + dest.cur_bit = 0; + memset(dest.data, 0, sizeof(bits_data)); + rc = decompress_crbb(test[itr].crbb_len, test[itr].cc, + test[itr].crbb_data, &dest + ); + if (rc < 0) { + LOGP(DRLCMACUL, LOGL_NOTICE, + "Failed to decode CRBB: length %d, data '%s'\n", + test[itr].crbb_len, osmo_hexdump( + test[itr].crbb_data, (test[itr].crbb_len + 7)/8)); + } + if (init_flag) + init_flag = 0; + if (test[itr].verify) { + if (check_result(dest, test[itr].ucmp_data, + test[itr].ucmp_len) == 0) { + LOGP(DRLCMACDL, LOGL_DEBUG, "Tree based decoding " + ":Error\nexpected data = %s\nexpected" + " len = %d\ndecoded data = %s\n" + "decoded len = %d\n", + osmo_hexdump(test[itr].ucmp_data, + (test[itr].ucmp_len + 7)/8), + test[itr].ucmp_len, osmo_hexdump(dest.data, + (dest.cur_bit + 7)/8), dest.cur_bit + ); + OSMO_ASSERT(0); + } + } + } + + printf("=== end %s ===\n", __func__); +} + +const struct log_info debug_log_info = { + filter_fn, + (struct log_info_cat *)default_categories, + ARRAY_SIZE(default_categories), +}; + +int main(int argc, char **argv) +{ + struct vty_app_info pcu_vty_info = {0}; + + osmo_init_logging(&debug_log_info); + log_set_use_color(osmo_stderr_target, 0); + log_set_print_filename(osmo_stderr_target, 0); + bssgp_set_log_ss(DBSSGP); + + vty_init(&pcu_vty_info); + pcu_vty_init(&debug_log_info); + + tall_pcu_ctx = talloc_named_const(NULL, 1, "moiji-mobile TbfTest context"); + if (!tall_pcu_ctx) + abort(); + test_EPDAN_decode_tree(); + if (getenv("TALLOC_REPORT_FULL")) + talloc_report_full(tall_pcu_ctx, stderr); + talloc_free(tall_pcu_ctx); + return EXIT_SUCCESS; +} + +/* + * stubs that should not be reached + */ +extern "C" { +void l1if_pdch_req() { abort(); } +void l1if_connect_pdch() { abort(); } +void l1if_close_pdch() { abort(); } +void l1if_open_pdch() { abort(); } +} diff --git a/tests/bitcomp/BitcompTest.err b/tests/bitcomp/BitcompTest.err new file mode 100644 index 0000000..2ee542e --- /dev/null +++ b/tests/bitcomp/BitcompTest.err @@ -0,0 +1,47 @@ +Tree based decoding +expected data = ff ff ff f8 00 00 01 ff ff ff f8 00 00 00 ff ff ff fe 00 00 3f ff ff ff db +expected len = 194 +decoded data = ff ff ff f8 00 00 01 ff ff ff f8 00 00 00 ff ff ff fe 00 00 3f ff ff ff db +decoded len = 4 +Tree based decoding +expected data = ff ff ff ff ff ff c0 00 00 00 00 3f ff ff ff ff ff f8 00 00 00 00 03 +expected len = 182 +decoded data = ff ff ff ff ff ff c0 00 00 00 00 3f ff ff ff ff ff f8 00 00 00 00 03 +decoded len = 194 +Tree based decoding +expected data = ff ff ff f8 +expected len = 29 +decoded data = ff ff ff f8 +decoded len = 182 +Tree based decoding +expected data = ff ff ff f8 00 00 ff ff ff f8 00 00 7f ff ff fe 00 00 0f ff ff ff e0 00 00 7f ff ff ff 80 00 01 ff ff ff ff +expected len = 288 +decoded data = ff ff ff f8 00 00 ff ff ff f8 00 00 7f ff ff fe 00 00 0f ff ff ff e0 00 00 7f ff ff ff 80 00 01 ff ff ff ff +decoded len = 29 +Tree based decoding +expected data = 37 47 81 f0 +expected len = 28 +decoded data = 37 47 81 f0 +decoded len = 288 +Tree based decoding +expected data = ff ff ff ff ff ff ff ff ff ff 00 00 +expected len = 90 +decoded data = ff ff ff ff ff ff ff ff ff ff 00 00 +decoded len = 28 +Tree based decoding +expected data = +expected len = 0 +decoded data = +decoded len = 90 +Tree based decoding +expected data = +expected len = 0 +decoded data = +decoded len = 19 +Failed to decode CRBB: length 14, data '00 1e ' +Tree based decoding +expected data = +expected len = 0 +decoded data = +decoded len = 0 +Failed to decode CRBB: length 24, data '00 00 00 ' diff --git a/tests/bitcomp/BitcompTest.ok b/tests/bitcomp/BitcompTest.ok new file mode 100644 index 0000000..f7720fc --- /dev/null +++ b/tests/bitcomp/BitcompTest.ok @@ -0,0 +1,2 @@ +=== start test_EPDAN_decode_tree === +=== end test_EPDAN_decode_tree === diff --git a/tests/testsuite.at b/tests/testsuite.at index 1049b31..3ab39cc 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -23,6 +23,14 @@ AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/tbf/TbfTest], [0], [expout], [experr]) AT_CLEANUP + +AT_SETUP([bitcomp]) +AT_KEYWORDS([bitcomp]) +cat $abs_srcdir/bitcomp/BitcompTest.ok > expout +cat $abs_srcdir/bitcomp/BitcompTest.err > experr +AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/bitcomp/BitcompTest], [0], [expout], [experr]) +AT_CLEANUP + AT_SETUP([edge]) AT_KEYWORDS([edge]) cat $abs_srcdir/edge/EdgeTest.ok > expout -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 17 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: pravin From gerrit-no-reply at lists.osmocom.org Fri Aug 12 10:30:44 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Fri, 12 Aug 2016 10:30:44 +0000 Subject: [PATCH] libosmo-abis[master]: Change API to convey marker bit Message-ID: Review at https://gerrit.osmocom.org/688 Change API to convey marker bit Previously RTP receive callback ignored Marker bit from RTP headers. Extend API to include it explicitly. Change-Id: I3c2b6365d8a51bf98805614e07344d2639875fde Related: OS#1750 --- M TODO-RELEASE M include/osmocom/trau/osmo_ortp.h M src/trau/osmo_ortp.c 3 files changed, 6 insertions(+), 3 deletions(-) git pull ssh://gerrit.osmocom.org:29418/libosmo-abis refs/changes/88/688/1 diff --git a/TODO-RELEASE b/TODO-RELEASE index 43b1e8e..7ea65b6 100644 --- a/TODO-RELEASE +++ b/TODO-RELEASE @@ -1 +1,2 @@ #library what description / commit summary line +libosmo-abis API change major: add parameter to rx_cb() callack in osmo_ortp.h diff --git a/include/osmocom/trau/osmo_ortp.h b/include/osmocom/trau/osmo_ortp.h index 7c2a5cb..1c0b223 100644 --- a/include/osmocom/trau/osmo_ortp.h +++ b/include/osmocom/trau/osmo_ortp.h @@ -55,7 +55,7 @@ /*! \brief callback for incoming data */ void (*rx_cb)(struct osmo_rtp_socket *rs, const uint8_t *payload, - unsigned int payload_len); + unsigned int payload_len, bool marker); /*! \brief Receive user timestamp, to be incremented by user */ uint32_t rx_user_ts; diff --git a/src/trau/osmo_ortp.c b/src/trau/osmo_ortp.c index eb78212..11b8bc2 100644 --- a/src/trau/osmo_ortp.c +++ b/src/trau/osmo_ortp.c @@ -159,7 +159,8 @@ /* hand into receiver */ if (rs->rx_cb) rs->rx_cb(rs, mblk->b_rptr, - mblk->b_wptr - mblk->b_rptr); + mblk->b_wptr - mblk->b_rptr, + rtp_get_markbit(mblk)); //rs->rx_user_ts += 160; freemsg(mblk); return 1; @@ -189,7 +190,8 @@ /* hand into receiver */ if (rs->rx_cb) rs->rx_cb(rs, mblk->b_rptr, - mblk->b_wptr - mblk->b_rptr); + mblk->b_wptr - mblk->b_rptr, + rtp_get_markbit(mblk)); freemsg(mblk); } else LOGP(DLMIB, LOGL_INFO, "recvm_with_ts(%u): ERROR!\n", -- To view, visit https://gerrit.osmocom.org/688 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I3c2b6365d8a51bf98805614e07344d2639875fde Gerrit-PatchSet: 1 Gerrit-Project: libosmo-abis Gerrit-Branch: master Gerrit-Owner: Max From gerrit-no-reply at lists.osmocom.org Fri Aug 12 10:32:39 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Fri, 12 Aug 2016 10:32:39 +0000 Subject: osmo-bts[master]: sysmo: fix dyn TS: Revert "Activate PTCCH UL" [in sysmobts] In-Reply-To: References: Message-ID: Patch Set 3: Code-Review+1 -- To view, visit https://gerrit.osmocom.org/671 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia59d95c75a8a5d3bd596f55cd1dc0906a6a95f7f Gerrit-PatchSet: 3 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Fri Aug 12 10:45:29 2016 From: gerrit-no-reply at lists.osmocom.org (pravin) Date: Fri, 12 Aug 2016 10:45:29 +0000 Subject: osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Patch Set 17: > Build Failed > > http://jenkins.osmocom.org/jenkins/job/osmo-pcu-gerrit/229/ : > FAILURE Newly added Regression bitcomp passes in our environment but its failed in jenkins build. Please let me know if I am missing something. -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 17 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: pravin Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Fri Aug 12 12:01:39 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Fri, 12 Aug 2016 12:01:39 +0000 Subject: [PATCH] openbsc[master]: comment: gsm48_gmm_sendmsg(): add spec reference on encryptable Message-ID: Review at https://gerrit.osmocom.org/689 comment: gsm48_gmm_sendmsg(): add spec reference on encryptable Change-Id: I54a3bc518bc38e38b78f6e9ea3705e4fbd5ffb98 --- M openbsc/src/gprs/gprs_gmm.c 1 file changed, 3 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/89/689/1 diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index aa49919..e95fca3 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -130,7 +130,9 @@ return sgsn->cfg.timers.T3314 + (sgsn->cfg.timers.T3312 + 4 * 60); } -/* Send a message through the underlying layer */ +/* Send a message through the underlying layer. + * @param encryptable: see at 3GPP TS 24.008 ? 4.7.1.2 and + * gsm48_hdr_gmm_cipherable(). Pass false for not cipherable messages. */ static int gsm48_gmm_sendmsg(struct msgb *msg, int command, struct sgsn_mm_ctx *mm, bool encryptable) { -- To view, visit https://gerrit.osmocom.org/689 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I54a3bc518bc38e38b78f6e9ea3705e4fbd5ffb98 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Fri Aug 12 12:06:17 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Fri, 12 Aug 2016 12:06:17 +0000 Subject: osmo-bts[master]: sysmo: fix dyn TS: Revert "Activate PTCCH UL" [in sysmobts] In-Reply-To: References: Message-ID: Patch Set 3: Code-Review+1 I believe this is settled and urgent enough, adding +1 to myself. -- To view, visit https://gerrit.osmocom.org/671 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia59d95c75a8a5d3bd596f55cd1dc0906a6a95f7f Gerrit-PatchSet: 3 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Fri Aug 12 12:07:00 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Fri, 12 Aug 2016 12:07:00 +0000 Subject: osmo-bts[master]: sysmo: fix dyn TS: Revert "Activate PTCCH UL" [in sysmobts] In-Reply-To: References: Message-ID: Patch Set 3: Code-Review+2 I believe this is settled and urgent enough, adding *+2* to myself. -- To view, visit https://gerrit.osmocom.org/671 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia59d95c75a8a5d3bd596f55cd1dc0906a6a95f7f Gerrit-PatchSet: 3 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Fri Aug 12 12:07:05 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Fri, 12 Aug 2016 12:07:05 +0000 Subject: [MERGED] osmo-bts[master]: sysmo: fix dyn TS: Revert "Activate PTCCH UL" [in sysmobts] In-Reply-To: References: Message-ID: Neels Hofmeyr has submitted this change and it was merged. Change subject: sysmo: fix dyn TS: Revert "Activate PTCCH UL" [in sysmobts] ...................................................................... sysmo: fix dyn TS: Revert "Activate PTCCH UL" [in sysmobts] This reverts commit 53d792c3b027bfb42d77804e3e687a287e122ef3. See http://osmocom.org/issues/1796 The commit caused this error for PDCH TS with SysmoBTS: DL1P <0007> l1_if.c:164 Tx L1 prim MPH-ACTIVATE.req DL1C <0006> oml.c:811 Error activating L1 SAPI PTCCH on TS 7: Invalid parameter DL1C <0006> oml.c:1089 (bts=0,trx=0,ts=7,ss=0) act failed mark broken due status: -4 Plain PDCH TS show this error but continue to function despite the SAPI activation failure. As a side effect, the SAPI activation failure breaks dynamic TS. GPRS initially works, but the broken status prevents transitions to TCH/* modes in the BSC: DRLL <0000> chan_alloc.c:355 Failed to allocate TCH_H channel DRSL <0004> abis_rsl.c:1656 BTS 0 CHAN RQD: no resources for TCH_H 0x45 Since the commit only enabled PTCCH UL in sysmobts, no other BTS models are affected. Notice that lc15 still has PTCCH UL disabled all the while, before and after this commit and its revert. Also note that PTCCH DL is and has been enabled without problems (see further above in sapi_dir_pdtch_sapis[]). This is only about PTCCH UL. Related: OS#1796 Change-Id: Ia59d95c75a8a5d3bd596f55cd1dc0906a6a95f7f --- M src/osmo-bts-sysmo/oml.c 1 file changed, 1 insertion(+), 2 deletions(-) Approvals: Max: Looks good to me, but someone else must approve Neels Hofmeyr: Looks good to me, approved Jenkins Builder: Verified diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c index 9beba43..e5d3e40 100644 --- a/src/osmo-bts-sysmo/oml.c +++ b/src/osmo-bts-sysmo/oml.c @@ -618,9 +618,8 @@ { GsmL1_Sapi_Pdtch, GsmL1_Dir_RxUplink }, { GsmL1_Sapi_Ptcch, GsmL1_Dir_TxDownlink }, { GsmL1_Sapi_Prach, GsmL1_Dir_RxUplink }, - { GsmL1_Sapi_Ptcch, GsmL1_Dir_RxUplink }, - /* FIXME: do we still need this if? */ #if 0 + { GsmL1_Sapi_Ptcch, GsmL1_Dir_RxUplink }, { GsmL1_Sapi_Pacch, GsmL1_Dir_TxDownlink }, #endif }; -- To view, visit https://gerrit.osmocom.org/671 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ia59d95c75a8a5d3bd596f55cd1dc0906a6a95f7f Gerrit-PatchSet: 4 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Fri Aug 12 13:07:52 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Fri, 12 Aug 2016 13:07:52 +0000 Subject: osmo-bts[master]: sysmo: fix dyn TS: Revert "Activate PTCCH UL" [in sysmobts] In-Reply-To: References: Message-ID: Patch Set 4: It will be settled when OS#1796 is fixed. This is just workaround plug. -- To view, visit https://gerrit.osmocom.org/671 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia59d95c75a8a5d3bd596f55cd1dc0906a6a95f7f Gerrit-PatchSet: 4 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Fri Aug 12 14:20:44 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Fri, 12 Aug 2016 14:20:44 +0000 Subject: [PATCH] libosmocore[master]: Add Marker to ph_tch_param Message-ID: Review at https://gerrit.osmocom.org/690 Add Marker to ph_tch_param Extend struct ph_tch_param with Marker bit from RTP header to indicate speech onset in case of DTX. Change-Id: Ic664902630b9d335ff9abc7a9ca7249eaf80e05f Related: OS#1750 --- M TODO-RELEASE M include/osmocom/gsm/l1sap.h 2 files changed, 3 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/90/690/1 diff --git a/TODO-RELEASE b/TODO-RELEASE index 472b328..648b6a6 100644 --- a/TODO-RELEASE +++ b/TODO-RELEASE @@ -2,4 +2,5 @@ libosmogsm internal API update Internal API for GPRS cipher implementors updated to accommodate for arbitrary key lengths libosmocore change major external talloc dependency / internal talloc removal libosmocore change major size of ph_data_param struct changed / Extend L1SAP PH-DATA with presence information -libosmocore change major size of ph_data_param struct changed / Extend L1SAP PH-DATA with measurement information \ No newline at end of file +libosmocore change major size of ph_data_param struct changed / Extend L1SAP PH-DATA with measurement information +libosmocore change major size of ph_tch_param struct changed / Extend with RTP Marker diff --git a/include/osmocom/gsm/l1sap.h b/include/osmocom/gsm/l1sap.h index f0e9f6c..e199efe 100644 --- a/include/osmocom/gsm/l1sap.h +++ b/include/osmocom/gsm/l1sap.h @@ -81,6 +81,7 @@ uint8_t chan_nr; /*!< \brief Channel Number (Like RSL) */ uint32_t fn; /*!< \brief GSM Frame Number */ int8_t rssi; /*!< \brief RSSI of received indication */ + uint8_t marker; /*!< \brief RTP Marker bit (speech onset indicator) */ }; /*! \brief for PH-CONN.ind */ -- To view, visit https://gerrit.osmocom.org/690 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ic664902630b9d335ff9abc7a9ca7249eaf80e05f Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Max From gerrit-no-reply at lists.osmocom.org Fri Aug 12 17:53:36 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Fri, 12 Aug 2016 17:53:36 +0000 Subject: [PATCH] osmo-bts[master]: Check Marker bit to send ONSET primitive to L1 Message-ID: Review at https://gerrit.osmocom.org/691 Check Marker bit to send ONSET primitive to L1 This change affect sysmobts and LC15 hw and requires corresponding change in libosmocore. Change-Id: I88c41568bcb0d82699f617adc4ad192603dd1bb6 Related: OS#1750 --- M include/osmo-bts/l1sap.h M src/common/l1sap.c M src/osmo-bts-litecell15/l1_if.c M src/osmo-bts-litecell15/l1_if.h M src/osmo-bts-litecell15/tch.c M src/osmo-bts-sysmo/l1_if.c M src/osmo-bts-sysmo/l1_if.h M src/osmo-bts-sysmo/tch.c 8 files changed, 61 insertions(+), 17 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/91/691/1 diff --git a/include/osmo-bts/l1sap.h b/include/osmo-bts/l1sap.h index 2735574..981cd75 100644 --- a/include/osmo-bts/l1sap.h +++ b/include/osmo-bts/l1sap.h @@ -55,7 +55,7 @@ /* call-back function for incoming RTP */ void l1sap_rtp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *rtp_pl, - unsigned int rtp_pl_len); + unsigned int rtp_pl_len, bool marker); /* channel control */ int l1sap_chan_act(struct gsm_bts_trx *trx, uint8_t chan_nr, struct tlv_parsed *tp); diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 6498103..03ac7b0 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -24,7 +24,7 @@ #include #include #include - +#include #include #include @@ -673,7 +673,7 @@ struct osmo_phsap_prim *resp_l1sap, empty_l1sap; struct gsm_time g_time; struct gsm_lchan *lchan; - uint8_t chan_nr; + uint8_t chan_nr, marker = 0; uint32_t fn; chan_nr = rts_ind->chan_nr; @@ -705,6 +705,9 @@ gsm_lchan_name(lchan)); resp_l1sap = &empty_l1sap; } else { + /* Remove RTP hear Marker bit */ + marker = msgb_get_u8(resp_msg); + resp_msg->l2h = resp_msg->data; msgb_push(resp_msg, sizeof(*resp_l1sap)); resp_msg->l1h = resp_msg->data; @@ -716,6 +719,7 @@ resp_msg); resp_l1sap->u.tch.chan_nr = chan_nr; resp_l1sap->u.tch.fn = fn; + resp_l1sap->u.tch.marker = marker; DEBUGP(DL1P, "Tx TCH.req %02u/%02u/%02u chan_nr=%d\n", g_time.t1, g_time.t2, g_time.t3, chan_nr); @@ -1061,7 +1065,7 @@ /*! \brief call-back function for incoming RTP */ void l1sap_rtp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *rtp_pl, - unsigned int rtp_pl_len) + unsigned int rtp_pl_len, bool marker) { struct gsm_lchan *lchan = rs->priv; struct msgb *msg, *tmp; @@ -1074,6 +1078,8 @@ memcpy(msgb_put(msg, rtp_pl_len), rtp_pl, rtp_pl_len); msgb_pull(msg, sizeof(*l1sap)); + /* Add RTP hear Marker bit */ + msgb_put_u8(msg, marker); /* make sure the queue doesn't get too long */ llist_for_each_entry(tmp, &lchan->dl_tch_queue, list) diff --git a/src/osmo-bts-litecell15/l1_if.c b/src/osmo-bts-litecell15/l1_if.c index dcd25ee..7e661b9 100644 --- a/src/osmo-bts-litecell15/l1_if.c +++ b/src/osmo-bts-litecell15/l1_if.c @@ -469,7 +469,7 @@ l1if_tch_encode(lchan, l1p->u.phDataReq.msgUnitParam.u8Buffer, &l1p->u.phDataReq.msgUnitParam.u8Size, - msg->data, msg->len); + msg->data, msg->len, l1sap->u.tch.marker); } /* no message/data, we generate an empty traffic msg */ diff --git a/src/osmo-bts-litecell15/l1_if.h b/src/osmo-bts-litecell15/l1_if.h index 2d136af..7dd4f95 100644 --- a/src/osmo-bts-litecell15/l1_if.h +++ b/src/osmo-bts-litecell15/l1_if.h @@ -11,6 +11,8 @@ #include +#include + enum { MQ_SYS_READ, MQ_L1_READ, @@ -88,7 +90,7 @@ /* tch.c */ void l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len, - const uint8_t *rtp_pl, unsigned int rtp_pl_len); + const uint8_t *rtp_pl, unsigned int rtp_pl_len, bool marker); int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg); int l1if_tch_fill(struct gsm_lchan *lchan, uint8_t *l1_buffer); struct msgb *gen_empty_tch_msg(struct gsm_lchan *lchan, uint32_t fn); diff --git a/src/osmo-bts-litecell15/tch.c b/src/osmo-bts-litecell15/tch.c index 187f688..67f430d 100644 --- a/src/osmo-bts-litecell15/tch.c +++ b/src/osmo-bts-litecell15/tch.c @@ -26,7 +26,7 @@ #include #include #include - +#include #include #include @@ -222,6 +222,9 @@ cmi = ft; LOGP(DRTP, LOGL_DEBUG, "SPEECH frame with CMI %u\n", cmi); break; + case AMR_NO_DATA: + LOGP(DRTP, LOGL_DEBUG, "SPEECH frame AMR NO_DATA\n"); + break; case AMR_SID: LOGP(DRTP, LOGL_DEBUG, "SID %s frame with CMI %u\n", sti ? "UPDATE" : "FIRST", cmi); @@ -288,6 +291,7 @@ * \param rs RTP Socket * \param[in] rtp_pl buffer containing RTP payload * \param[in] rtp_pl_len length of \a rtp_pl + * \param[in] marker RTP header Marrek bit (indicates speech onset) * * This function prepares a msgb with a L1 PH-DATA.req primitive and * queues it into lchan->dl_tch_queue. @@ -297,7 +301,7 @@ * pre-fill the primtive. */ void l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len, - const uint8_t *rtp_pl, unsigned int rtp_pl_len) + const uint8_t *rtp_pl, unsigned int rtp_pl_len, bool marker) { uint8_t *payload_type; uint8_t *l1_payload; @@ -327,9 +331,22 @@ rtp_pl_len); break; case GSM48_CMODE_SPEECH_AMR: - *payload_type = GsmL1_TchPlType_Amr; - rc = rtppayload_to_l1_amr(l1_payload, rtp_pl, - rtp_pl_len, lchan); + if (marker) { + *payload_type = GsmL1_TchPlType_Amr_Onset; + rc = 0; + enum osmo_amr_type ft; + enum osmo_amr_quality bfi; + uint8_t cmr; + int8_t sti, cmi; + + osmo_amr_rtp_dec(rtp_pl, rtp_pl_len, &cmr, &cmi, &ft, &bfi, &sti); + LOGP(DRTP, LOGL_ERROR, "Marker SPEECH frame AMR %s\n", get_value_string(osmo_amr_type_names, ft)); + } + else { + *payload_type = GsmL1_TchPlType_Amr; + rc = rtppayload_to_l1_amr(l1_payload, rtp_pl, + rtp_pl_len, lchan); + } break; default: /* we don't support CSD modes */ diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index f70ccf5..b619715 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -462,7 +462,7 @@ l1if_tch_encode(lchan, l1p->u.phDataReq.msgUnitParam.u8Buffer, &l1p->u.phDataReq.msgUnitParam.u8Size, - msg->data, msg->len); + msg->data, msg->len, l1sap->u.tch.marker); } /* no message/data, we generate an empty traffic msg */ diff --git a/src/osmo-bts-sysmo/l1_if.h b/src/osmo-bts-sysmo/l1_if.h index 2fc8a29..47720d5 100644 --- a/src/osmo-bts-sysmo/l1_if.h +++ b/src/osmo-bts-sysmo/l1_if.h @@ -11,6 +11,8 @@ #include +#include + enum { MQ_SYS_READ, MQ_L1_READ, @@ -108,7 +110,7 @@ /* tch.c */ void l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len, - const uint8_t *rtp_pl, unsigned int rtp_pl_len); + const uint8_t *rtp_pl, unsigned int rtp_pl_len, bool marker); int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg); int l1if_tch_fill(struct gsm_lchan *lchan, uint8_t *l1_buffer); struct msgb *gen_empty_tch_msg(struct gsm_lchan *lchan, uint32_t fn); diff --git a/src/osmo-bts-sysmo/tch.c b/src/osmo-bts-sysmo/tch.c index 39feae1..a7c3eb8 100644 --- a/src/osmo-bts-sysmo/tch.c +++ b/src/osmo-bts-sysmo/tch.c @@ -319,6 +319,9 @@ cmi = ft; LOGP(DRTP, LOGL_DEBUG, "SPEECH frame with CMI %u\n", cmi); break; + case AMR_NO_DATA: + LOGP(DRTP, LOGL_DEBUG, "SPEECH frame AMR NO_DATA\n"); + break; case AMR_SID: LOGP(DRTP, LOGL_DEBUG, "SID %s frame with CMI %u\n", sti ? "UPDATE" : "FIRST", cmi); @@ -385,6 +388,7 @@ * \param rs RTP Socket * \param[in] rtp_pl buffer containing RTP payload * \param[in] rtp_pl_len length of \a rtp_pl + * \param[in] marker RTP header Marrek bit (indicates speech onset) * * This function prepares a msgb with a L1 PH-DATA.req primitive and * queues it into lchan->dl_tch_queue. @@ -394,7 +398,7 @@ * pre-fill the primtive. */ void l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len, - const uint8_t *rtp_pl, unsigned int rtp_pl_len) + const uint8_t *rtp_pl, unsigned int rtp_pl_len, bool marker) { uint8_t *payload_type; uint8_t *l1_payload; @@ -426,9 +430,22 @@ break; #endif case GSM48_CMODE_SPEECH_AMR: - *payload_type = GsmL1_TchPlType_Amr; - rc = rtppayload_to_l1_amr(l1_payload, rtp_pl, - rtp_pl_len, lchan); + if (marker) { + *payload_type = GsmL1_TchPlType_Amr_Onset; + rc = 0; + enum osmo_amr_type ft; + enum osmo_amr_quality bfi; + uint8_t cmr; + int8_t sti, cmi; + + osmo_amr_rtp_dec(rtp_pl, rtp_pl_len, &cmr, &cmi, &ft, &bfi, &sti); + LOGP(DRTP, LOGL_ERROR, "Marker SPEECH frame AMR %s\n", get_value_string(osmo_amr_type_names, ft)); + } + else { + *payload_type = GsmL1_TchPlType_Amr; + rc = rtppayload_to_l1_amr(l1_payload, rtp_pl, + rtp_pl_len, lchan); + } break; default: /* we don't support CSD modes */ -- To view, visit https://gerrit.osmocom.org/691 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I88c41568bcb0d82699f617adc4ad192603dd1bb6 Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Max From gerrit-no-reply at lists.osmocom.org Sat Aug 13 05:49:30 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 13 Aug 2016 05:49:30 +0000 Subject: openbsc[master]: add DIU logging category In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/687 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ic2f6bb1023377c24247521dde2d2bcf14f04cfe2 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 13 05:51:23 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 13 Aug 2016 05:51:23 +0000 Subject: openbsc[master]: add libiu In-Reply-To: References: Message-ID: Patch Set 5: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/192 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Iffc26f9c73cb15463948f7435b72ac1747aabdb3 Gerrit-PatchSet: 5 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 13 05:52:46 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 13 Aug 2016 05:52:46 +0000 Subject: openbsc[master]: add DIU logging category In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+1 I'm not sure if we should proliferate too many logging categories, if there's not really much to log inside the category. libiu only contains 5 log messages, and they all relate to SCCP user sap primitives. Maybe we can move the messages into the SCCP provider library, or we re-use the LSCCP sub-system (if it exists)? -- To view, visit https://gerrit.osmocom.org/687 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ic2f6bb1023377c24247521dde2d2bcf14f04cfe2 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 13 10:57:04 2016 From: gerrit-no-reply at lists.osmocom.org (Max) Date: Sat, 13 Aug 2016 10:57:04 +0000 Subject: [PATCH] osmo-bts[master]: Use SID_FIRST_P1 to initiate DTX Message-ID: Review at https://gerrit.osmocom.org/692 Use SID_FIRST_P1 to initiate DTX Some phone seems to not send SID_FIRST_P2 message which seems like a different understanding of the DTX spec. Accommodate for that and use any of P1 | P2 message to initiate DTX in case of AMR HR. Change-Id: Iaf993b89caa0ad49b97d1c745dcaf039f867f018 --- M src/osmo-bts-litecell15/tch.c M src/osmo-bts-sysmo/tch.c 2 files changed, 2 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/92/692/1 diff --git a/src/osmo-bts-litecell15/tch.c b/src/osmo-bts-litecell15/tch.c index 67f430d..e7e054a 100644 --- a/src/osmo-bts-litecell15/tch.c +++ b/src/osmo-bts-litecell15/tch.c @@ -463,6 +463,7 @@ case GsmL1_TchPlType_Amr: rmsg = l1_to_rtppayload_amr(payload, payload_len, lchan); break; + case GsmL1_TchPlType_Amr_SidFirstP1: case GsmL1_TchPlType_Amr_SidFirstP2: /* L1 do not give us SID_FIRST data, just indication */ memcpy(sid_first, payload, payload_len); diff --git a/src/osmo-bts-sysmo/tch.c b/src/osmo-bts-sysmo/tch.c index a7c3eb8..fb68529 100644 --- a/src/osmo-bts-sysmo/tch.c +++ b/src/osmo-bts-sysmo/tch.c @@ -566,6 +566,7 @@ case GsmL1_TchPlType_Amr: rmsg = l1_to_rtppayload_amr(payload, payload_len, lchan); break; + case GsmL1_TchPlType_Amr_SidFirstP1: case GsmL1_TchPlType_Amr_SidFirstP2: /* L1 do not give us SID_FIRST data, just indication */ memcpy(sid_first, payload, payload_len); -- To view, visit https://gerrit.osmocom.org/692 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Iaf993b89caa0ad49b97d1c745dcaf039f867f018 Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Max From gerrit-no-reply at lists.osmocom.org Sun Aug 14 06:19:11 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Sun, 14 Aug 2016 06:19:11 +0000 Subject: [PATCH] cellmgr-ng[master]: vty: Adapt the go_parent_cb and fix compiler warning Message-ID: Review at https://gerrit.osmocom.org/693 vty: Adapt the go_parent_cb and fix compiler warning The return type changed from enum to int and it is time to catch up with it. vty_interface.c:108:2: warning: initialization from incompatible pointer type .go_parent_cb = ss7_go_parent, ^ vty_interface.c:108:2: warning: (near initialization for ?vty_info.go_parent_cb?) mgcp_ss7_vty.c:36:2: warning: initialization from incompatible pointer type .go_parent_cb = mgcp_go_parent, ^ mgcp_ss7_vty.c:36:2: warning: (near initialization for ?vty_info.go_parent_cb?) Change-Id: I8061df697daf79fa57b8313c15f6567ff152f4a5 --- M src/mgcp/mgcp_vty.c M src/mgcp_ss7_vty.c M src/vty_interface.c 3 files changed, 3 insertions(+), 3 deletions(-) git pull ssh://gerrit.osmocom.org:29418/cellmgr-ng refs/changes/93/693/1 diff --git a/src/mgcp/mgcp_vty.c b/src/mgcp/mgcp_vty.c index e3a7008..dfcc6fe 100644 --- a/src/mgcp/mgcp_vty.c +++ b/src/mgcp/mgcp_vty.c @@ -40,7 +40,7 @@ static int allocate_endpoints(struct mgcp_trunk_config *tcfg); -enum node_type mgcp_go_parent(struct vty *vty) +int mgcp_go_parent(struct vty *vty) { switch (vty->node) { case TRUNK_NODE: diff --git a/src/mgcp_ss7_vty.c b/src/mgcp_ss7_vty.c index 8ed27ad..5bdb658 100644 --- a/src/mgcp_ss7_vty.c +++ b/src/mgcp_ss7_vty.c @@ -29,7 +29,7 @@ extern struct mgcp_config *g_cfg; -enum node_type mgcp_go_parent(struct vty *vty); +int mgcp_go_parent(struct vty *vty); static struct vty_app_info vty_info = { .name = "mgcp_ss7", .version = "0.0.1", diff --git a/src/vty_interface.c b/src/vty_interface.c index de250d8..6c6d30f 100644 --- a/src/vty_interface.c +++ b/src/vty_interface.c @@ -48,7 +48,7 @@ extern struct bsc_data *bsc; -static enum node_type ss7_go_parent(struct vty *vty) +static int ss7_go_parent(struct vty *vty) { switch (vty->node) { case LINK_NODE: -- To view, visit https://gerrit.osmocom.org/693 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I8061df697daf79fa57b8313c15f6567ff152f4a5 Gerrit-PatchSet: 1 Gerrit-Project: cellmgr-ng Gerrit-Branch: master Gerrit-Owner: Holger Freyther From gerrit-no-reply at lists.osmocom.org Sun Aug 14 06:19:11 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Sun, 14 Aug 2016 06:19:11 +0000 Subject: [PATCH] cellmgr-ng[master]: mgcp: Address compiler warning and initialize Message-ID: Review at https://gerrit.osmocom.org/694 mgcp: Address compiler warning and initialize mgcp/mgcp_protocol.c: In function ?mgcp_handle_message?: /home/ich/install/openbsc/include/osmocom/core/logging.h:59:4: warning: ?save? may be used uninitialized in this function [-Wmaybe-uninitialized] logp2(ss, level, __BASE_FILE__, __LINE__, 0, fmt, ##args); \ ^ mgcp/mgcp_protocol.c:368:15: note: ?save? was declared here char *elem, *save; Change-Id: I28152373b043c8a5b55a83ac09dd7bafce4d2d66 --- M src/mgcp/mgcp_protocol.c 1 file changed, 1 insertion(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/cellmgr-ng refs/changes/94/694/1 diff --git a/src/mgcp/mgcp_protocol.c b/src/mgcp/mgcp_protocol.c index d3561d5..40acc09 100644 --- a/src/mgcp/mgcp_protocol.c +++ b/src/mgcp/mgcp_protocol.c @@ -365,7 +365,7 @@ static int mgcp_analyze_header(struct mgcp_parse_data *pdata, char *data) { int i = 0; - char *elem, *save; + char *elem, *save = NULL; pdata->trans = "000000"; -- To view, visit https://gerrit.osmocom.org/694 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I28152373b043c8a5b55a83ac09dd7bafce4d2d66 Gerrit-PatchSet: 1 Gerrit-Project: cellmgr-ng Gerrit-Branch: master Gerrit-Owner: Holger Freyther From gerrit-no-reply at lists.osmocom.org Sun Aug 14 06:24:49 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Sun, 14 Aug 2016 06:24:49 +0000 Subject: cellmgr-ng[master]: mgcp: Address compiler warning and initialize In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/694 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I28152373b043c8a5b55a83ac09dd7bafce4d2d66 Gerrit-PatchSet: 1 Gerrit-Project: cellmgr-ng Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sun Aug 14 06:24:55 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Sun, 14 Aug 2016 06:24:55 +0000 Subject: cellmgr-ng[master]: vty: Adapt the go_parent_cb and fix compiler warning In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/693 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I8061df697daf79fa57b8313c15f6567ff152f4a5 Gerrit-PatchSet: 1 Gerrit-Project: cellmgr-ng Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sun Aug 14 06:24:59 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Sun, 14 Aug 2016 06:24:59 +0000 Subject: [MERGED] cellmgr-ng[master]: vty: Adapt the go_parent_cb and fix compiler warning In-Reply-To: References: Message-ID: Holger Freyther has submitted this change and it was merged. Change subject: vty: Adapt the go_parent_cb and fix compiler warning ...................................................................... vty: Adapt the go_parent_cb and fix compiler warning The return type changed from enum to int and it is time to catch up with it. vty_interface.c:108:2: warning: initialization from incompatible pointer type .go_parent_cb = ss7_go_parent, ^ vty_interface.c:108:2: warning: (near initialization for ?vty_info.go_parent_cb?) mgcp_ss7_vty.c:36:2: warning: initialization from incompatible pointer type .go_parent_cb = mgcp_go_parent, ^ mgcp_ss7_vty.c:36:2: warning: (near initialization for ?vty_info.go_parent_cb?) Change-Id: I8061df697daf79fa57b8313c15f6567ff152f4a5 --- M src/mgcp/mgcp_vty.c M src/mgcp_ss7_vty.c M src/vty_interface.c 3 files changed, 3 insertions(+), 3 deletions(-) Approvals: Jenkins Builder: Verified Holger Freyther: Looks good to me, approved diff --git a/src/mgcp/mgcp_vty.c b/src/mgcp/mgcp_vty.c index e3a7008..dfcc6fe 100644 --- a/src/mgcp/mgcp_vty.c +++ b/src/mgcp/mgcp_vty.c @@ -40,7 +40,7 @@ static int allocate_endpoints(struct mgcp_trunk_config *tcfg); -enum node_type mgcp_go_parent(struct vty *vty) +int mgcp_go_parent(struct vty *vty) { switch (vty->node) { case TRUNK_NODE: diff --git a/src/mgcp_ss7_vty.c b/src/mgcp_ss7_vty.c index 8ed27ad..5bdb658 100644 --- a/src/mgcp_ss7_vty.c +++ b/src/mgcp_ss7_vty.c @@ -29,7 +29,7 @@ extern struct mgcp_config *g_cfg; -enum node_type mgcp_go_parent(struct vty *vty); +int mgcp_go_parent(struct vty *vty); static struct vty_app_info vty_info = { .name = "mgcp_ss7", .version = "0.0.1", diff --git a/src/vty_interface.c b/src/vty_interface.c index de250d8..6c6d30f 100644 --- a/src/vty_interface.c +++ b/src/vty_interface.c @@ -48,7 +48,7 @@ extern struct bsc_data *bsc; -static enum node_type ss7_go_parent(struct vty *vty) +static int ss7_go_parent(struct vty *vty) { switch (vty->node) { case LINK_NODE: -- To view, visit https://gerrit.osmocom.org/693 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I8061df697daf79fa57b8313c15f6567ff152f4a5 Gerrit-PatchSet: 1 Gerrit-Project: cellmgr-ng Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Sun Aug 14 06:24:59 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Sun, 14 Aug 2016 06:24:59 +0000 Subject: [MERGED] cellmgr-ng[master]: mgcp: Address compiler warning and initialize In-Reply-To: References: Message-ID: Holger Freyther has submitted this change and it was merged. Change subject: mgcp: Address compiler warning and initialize ...................................................................... mgcp: Address compiler warning and initialize mgcp/mgcp_protocol.c: In function ?mgcp_handle_message?: /home/ich/install/openbsc/include/osmocom/core/logging.h:59:4: warning: ?save? may be used uninitialized in this function [-Wmaybe-uninitialized] logp2(ss, level, __BASE_FILE__, __LINE__, 0, fmt, ##args); \ ^ mgcp/mgcp_protocol.c:368:15: note: ?save? was declared here char *elem, *save; Change-Id: I28152373b043c8a5b55a83ac09dd7bafce4d2d66 --- M src/mgcp/mgcp_protocol.c 1 file changed, 1 insertion(+), 1 deletion(-) Approvals: Jenkins Builder: Verified Holger Freyther: Looks good to me, approved diff --git a/src/mgcp/mgcp_protocol.c b/src/mgcp/mgcp_protocol.c index d3561d5..40acc09 100644 --- a/src/mgcp/mgcp_protocol.c +++ b/src/mgcp/mgcp_protocol.c @@ -365,7 +365,7 @@ static int mgcp_analyze_header(struct mgcp_parse_data *pdata, char *data) { int i = 0; - char *elem, *save; + char *elem, *save = NULL; pdata->trans = "000000"; -- To view, visit https://gerrit.osmocom.org/694 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I28152373b043c8a5b55a83ac09dd7bafce4d2d66 Gerrit-PatchSet: 1 Gerrit-Project: cellmgr-ng Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 15 11:17:06 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 15 Aug 2016 11:17:06 +0000 Subject: [PATCH] cellmgr-ng[master]: debian: Add systemd service file Message-ID: Review at https://gerrit.osmocom.org/695 debian: Add systemd service file Provide a modern systemd service file for the osmo-stp. The sysvinit file is quite basic and doesn't signal syntax errors nicely. Let us embrace the future. Change-Id: Ic0cc0f17d442aa0ad38de9f0cf8aeb14121938de --- M debian/control A debian/osmo-stp.service 2 files changed, 12 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/cellmgr-ng refs/changes/95/695/1 diff --git a/debian/control b/debian/control index 6d23a4e..0f4c286 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Section: net Priority: optional Maintainer: Holger Hans Peter Freyther -Build-Depends: debhelper (>= 9), autotools-dev, pkg-config, libosmocore-dev, libosmo-sccp-dev, dh-autoreconf, libsnmp-dev, libsctp-dev +Build-Depends: debhelper (>= 9), autotools-dev, pkg-config, libosmocore-dev, libosmo-sccp-dev, dh-autoreconf, dh-systemd (>= 1.5), libsnmp-dev, libsctp-dev Standards-Version: 3.9.6 Homepage: http://openbsc.osmocom.org/ Vcs-Git: git://bs11-abis.gnumonks.org/cellmgr-ng.git diff --git a/debian/osmo-stp.service b/debian/osmo-stp.service new file mode 100644 index 0000000..cef1085 --- /dev/null +++ b/debian/osmo-stp.service @@ -0,0 +1,11 @@ +[Unit] +Description=Osmocom osmo-stp bridge + +[Service] +Type=simple +ExecStart=/usr/sbin/osmo-stp -c /etc/osmocom/osmo-stp.cfg +Restart=always +RestartSec=2 + +[Install] +WantedBy=multi-user.target -- To view, visit https://gerrit.osmocom.org/695 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ic0cc0f17d442aa0ad38de9f0cf8aeb14121938de Gerrit-PatchSet: 1 Gerrit-Project: cellmgr-ng Gerrit-Branch: master Gerrit-Owner: Holger Freyther From gerrit-no-reply at lists.osmocom.org Mon Aug 15 11:17:07 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 15 Aug 2016 11:17:07 +0000 Subject: [PATCH] cellmgr-ng[master]: tests/vty: Add VTY tests to the osmo-stp Message-ID: Review at https://gerrit.osmocom.org/696 tests/vty: Add VTY tests to the osmo-stp There seems to be issues with the write handling of the osmo-stp and so far we did not enable vty tests here. Make it possible to enable the tests, fix the VTY strings, change string to OsmoSTP. Change-Id: I547fd4840d86ce16e8589fb63802dd7099781194 --- M .gitignore M configure.ac M contrib/jenkins.sh A doc/examples/osmo-stp.cfg A osmoappdesc.py M src/sctp_m3ua_client.c M src/vty_interface.c M src/vty_interface_cmds.c M tests/Makefile.am 9 files changed, 121 insertions(+), 22 deletions(-) git pull ssh://gerrit.osmocom.org:29418/cellmgr-ng refs/changes/96/696/1 diff --git a/.gitignore b/.gitignore index 5056481..6435a26 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ *.gcda *.gcno *.info +*.pyc # binaries cellmgr_ng diff --git a/configure.ac b/configure.ac index f0a50e6..47176ac 100644 --- a/configure.ac +++ b/configure.ac @@ -28,6 +28,21 @@ PKG_CHECK_MODULES([LIBOSMOVTY], [libosmovty >= 0.3.2]) #PKG_CHECK_MODULES([NEXUSWARE_C7], [nexusware-c7]) +AC_ARG_ENABLE([external_tests], + AC_HELP_STRING([--enable-external-tests], + [Include the VTY tests in make check [default=no]]), + [enable_ext_tests="$enableval"],[enable_ext_tests="no"]) +if test "x$enable_ext_tests" = "xyes" ; then + AM_PATH_PYTHON + AC_CHECK_PROG(OSMOTESTEXT_CHECK,osmotestvty.py,yes) + if test "x$OSMOTESTEXT_CHECK" != "xyes" ; then + AC_MSG_ERROR([Please install osmocom-python to run the VTY tests.]) + fi +fi +AC_MSG_CHECKING([whether to enable VTY tests]) +AC_MSG_RESULT([$enable_ext_tests]) +AM_CONDITIONAL(ENABLE_EXT_TESTS, test "x$enable_ext_tests" = "xyes") + old_libs=$LIBS AC_CHECK_LIB([sctp], sctp_sendmsg, [], [AC_MSG_ERROR([The sctp library is required.])]) LIBS=$old_libs diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index f27f1da..208c897 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -37,5 +37,5 @@ cd ../../ autoreconf --install --force PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig ./configure -PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig $MAKE $PARALLEL_MAKE +PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig $MAKE $PARALLEL_MAKE --enable-external-tests PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig LD_LIBRARY_PATH=$PWD/deps/install/lib $MAKE distcheck diff --git a/doc/examples/osmo-stp.cfg b/doc/examples/osmo-stp.cfg new file mode 100644 index 0000000..6997bf2 --- /dev/null +++ b/doc/examples/osmo-stp.cfg @@ -0,0 +1,41 @@ +ss7 + udp src-port 4444 + m2ua src-port 5555 + linkset 0 + description My first linkset + mtp3 dpc 1 + mtp3 opc 2 + mtp3 ni 3 + link 0 + description A m2ua link + ss7-transport m2ua + linkset 1 + description My m3ua linkset + mtp3 dpc 1 + mtp3 opc 2 + mtp3 ni 3 + mtp3 spare 0 + link 0 + description A m3ua client + ss7-transport m3ua-client + msc 0 + mode server + port 5000 + token atoken + msc 1 + mode server + port 5001 + token atoken + timeout ping 20 + timeout pong 5 + timeout restart 3 + application 0 + description Relay TCP/IPA to M2UA linkset + type relay + route linkset 0 msc 0 + forward-only + application 1 + description Relay TCP/IPA to M3UA linkset + type relay + route linkset 1 msc 1 + forward-only diff --git a/osmoappdesc.py b/osmoappdesc.py new file mode 100644 index 0000000..9ad5188 --- /dev/null +++ b/osmoappdesc.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python + +# (C) 2016 by Holger Hans Peter Freyther +# 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 . + +app_configs = { + "osmo-stp": ["doc/examples/osmo-stp.cfg"] +} + +apps = [(4242, "src/osmo-stp", "OsmoSTP", "osmo-stp"), + ] + +vty_command = ["src/osmo-stp", "-c", "doc/examples/osmo-stp.cfg"] + +vty_app = apps[0] + diff --git a/src/sctp_m3ua_client.c b/src/sctp_m3ua_client.c index 01f2af7..a15860a 100644 --- a/src/sctp_m3ua_client.c +++ b/src/sctp_m3ua_client.c @@ -388,6 +388,10 @@ lnk->queue.bfd.fd = -1; lnk->traffic_mode = 2; lnk->aspac_ack_timeout = 10; + + /* default ports */ + lnk->local.sin_port = lnk->remote.sin_port = htons(2905); + return lnk; } diff --git a/src/vty_interface.c b/src/vty_interface.c index 6c6d30f..3a654c0 100644 --- a/src/vty_interface.c +++ b/src/vty_interface.c @@ -103,7 +103,7 @@ } static struct vty_app_info vty_info = { - .name = "Cellmgr-ng", + .name = "OsmoSTP", .version = VERSION, .go_parent_cb = ss7_go_parent, }; @@ -155,13 +155,13 @@ static void write_link(struct vty *vty, struct mtp_link *link) { - const char *name = link->name ? link->name : ""; struct mtp_udp_link *ulnk; struct mtp_m2ua_link *m2ua; struct mtp_m3ua_client_link *m3ua_client; vty_out(vty, " link %d%s", link->nr, VTY_NEWLINE); - vty_out(vty, " description %s%s", name, VTY_NEWLINE); + if (link->name && strlen(link->name) > 0) + vty_out(vty, " description %s%s", link->name, VTY_NEWLINE); switch (link->type) { case SS7_LTYPE_UDP: @@ -214,12 +214,12 @@ static void write_linkset(struct vty *vty, struct mtp_link_set *set) { - const char *name = set->name ? set->name : ""; struct mtp_link *link; int i; vty_out(vty, " linkset %d%s", set->nr, VTY_NEWLINE); - vty_out(vty, " description %s%s", name, VTY_NEWLINE); + if (set->name && strlen(set->name) > 0) + vty_out(vty, " description %s%s", set->name, VTY_NEWLINE); vty_out(vty, " mtp3 dpc %d%s", set->dpc, VTY_NEWLINE); vty_out(vty, " mtp3 opc %d%s", set->opc, VTY_NEWLINE); vty_out(vty, " mtp3 ni %d%s", set->ni, VTY_NEWLINE); @@ -260,18 +260,20 @@ static void write_msc(struct vty *vty, struct msc_connection *msc) { - const char *name = msc->name ? msc->name : ""; vty_out(vty, " msc %d%s", msc->nr, VTY_NEWLINE); - vty_out(vty, " description %s%s", name, VTY_NEWLINE); + if (msc->name && strlen(msc->name) > 0) + vty_out(vty, " description %s%s", msc->name, VTY_NEWLINE); vty_out(vty, " mode %s%s", msc_mode(msc), VTY_NEWLINE); if (msc->ip) vty_out(vty, " ip %s%s", msc->ip, VTY_NEWLINE); vty_out(vty, " port %d%s", msc->port, VTY_NEWLINE); vty_out(vty, " token %s%s", msc->token, VTY_NEWLINE); vty_out(vty, " dscp %d%s", msc->dscp, VTY_NEWLINE); - vty_out(vty, " timeout ping %d%s", msc->ping_time, VTY_NEWLINE); - vty_out(vty, " timeout pong %d%s", msc->pong_time, VTY_NEWLINE); + if (msc->ping_time > 0) { + vty_out(vty, " timeout ping %d%s", msc->ping_time, VTY_NEWLINE); + vty_out(vty, " timeout pong %d%s", msc->pong_time, VTY_NEWLINE); + } vty_out(vty, " timeout restart %d%s", msc->msc_time, VTY_NEWLINE); } @@ -316,10 +318,9 @@ static void write_application(struct vty *vty, struct ss7_application *app) { - const char *name = app->name ? app->name : ""; - vty_out(vty, " application %d%s", app->nr, VTY_NEWLINE); - vty_out(vty, " description %s%s", name, VTY_NEWLINE); + if (app->name && strlen(app->name) > 0) + vty_out(vty, " description %s%s", app->name, VTY_NEWLINE); vty_out(vty, " type %s%s", app_type(app->type), VTY_NEWLINE); if (app->fixed_ass_cmpl_reply) @@ -463,7 +464,7 @@ DEFUN(cfg_linkset_no_mtp3_ssn, cfg_linkset_no_mtp3_ssn_cmd, "no mtp3 ssn <0-255>", - "MTP Level3\n" "SSN supported\n" "SSN\n") + NO_STR "MTP Level3\n" "SSN supported\n" "SSN\n") { struct mtp_link_set *set = vty->index; set->supported_ssn[atoi(argv[0])] = 0; @@ -604,7 +605,7 @@ DEFUN(cfg_link_ss7_transport, cfg_link_ss7_transport_cmd, "ss7-transport (none|udp|m2ua|m3ua-client)", "SS7 transport for the link\n" - "No transport\n" "MTP over UDP\n" "SCTP M2UA\n") + "No transport\n" "MTP over UDP\n" "SCTP M2UA server\n" "SCTP M3UA client\n") { int wanted = SS7_LTYPE_NONE; struct mtp_link *link; @@ -648,7 +649,7 @@ DEFUN(cfg_link_udp_dest_ip, cfg_link_udp_dest_ip_cmd, "udp dest ip HOST_NAME", - "UDP Transport\n" "IP\n" "Hostname\n") + "UDP Transport\n" "Destination\n" "IP\n" "Hostname\n") { struct hostent *hosts; @@ -684,7 +685,7 @@ DEFUN(cfg_link_udp_dest_port, cfg_link_udp_dest_port_cmd, "udp dest port <1-65535>", - "UDP Transport\n" "Set the port number\n" "Port\n") + "UDP Transport\n" "Destination\n" "Set the port number\n" "Port\n") { struct mtp_link *link = vty->index; struct mtp_udp_link *ulnk; @@ -896,7 +897,7 @@ DEFUN(cfg_link_m3ua_client_traffic_mode, cfg_link_m3ua_client_traffic_mode_cmd, "m3ua-client traffic-mode (override|loadshare|broadcast)", - "M3UA Client\n" "Traffic Mode\n" "Override" "Loadshare\n" "Broadcast\n") + "M3UA Client\n" "Traffic Mode\n" "Override\n" "Loadshare\n" "Broadcast\n") { struct mtp_link *link = vty->index; struct mtp_m3ua_client_link *m3ua_link; @@ -1047,7 +1048,7 @@ } DEFUN(cfg_msc_timeout_restart, cfg_msc_timeout_restart_cmd, - "timeout restart <1-65535>", + "timeout restart <0-65535>", "Timeout commands\n" "Time between restarts\n" "Seconds\n") { struct msc_connection *msc = vty->index; @@ -1306,7 +1307,7 @@ DEFUN(cfg_app_no_hardcode_ass, cfg_app_no_hardcode_ass_cmd, "no hardcode-assignment-complete", - "Hardcode the assignment complete message to HR3\n") + NO_STR "Hardcode the assignment complete message to HR3\n") { struct ss7_application *app = vty->index; app->fixed_ass_cmpl_reply = 0; diff --git a/src/vty_interface_cmds.c b/src/vty_interface_cmds.c index 78e67c0..7c634c0 100644 --- a/src/vty_interface_cmds.c +++ b/src/vty_interface_cmds.c @@ -280,7 +280,7 @@ DEFUN(show_sctp_count, show_sctp_count_cmd, "show sctp-connections count", - SHOW_STR "Number of SCTP connections\n") + SHOW_STR "SCTP connections\n" "Number of connections\n") { int count = sctp_m2ua_conn_count(bsc->m2ua_trans); vty_out(vty, "Active SCTP connections are: %d.%s", count, VTY_NEWLINE); @@ -289,7 +289,7 @@ DEFUN(show_sctp_details, show_sctp_details_cmd, "show sctp-connections details", - SHOW_STR "Details of SCTP connections\n") + SHOW_STR "SCTP connections\n" "Details\n") { struct sctp_m2ua_conn *conn; diff --git a/tests/Makefile.am b/tests/Makefile.am index 5c9cdd5..6276980 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -20,9 +20,19 @@ EXTRA_DIST = testsuite.at $(srcdir)/package.m4 $(TESTSUITE) TESTSUITE = $(srcdir)/testsuite + +if ENABLE_EXT_TESTS +python-tests: $(BUILT_SOURCES) + osmotestvty.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v + osmotestconfig.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v +else +python-tests: $(BUILT_SOURCES) + echo "Not running python-based tests (determined at configure-time)" +endif check-local: atconfig $(TESTSUITE) $(SHELL) '$(TESTSUITE)' $(TESTSUITEFLAGS) + $(MAKE) $(AM_MAKEFLAGS) python-tests installcheck-local: atconfig $(TESTSUITE) $(SHELL) '$(TESTSUITE)' AUTOTEST_PATH='$(bindir)' \ -- To view, visit https://gerrit.osmocom.org/696 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I547fd4840d86ce16e8589fb63802dd7099781194 Gerrit-PatchSet: 1 Gerrit-Project: cellmgr-ng Gerrit-Branch: master Gerrit-Owner: Holger Freyther From gerrit-no-reply at lists.osmocom.org Mon Aug 15 11:25:08 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 15 Aug 2016 11:25:08 +0000 Subject: [PATCH] cellmgr-ng[master]: misc: Attempt to fix various 64bit compiler warnings Message-ID: Review at https://gerrit.osmocom.org/697 misc: Attempt to fix various 64bit compiler warnings Change-Id: I4ed058aba15d9fdc22dde99d60df0aabd6585b75 --- M src/link_udp.c M src/mgcp_ss7.c M src/msc_conn.c M src/sctp_m3ua_client.c M tests/patching/patching_test.c 5 files changed, 5 insertions(+), 5 deletions(-) git pull ssh://gerrit.osmocom.org:29418/cellmgr-ng refs/changes/97/697/1 diff --git a/src/link_udp.c b/src/link_udp.c index 85f6c09..d66c1cd 100644 --- a/src/link_udp.c +++ b/src/link_udp.c @@ -149,7 +149,7 @@ length = ntohl(hdr->data_length); if (length + sizeof(*hdr) > (unsigned int) rc) { LOGP(DINP, LOGL_ERROR, - "The MSU payload does not fit: %u + %u > %d on link %d/%s of %d/%s.\n", + "The MSU payload does not fit: %u + %zu > %d on link %d/%s of %d/%s.\n", length, sizeof(*hdr), rc, link->nr, link->name, link->set->nr, link->set->name); rc = 0; diff --git a/src/mgcp_ss7.c b/src/mgcp_ss7.c index 6604545..6e616e5 100644 --- a/src/mgcp_ss7.c +++ b/src/mgcp_ss7.c @@ -733,7 +733,7 @@ perror("Gateway failed to read"); return -1; } else if (slen > sizeof(addr)) { - fprintf(stderr, "Gateway received message from outerspace: %d %d\n", + fprintf(stderr, "Gateway received message from outerspace: %zu %zu\n", slen, sizeof(addr)); return -1; } diff --git a/src/msc_conn.c b/src/msc_conn.c index 82ca811..703c761 100644 --- a/src/msc_conn.c +++ b/src/msc_conn.c @@ -605,7 +605,7 @@ len = msgb_l2len(msg) - 4; if (len != strlen(msc->token)) { - LOGP(DMSC, LOGL_ERROR, "Wrong length %u vs. %u\n", + LOGP(DMSC, LOGL_ERROR, "Wrong length %u vs. %zu\n", len, strlen(msc->token)); goto clean; } diff --git a/src/sctp_m3ua_client.c b/src/sctp_m3ua_client.c index a15860a..bf9204a 100644 --- a/src/sctp_m3ua_client.c +++ b/src/sctp_m3ua_client.c @@ -573,7 +573,7 @@ dpc = ntohl(proto->dpc); sls = proto->sls; si = proto->si; - LOGP(DINP, LOGL_DEBUG, "Got data for OPC(%d)/DPC(%d)/SLS(%d) len(%d)\n", + LOGP(DINP, LOGL_DEBUG, "Got data for OPC(%d)/DPC(%d)/SLS(%d) len(%zu)\n", opc, dpc, sls, msgb_l2len(msg) - sizeof(*proto)); diff --git a/tests/patching/patching_test.c b/tests/patching/patching_test.c index 9208788..54e8677 100644 --- a/tests/patching/patching_test.c +++ b/tests/patching/patching_test.c @@ -368,7 +368,7 @@ } if (msgb_l2len(outp) != sizeof(dt1_ass_compl_hardcoded)) { - printf("The length's don't match on %u != %u\n", + printf("The length's don't match on %zu != %zu\n", msgb_l2len(outp), sizeof(dt1_ass_compl_hardcoded)); printf("hex: %s\n", osmo_hexdump(outp->l2h, msgb_l2len(outp))); abort(); -- To view, visit https://gerrit.osmocom.org/697 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I4ed058aba15d9fdc22dde99d60df0aabd6585b75 Gerrit-PatchSet: 1 Gerrit-Project: cellmgr-ng Gerrit-Branch: master Gerrit-Owner: Holger Freyther From gerrit-no-reply at lists.osmocom.org Mon Aug 15 11:26:57 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 15 Aug 2016 11:26:57 +0000 Subject: [PATCH] cellmgr-ng[master]: tests/vty: Add VTY tests to the osmo-stp In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/696 to look at the new patch set (#2). tests/vty: Add VTY tests to the osmo-stp There seems to be issues with the write handling of the osmo-stp and so far we did not enable vty tests here. Make it possible to enable the tests, fix the VTY strings, change string to OsmoSTP. Change-Id: I547fd4840d86ce16e8589fb63802dd7099781194 --- M .gitignore M configure.ac M contrib/jenkins.sh A doc/examples/osmo-stp.cfg A osmoappdesc.py M src/sctp_m3ua_client.c M src/vty_interface.c M src/vty_interface_cmds.c M tests/Makefile.am 9 files changed, 121 insertions(+), 22 deletions(-) git pull ssh://gerrit.osmocom.org:29418/cellmgr-ng refs/changes/96/696/2 diff --git a/.gitignore b/.gitignore index 5056481..6435a26 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ *.gcda *.gcno *.info +*.pyc # binaries cellmgr_ng diff --git a/configure.ac b/configure.ac index f0a50e6..47176ac 100644 --- a/configure.ac +++ b/configure.ac @@ -28,6 +28,21 @@ PKG_CHECK_MODULES([LIBOSMOVTY], [libosmovty >= 0.3.2]) #PKG_CHECK_MODULES([NEXUSWARE_C7], [nexusware-c7]) +AC_ARG_ENABLE([external_tests], + AC_HELP_STRING([--enable-external-tests], + [Include the VTY tests in make check [default=no]]), + [enable_ext_tests="$enableval"],[enable_ext_tests="no"]) +if test "x$enable_ext_tests" = "xyes" ; then + AM_PATH_PYTHON + AC_CHECK_PROG(OSMOTESTEXT_CHECK,osmotestvty.py,yes) + if test "x$OSMOTESTEXT_CHECK" != "xyes" ; then + AC_MSG_ERROR([Please install osmocom-python to run the VTY tests.]) + fi +fi +AC_MSG_CHECKING([whether to enable VTY tests]) +AC_MSG_RESULT([$enable_ext_tests]) +AM_CONDITIONAL(ENABLE_EXT_TESTS, test "x$enable_ext_tests" = "xyes") + old_libs=$LIBS AC_CHECK_LIB([sctp], sctp_sendmsg, [], [AC_MSG_ERROR([The sctp library is required.])]) LIBS=$old_libs diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index f27f1da..4aa644c 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -36,6 +36,6 @@ cd ../../ autoreconf --install --force -PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig ./configure +PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig ./configure --enable-external-tests PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig $MAKE $PARALLEL_MAKE PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig LD_LIBRARY_PATH=$PWD/deps/install/lib $MAKE distcheck diff --git a/doc/examples/osmo-stp.cfg b/doc/examples/osmo-stp.cfg new file mode 100644 index 0000000..6997bf2 --- /dev/null +++ b/doc/examples/osmo-stp.cfg @@ -0,0 +1,41 @@ +ss7 + udp src-port 4444 + m2ua src-port 5555 + linkset 0 + description My first linkset + mtp3 dpc 1 + mtp3 opc 2 + mtp3 ni 3 + link 0 + description A m2ua link + ss7-transport m2ua + linkset 1 + description My m3ua linkset + mtp3 dpc 1 + mtp3 opc 2 + mtp3 ni 3 + mtp3 spare 0 + link 0 + description A m3ua client + ss7-transport m3ua-client + msc 0 + mode server + port 5000 + token atoken + msc 1 + mode server + port 5001 + token atoken + timeout ping 20 + timeout pong 5 + timeout restart 3 + application 0 + description Relay TCP/IPA to M2UA linkset + type relay + route linkset 0 msc 0 + forward-only + application 1 + description Relay TCP/IPA to M3UA linkset + type relay + route linkset 1 msc 1 + forward-only diff --git a/osmoappdesc.py b/osmoappdesc.py new file mode 100644 index 0000000..9ad5188 --- /dev/null +++ b/osmoappdesc.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python + +# (C) 2016 by Holger Hans Peter Freyther +# 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 . + +app_configs = { + "osmo-stp": ["doc/examples/osmo-stp.cfg"] +} + +apps = [(4242, "src/osmo-stp", "OsmoSTP", "osmo-stp"), + ] + +vty_command = ["src/osmo-stp", "-c", "doc/examples/osmo-stp.cfg"] + +vty_app = apps[0] + diff --git a/src/sctp_m3ua_client.c b/src/sctp_m3ua_client.c index 3726dab..bf9204a 100644 --- a/src/sctp_m3ua_client.c +++ b/src/sctp_m3ua_client.c @@ -388,6 +388,10 @@ lnk->queue.bfd.fd = -1; lnk->traffic_mode = 2; lnk->aspac_ack_timeout = 10; + + /* default ports */ + lnk->local.sin_port = lnk->remote.sin_port = htons(2905); + return lnk; } diff --git a/src/vty_interface.c b/src/vty_interface.c index 6c6d30f..3a654c0 100644 --- a/src/vty_interface.c +++ b/src/vty_interface.c @@ -103,7 +103,7 @@ } static struct vty_app_info vty_info = { - .name = "Cellmgr-ng", + .name = "OsmoSTP", .version = VERSION, .go_parent_cb = ss7_go_parent, }; @@ -155,13 +155,13 @@ static void write_link(struct vty *vty, struct mtp_link *link) { - const char *name = link->name ? link->name : ""; struct mtp_udp_link *ulnk; struct mtp_m2ua_link *m2ua; struct mtp_m3ua_client_link *m3ua_client; vty_out(vty, " link %d%s", link->nr, VTY_NEWLINE); - vty_out(vty, " description %s%s", name, VTY_NEWLINE); + if (link->name && strlen(link->name) > 0) + vty_out(vty, " description %s%s", link->name, VTY_NEWLINE); switch (link->type) { case SS7_LTYPE_UDP: @@ -214,12 +214,12 @@ static void write_linkset(struct vty *vty, struct mtp_link_set *set) { - const char *name = set->name ? set->name : ""; struct mtp_link *link; int i; vty_out(vty, " linkset %d%s", set->nr, VTY_NEWLINE); - vty_out(vty, " description %s%s", name, VTY_NEWLINE); + if (set->name && strlen(set->name) > 0) + vty_out(vty, " description %s%s", set->name, VTY_NEWLINE); vty_out(vty, " mtp3 dpc %d%s", set->dpc, VTY_NEWLINE); vty_out(vty, " mtp3 opc %d%s", set->opc, VTY_NEWLINE); vty_out(vty, " mtp3 ni %d%s", set->ni, VTY_NEWLINE); @@ -260,18 +260,20 @@ static void write_msc(struct vty *vty, struct msc_connection *msc) { - const char *name = msc->name ? msc->name : ""; vty_out(vty, " msc %d%s", msc->nr, VTY_NEWLINE); - vty_out(vty, " description %s%s", name, VTY_NEWLINE); + if (msc->name && strlen(msc->name) > 0) + vty_out(vty, " description %s%s", msc->name, VTY_NEWLINE); vty_out(vty, " mode %s%s", msc_mode(msc), VTY_NEWLINE); if (msc->ip) vty_out(vty, " ip %s%s", msc->ip, VTY_NEWLINE); vty_out(vty, " port %d%s", msc->port, VTY_NEWLINE); vty_out(vty, " token %s%s", msc->token, VTY_NEWLINE); vty_out(vty, " dscp %d%s", msc->dscp, VTY_NEWLINE); - vty_out(vty, " timeout ping %d%s", msc->ping_time, VTY_NEWLINE); - vty_out(vty, " timeout pong %d%s", msc->pong_time, VTY_NEWLINE); + if (msc->ping_time > 0) { + vty_out(vty, " timeout ping %d%s", msc->ping_time, VTY_NEWLINE); + vty_out(vty, " timeout pong %d%s", msc->pong_time, VTY_NEWLINE); + } vty_out(vty, " timeout restart %d%s", msc->msc_time, VTY_NEWLINE); } @@ -316,10 +318,9 @@ static void write_application(struct vty *vty, struct ss7_application *app) { - const char *name = app->name ? app->name : ""; - vty_out(vty, " application %d%s", app->nr, VTY_NEWLINE); - vty_out(vty, " description %s%s", name, VTY_NEWLINE); + if (app->name && strlen(app->name) > 0) + vty_out(vty, " description %s%s", app->name, VTY_NEWLINE); vty_out(vty, " type %s%s", app_type(app->type), VTY_NEWLINE); if (app->fixed_ass_cmpl_reply) @@ -463,7 +464,7 @@ DEFUN(cfg_linkset_no_mtp3_ssn, cfg_linkset_no_mtp3_ssn_cmd, "no mtp3 ssn <0-255>", - "MTP Level3\n" "SSN supported\n" "SSN\n") + NO_STR "MTP Level3\n" "SSN supported\n" "SSN\n") { struct mtp_link_set *set = vty->index; set->supported_ssn[atoi(argv[0])] = 0; @@ -604,7 +605,7 @@ DEFUN(cfg_link_ss7_transport, cfg_link_ss7_transport_cmd, "ss7-transport (none|udp|m2ua|m3ua-client)", "SS7 transport for the link\n" - "No transport\n" "MTP over UDP\n" "SCTP M2UA\n") + "No transport\n" "MTP over UDP\n" "SCTP M2UA server\n" "SCTP M3UA client\n") { int wanted = SS7_LTYPE_NONE; struct mtp_link *link; @@ -648,7 +649,7 @@ DEFUN(cfg_link_udp_dest_ip, cfg_link_udp_dest_ip_cmd, "udp dest ip HOST_NAME", - "UDP Transport\n" "IP\n" "Hostname\n") + "UDP Transport\n" "Destination\n" "IP\n" "Hostname\n") { struct hostent *hosts; @@ -684,7 +685,7 @@ DEFUN(cfg_link_udp_dest_port, cfg_link_udp_dest_port_cmd, "udp dest port <1-65535>", - "UDP Transport\n" "Set the port number\n" "Port\n") + "UDP Transport\n" "Destination\n" "Set the port number\n" "Port\n") { struct mtp_link *link = vty->index; struct mtp_udp_link *ulnk; @@ -896,7 +897,7 @@ DEFUN(cfg_link_m3ua_client_traffic_mode, cfg_link_m3ua_client_traffic_mode_cmd, "m3ua-client traffic-mode (override|loadshare|broadcast)", - "M3UA Client\n" "Traffic Mode\n" "Override" "Loadshare\n" "Broadcast\n") + "M3UA Client\n" "Traffic Mode\n" "Override\n" "Loadshare\n" "Broadcast\n") { struct mtp_link *link = vty->index; struct mtp_m3ua_client_link *m3ua_link; @@ -1047,7 +1048,7 @@ } DEFUN(cfg_msc_timeout_restart, cfg_msc_timeout_restart_cmd, - "timeout restart <1-65535>", + "timeout restart <0-65535>", "Timeout commands\n" "Time between restarts\n" "Seconds\n") { struct msc_connection *msc = vty->index; @@ -1306,7 +1307,7 @@ DEFUN(cfg_app_no_hardcode_ass, cfg_app_no_hardcode_ass_cmd, "no hardcode-assignment-complete", - "Hardcode the assignment complete message to HR3\n") + NO_STR "Hardcode the assignment complete message to HR3\n") { struct ss7_application *app = vty->index; app->fixed_ass_cmpl_reply = 0; diff --git a/src/vty_interface_cmds.c b/src/vty_interface_cmds.c index 78e67c0..7c634c0 100644 --- a/src/vty_interface_cmds.c +++ b/src/vty_interface_cmds.c @@ -280,7 +280,7 @@ DEFUN(show_sctp_count, show_sctp_count_cmd, "show sctp-connections count", - SHOW_STR "Number of SCTP connections\n") + SHOW_STR "SCTP connections\n" "Number of connections\n") { int count = sctp_m2ua_conn_count(bsc->m2ua_trans); vty_out(vty, "Active SCTP connections are: %d.%s", count, VTY_NEWLINE); @@ -289,7 +289,7 @@ DEFUN(show_sctp_details, show_sctp_details_cmd, "show sctp-connections details", - SHOW_STR "Details of SCTP connections\n") + SHOW_STR "SCTP connections\n" "Details\n") { struct sctp_m2ua_conn *conn; diff --git a/tests/Makefile.am b/tests/Makefile.am index 5c9cdd5..6276980 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -20,9 +20,19 @@ EXTRA_DIST = testsuite.at $(srcdir)/package.m4 $(TESTSUITE) TESTSUITE = $(srcdir)/testsuite + +if ENABLE_EXT_TESTS +python-tests: $(BUILT_SOURCES) + osmotestvty.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v + osmotestconfig.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v +else +python-tests: $(BUILT_SOURCES) + echo "Not running python-based tests (determined at configure-time)" +endif check-local: atconfig $(TESTSUITE) $(SHELL) '$(TESTSUITE)' $(TESTSUITEFLAGS) + $(MAKE) $(AM_MAKEFLAGS) python-tests installcheck-local: atconfig $(TESTSUITE) $(SHELL) '$(TESTSUITE)' AUTOTEST_PATH='$(bindir)' \ -- To view, visit https://gerrit.osmocom.org/696 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I547fd4840d86ce16e8589fb63802dd7099781194 Gerrit-PatchSet: 2 Gerrit-Project: cellmgr-ng Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 15 11:36:28 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 15 Aug 2016 11:36:28 +0000 Subject: [PATCH] cellmgr-ng[master]: misc: Attempt to fix various 64bit compiler warnings In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/697 to look at the new patch set (#3). misc: Attempt to fix various 64bit compiler warnings Change-Id: I4ed058aba15d9fdc22dde99d60df0aabd6585b75 --- M src/link_udp.c M src/mgcp_ss7.c M src/msc_conn.c M src/sctp_m3ua_client.c M tests/patching/patching_test.c 5 files changed, 6 insertions(+), 6 deletions(-) git pull ssh://gerrit.osmocom.org:29418/cellmgr-ng refs/changes/97/697/3 diff --git a/src/link_udp.c b/src/link_udp.c index 85f6c09..d66c1cd 100644 --- a/src/link_udp.c +++ b/src/link_udp.c @@ -149,7 +149,7 @@ length = ntohl(hdr->data_length); if (length + sizeof(*hdr) > (unsigned int) rc) { LOGP(DINP, LOGL_ERROR, - "The MSU payload does not fit: %u + %u > %d on link %d/%s of %d/%s.\n", + "The MSU payload does not fit: %u + %zu > %d on link %d/%s of %d/%s.\n", length, sizeof(*hdr), rc, link->nr, link->name, link->set->nr, link->set->name); rc = 0; diff --git a/src/mgcp_ss7.c b/src/mgcp_ss7.c index 6604545..317832c 100644 --- a/src/mgcp_ss7.c +++ b/src/mgcp_ss7.c @@ -733,8 +733,8 @@ perror("Gateway failed to read"); return -1; } else if (slen > sizeof(addr)) { - fprintf(stderr, "Gateway received message from outerspace: %d %d\n", - slen, sizeof(addr)); + fprintf(stderr, "Gateway received message from outerspace: %u %zu\n", + (unsigned int) slen, sizeof(addr)); return -1; } diff --git a/src/msc_conn.c b/src/msc_conn.c index 82ca811..703c761 100644 --- a/src/msc_conn.c +++ b/src/msc_conn.c @@ -605,7 +605,7 @@ len = msgb_l2len(msg) - 4; if (len != strlen(msc->token)) { - LOGP(DMSC, LOGL_ERROR, "Wrong length %u vs. %u\n", + LOGP(DMSC, LOGL_ERROR, "Wrong length %u vs. %zu\n", len, strlen(msc->token)); goto clean; } diff --git a/src/sctp_m3ua_client.c b/src/sctp_m3ua_client.c index 01f2af7..3726dab 100644 --- a/src/sctp_m3ua_client.c +++ b/src/sctp_m3ua_client.c @@ -569,7 +569,7 @@ dpc = ntohl(proto->dpc); sls = proto->sls; si = proto->si; - LOGP(DINP, LOGL_DEBUG, "Got data for OPC(%d)/DPC(%d)/SLS(%d) len(%d)\n", + LOGP(DINP, LOGL_DEBUG, "Got data for OPC(%d)/DPC(%d)/SLS(%d) len(%zu)\n", opc, dpc, sls, msgb_l2len(msg) - sizeof(*proto)); diff --git a/tests/patching/patching_test.c b/tests/patching/patching_test.c index 9208788..26d4a52 100644 --- a/tests/patching/patching_test.c +++ b/tests/patching/patching_test.c @@ -368,7 +368,7 @@ } if (msgb_l2len(outp) != sizeof(dt1_ass_compl_hardcoded)) { - printf("The length's don't match on %u != %u\n", + printf("The length's don't match on %u != %zu\n", msgb_l2len(outp), sizeof(dt1_ass_compl_hardcoded)); printf("hex: %s\n", osmo_hexdump(outp->l2h, msgb_l2len(outp))); abort(); -- To view, visit https://gerrit.osmocom.org/697 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I4ed058aba15d9fdc22dde99d60df0aabd6585b75 Gerrit-PatchSet: 3 Gerrit-Project: cellmgr-ng Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 15 11:44:15 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 15 Aug 2016 11:44:15 +0000 Subject: cellmgr-ng[master]: misc: Attempt to fix various 64bit compiler warnings In-Reply-To: References: Message-ID: Patch Set 3: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/697 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I4ed058aba15d9fdc22dde99d60df0aabd6585b75 Gerrit-PatchSet: 3 Gerrit-Project: cellmgr-ng Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 15 11:44:21 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 15 Aug 2016 11:44:21 +0000 Subject: cellmgr-ng[master]: debian: Add systemd service file In-Reply-To: References: Message-ID: Patch Set 3: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/695 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ic0cc0f17d442aa0ad38de9f0cf8aeb14121938de Gerrit-PatchSet: 3 Gerrit-Project: cellmgr-ng Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 15 11:44:56 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 15 Aug 2016 11:44:56 +0000 Subject: cellmgr-ng[master]: tests/vty: Add VTY tests to the osmo-stp In-Reply-To: References: Message-ID: Patch Set 3: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/696 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I547fd4840d86ce16e8589fb63802dd7099781194 Gerrit-PatchSet: 3 Gerrit-Project: cellmgr-ng Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 15 11:45:24 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 15 Aug 2016 11:45:24 +0000 Subject: [MERGED] cellmgr-ng[master]: tests/vty: Add VTY tests to the osmo-stp In-Reply-To: References: Message-ID: Holger Freyther has submitted this change and it was merged. Change subject: tests/vty: Add VTY tests to the osmo-stp ...................................................................... tests/vty: Add VTY tests to the osmo-stp There seems to be issues with the write handling of the osmo-stp and so far we did not enable vty tests here. Make it possible to enable the tests, fix the VTY strings, change string to OsmoSTP. Change-Id: I547fd4840d86ce16e8589fb63802dd7099781194 --- M .gitignore M configure.ac M contrib/jenkins.sh A doc/examples/osmo-stp.cfg A osmoappdesc.py M src/sctp_m3ua_client.c M src/vty_interface.c M src/vty_interface_cmds.c M tests/Makefile.am 9 files changed, 121 insertions(+), 22 deletions(-) Approvals: Jenkins Builder: Verified Holger Freyther: Looks good to me, approved diff --git a/.gitignore b/.gitignore index 5056481..6435a26 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ *.gcda *.gcno *.info +*.pyc # binaries cellmgr_ng diff --git a/configure.ac b/configure.ac index f0a50e6..47176ac 100644 --- a/configure.ac +++ b/configure.ac @@ -28,6 +28,21 @@ PKG_CHECK_MODULES([LIBOSMOVTY], [libosmovty >= 0.3.2]) #PKG_CHECK_MODULES([NEXUSWARE_C7], [nexusware-c7]) +AC_ARG_ENABLE([external_tests], + AC_HELP_STRING([--enable-external-tests], + [Include the VTY tests in make check [default=no]]), + [enable_ext_tests="$enableval"],[enable_ext_tests="no"]) +if test "x$enable_ext_tests" = "xyes" ; then + AM_PATH_PYTHON + AC_CHECK_PROG(OSMOTESTEXT_CHECK,osmotestvty.py,yes) + if test "x$OSMOTESTEXT_CHECK" != "xyes" ; then + AC_MSG_ERROR([Please install osmocom-python to run the VTY tests.]) + fi +fi +AC_MSG_CHECKING([whether to enable VTY tests]) +AC_MSG_RESULT([$enable_ext_tests]) +AM_CONDITIONAL(ENABLE_EXT_TESTS, test "x$enable_ext_tests" = "xyes") + old_libs=$LIBS AC_CHECK_LIB([sctp], sctp_sendmsg, [], [AC_MSG_ERROR([The sctp library is required.])]) LIBS=$old_libs diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index f27f1da..4aa644c 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -36,6 +36,6 @@ cd ../../ autoreconf --install --force -PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig ./configure +PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig ./configure --enable-external-tests PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig $MAKE $PARALLEL_MAKE PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig LD_LIBRARY_PATH=$PWD/deps/install/lib $MAKE distcheck diff --git a/doc/examples/osmo-stp.cfg b/doc/examples/osmo-stp.cfg new file mode 100644 index 0000000..6997bf2 --- /dev/null +++ b/doc/examples/osmo-stp.cfg @@ -0,0 +1,41 @@ +ss7 + udp src-port 4444 + m2ua src-port 5555 + linkset 0 + description My first linkset + mtp3 dpc 1 + mtp3 opc 2 + mtp3 ni 3 + link 0 + description A m2ua link + ss7-transport m2ua + linkset 1 + description My m3ua linkset + mtp3 dpc 1 + mtp3 opc 2 + mtp3 ni 3 + mtp3 spare 0 + link 0 + description A m3ua client + ss7-transport m3ua-client + msc 0 + mode server + port 5000 + token atoken + msc 1 + mode server + port 5001 + token atoken + timeout ping 20 + timeout pong 5 + timeout restart 3 + application 0 + description Relay TCP/IPA to M2UA linkset + type relay + route linkset 0 msc 0 + forward-only + application 1 + description Relay TCP/IPA to M3UA linkset + type relay + route linkset 1 msc 1 + forward-only diff --git a/osmoappdesc.py b/osmoappdesc.py new file mode 100644 index 0000000..9ad5188 --- /dev/null +++ b/osmoappdesc.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python + +# (C) 2016 by Holger Hans Peter Freyther +# 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 . + +app_configs = { + "osmo-stp": ["doc/examples/osmo-stp.cfg"] +} + +apps = [(4242, "src/osmo-stp", "OsmoSTP", "osmo-stp"), + ] + +vty_command = ["src/osmo-stp", "-c", "doc/examples/osmo-stp.cfg"] + +vty_app = apps[0] + diff --git a/src/sctp_m3ua_client.c b/src/sctp_m3ua_client.c index 3726dab..bf9204a 100644 --- a/src/sctp_m3ua_client.c +++ b/src/sctp_m3ua_client.c @@ -388,6 +388,10 @@ lnk->queue.bfd.fd = -1; lnk->traffic_mode = 2; lnk->aspac_ack_timeout = 10; + + /* default ports */ + lnk->local.sin_port = lnk->remote.sin_port = htons(2905); + return lnk; } diff --git a/src/vty_interface.c b/src/vty_interface.c index 6c6d30f..3a654c0 100644 --- a/src/vty_interface.c +++ b/src/vty_interface.c @@ -103,7 +103,7 @@ } static struct vty_app_info vty_info = { - .name = "Cellmgr-ng", + .name = "OsmoSTP", .version = VERSION, .go_parent_cb = ss7_go_parent, }; @@ -155,13 +155,13 @@ static void write_link(struct vty *vty, struct mtp_link *link) { - const char *name = link->name ? link->name : ""; struct mtp_udp_link *ulnk; struct mtp_m2ua_link *m2ua; struct mtp_m3ua_client_link *m3ua_client; vty_out(vty, " link %d%s", link->nr, VTY_NEWLINE); - vty_out(vty, " description %s%s", name, VTY_NEWLINE); + if (link->name && strlen(link->name) > 0) + vty_out(vty, " description %s%s", link->name, VTY_NEWLINE); switch (link->type) { case SS7_LTYPE_UDP: @@ -214,12 +214,12 @@ static void write_linkset(struct vty *vty, struct mtp_link_set *set) { - const char *name = set->name ? set->name : ""; struct mtp_link *link; int i; vty_out(vty, " linkset %d%s", set->nr, VTY_NEWLINE); - vty_out(vty, " description %s%s", name, VTY_NEWLINE); + if (set->name && strlen(set->name) > 0) + vty_out(vty, " description %s%s", set->name, VTY_NEWLINE); vty_out(vty, " mtp3 dpc %d%s", set->dpc, VTY_NEWLINE); vty_out(vty, " mtp3 opc %d%s", set->opc, VTY_NEWLINE); vty_out(vty, " mtp3 ni %d%s", set->ni, VTY_NEWLINE); @@ -260,18 +260,20 @@ static void write_msc(struct vty *vty, struct msc_connection *msc) { - const char *name = msc->name ? msc->name : ""; vty_out(vty, " msc %d%s", msc->nr, VTY_NEWLINE); - vty_out(vty, " description %s%s", name, VTY_NEWLINE); + if (msc->name && strlen(msc->name) > 0) + vty_out(vty, " description %s%s", msc->name, VTY_NEWLINE); vty_out(vty, " mode %s%s", msc_mode(msc), VTY_NEWLINE); if (msc->ip) vty_out(vty, " ip %s%s", msc->ip, VTY_NEWLINE); vty_out(vty, " port %d%s", msc->port, VTY_NEWLINE); vty_out(vty, " token %s%s", msc->token, VTY_NEWLINE); vty_out(vty, " dscp %d%s", msc->dscp, VTY_NEWLINE); - vty_out(vty, " timeout ping %d%s", msc->ping_time, VTY_NEWLINE); - vty_out(vty, " timeout pong %d%s", msc->pong_time, VTY_NEWLINE); + if (msc->ping_time > 0) { + vty_out(vty, " timeout ping %d%s", msc->ping_time, VTY_NEWLINE); + vty_out(vty, " timeout pong %d%s", msc->pong_time, VTY_NEWLINE); + } vty_out(vty, " timeout restart %d%s", msc->msc_time, VTY_NEWLINE); } @@ -316,10 +318,9 @@ static void write_application(struct vty *vty, struct ss7_application *app) { - const char *name = app->name ? app->name : ""; - vty_out(vty, " application %d%s", app->nr, VTY_NEWLINE); - vty_out(vty, " description %s%s", name, VTY_NEWLINE); + if (app->name && strlen(app->name) > 0) + vty_out(vty, " description %s%s", app->name, VTY_NEWLINE); vty_out(vty, " type %s%s", app_type(app->type), VTY_NEWLINE); if (app->fixed_ass_cmpl_reply) @@ -463,7 +464,7 @@ DEFUN(cfg_linkset_no_mtp3_ssn, cfg_linkset_no_mtp3_ssn_cmd, "no mtp3 ssn <0-255>", - "MTP Level3\n" "SSN supported\n" "SSN\n") + NO_STR "MTP Level3\n" "SSN supported\n" "SSN\n") { struct mtp_link_set *set = vty->index; set->supported_ssn[atoi(argv[0])] = 0; @@ -604,7 +605,7 @@ DEFUN(cfg_link_ss7_transport, cfg_link_ss7_transport_cmd, "ss7-transport (none|udp|m2ua|m3ua-client)", "SS7 transport for the link\n" - "No transport\n" "MTP over UDP\n" "SCTP M2UA\n") + "No transport\n" "MTP over UDP\n" "SCTP M2UA server\n" "SCTP M3UA client\n") { int wanted = SS7_LTYPE_NONE; struct mtp_link *link; @@ -648,7 +649,7 @@ DEFUN(cfg_link_udp_dest_ip, cfg_link_udp_dest_ip_cmd, "udp dest ip HOST_NAME", - "UDP Transport\n" "IP\n" "Hostname\n") + "UDP Transport\n" "Destination\n" "IP\n" "Hostname\n") { struct hostent *hosts; @@ -684,7 +685,7 @@ DEFUN(cfg_link_udp_dest_port, cfg_link_udp_dest_port_cmd, "udp dest port <1-65535>", - "UDP Transport\n" "Set the port number\n" "Port\n") + "UDP Transport\n" "Destination\n" "Set the port number\n" "Port\n") { struct mtp_link *link = vty->index; struct mtp_udp_link *ulnk; @@ -896,7 +897,7 @@ DEFUN(cfg_link_m3ua_client_traffic_mode, cfg_link_m3ua_client_traffic_mode_cmd, "m3ua-client traffic-mode (override|loadshare|broadcast)", - "M3UA Client\n" "Traffic Mode\n" "Override" "Loadshare\n" "Broadcast\n") + "M3UA Client\n" "Traffic Mode\n" "Override\n" "Loadshare\n" "Broadcast\n") { struct mtp_link *link = vty->index; struct mtp_m3ua_client_link *m3ua_link; @@ -1047,7 +1048,7 @@ } DEFUN(cfg_msc_timeout_restart, cfg_msc_timeout_restart_cmd, - "timeout restart <1-65535>", + "timeout restart <0-65535>", "Timeout commands\n" "Time between restarts\n" "Seconds\n") { struct msc_connection *msc = vty->index; @@ -1306,7 +1307,7 @@ DEFUN(cfg_app_no_hardcode_ass, cfg_app_no_hardcode_ass_cmd, "no hardcode-assignment-complete", - "Hardcode the assignment complete message to HR3\n") + NO_STR "Hardcode the assignment complete message to HR3\n") { struct ss7_application *app = vty->index; app->fixed_ass_cmpl_reply = 0; diff --git a/src/vty_interface_cmds.c b/src/vty_interface_cmds.c index 78e67c0..7c634c0 100644 --- a/src/vty_interface_cmds.c +++ b/src/vty_interface_cmds.c @@ -280,7 +280,7 @@ DEFUN(show_sctp_count, show_sctp_count_cmd, "show sctp-connections count", - SHOW_STR "Number of SCTP connections\n") + SHOW_STR "SCTP connections\n" "Number of connections\n") { int count = sctp_m2ua_conn_count(bsc->m2ua_trans); vty_out(vty, "Active SCTP connections are: %d.%s", count, VTY_NEWLINE); @@ -289,7 +289,7 @@ DEFUN(show_sctp_details, show_sctp_details_cmd, "show sctp-connections details", - SHOW_STR "Details of SCTP connections\n") + SHOW_STR "SCTP connections\n" "Details\n") { struct sctp_m2ua_conn *conn; diff --git a/tests/Makefile.am b/tests/Makefile.am index 5c9cdd5..6276980 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -20,9 +20,19 @@ EXTRA_DIST = testsuite.at $(srcdir)/package.m4 $(TESTSUITE) TESTSUITE = $(srcdir)/testsuite + +if ENABLE_EXT_TESTS +python-tests: $(BUILT_SOURCES) + osmotestvty.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v + osmotestconfig.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v +else +python-tests: $(BUILT_SOURCES) + echo "Not running python-based tests (determined at configure-time)" +endif check-local: atconfig $(TESTSUITE) $(SHELL) '$(TESTSUITE)' $(TESTSUITEFLAGS) + $(MAKE) $(AM_MAKEFLAGS) python-tests installcheck-local: atconfig $(TESTSUITE) $(SHELL) '$(TESTSUITE)' AUTOTEST_PATH='$(bindir)' \ -- To view, visit https://gerrit.osmocom.org/696 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I547fd4840d86ce16e8589fb63802dd7099781194 Gerrit-PatchSet: 3 Gerrit-Project: cellmgr-ng Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 15 11:45:24 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 15 Aug 2016 11:45:24 +0000 Subject: [MERGED] cellmgr-ng[master]: debian: Add systemd service file In-Reply-To: References: Message-ID: Holger Freyther has submitted this change and it was merged. Change subject: debian: Add systemd service file ...................................................................... debian: Add systemd service file Provide a modern systemd service file for the osmo-stp. The sysvinit file is quite basic and doesn't signal syntax errors nicely. Let us embrace the future. Change-Id: Ic0cc0f17d442aa0ad38de9f0cf8aeb14121938de --- M debian/control A debian/osmo-stp.service 2 files changed, 12 insertions(+), 1 deletion(-) Approvals: Jenkins Builder: Verified Holger Freyther: Looks good to me, approved diff --git a/debian/control b/debian/control index 6d23a4e..0f4c286 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Section: net Priority: optional Maintainer: Holger Hans Peter Freyther -Build-Depends: debhelper (>= 9), autotools-dev, pkg-config, libosmocore-dev, libosmo-sccp-dev, dh-autoreconf, libsnmp-dev, libsctp-dev +Build-Depends: debhelper (>= 9), autotools-dev, pkg-config, libosmocore-dev, libosmo-sccp-dev, dh-autoreconf, dh-systemd (>= 1.5), libsnmp-dev, libsctp-dev Standards-Version: 3.9.6 Homepage: http://openbsc.osmocom.org/ Vcs-Git: git://bs11-abis.gnumonks.org/cellmgr-ng.git diff --git a/debian/osmo-stp.service b/debian/osmo-stp.service new file mode 100644 index 0000000..cef1085 --- /dev/null +++ b/debian/osmo-stp.service @@ -0,0 +1,11 @@ +[Unit] +Description=Osmocom osmo-stp bridge + +[Service] +Type=simple +ExecStart=/usr/sbin/osmo-stp -c /etc/osmocom/osmo-stp.cfg +Restart=always +RestartSec=2 + +[Install] +WantedBy=multi-user.target -- To view, visit https://gerrit.osmocom.org/695 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ic0cc0f17d442aa0ad38de9f0cf8aeb14121938de Gerrit-PatchSet: 3 Gerrit-Project: cellmgr-ng Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 15 11:45:24 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 15 Aug 2016 11:45:24 +0000 Subject: [MERGED] cellmgr-ng[master]: misc: Attempt to fix various 64bit compiler warnings In-Reply-To: References: Message-ID: Holger Freyther has submitted this change and it was merged. Change subject: misc: Attempt to fix various 64bit compiler warnings ...................................................................... misc: Attempt to fix various 64bit compiler warnings Change-Id: I4ed058aba15d9fdc22dde99d60df0aabd6585b75 --- M src/link_udp.c M src/mgcp_ss7.c M src/msc_conn.c M src/sctp_m3ua_client.c M tests/patching/patching_test.c 5 files changed, 6 insertions(+), 6 deletions(-) Approvals: Jenkins Builder: Verified Holger Freyther: Looks good to me, approved diff --git a/src/link_udp.c b/src/link_udp.c index 85f6c09..d66c1cd 100644 --- a/src/link_udp.c +++ b/src/link_udp.c @@ -149,7 +149,7 @@ length = ntohl(hdr->data_length); if (length + sizeof(*hdr) > (unsigned int) rc) { LOGP(DINP, LOGL_ERROR, - "The MSU payload does not fit: %u + %u > %d on link %d/%s of %d/%s.\n", + "The MSU payload does not fit: %u + %zu > %d on link %d/%s of %d/%s.\n", length, sizeof(*hdr), rc, link->nr, link->name, link->set->nr, link->set->name); rc = 0; diff --git a/src/mgcp_ss7.c b/src/mgcp_ss7.c index 6604545..317832c 100644 --- a/src/mgcp_ss7.c +++ b/src/mgcp_ss7.c @@ -733,8 +733,8 @@ perror("Gateway failed to read"); return -1; } else if (slen > sizeof(addr)) { - fprintf(stderr, "Gateway received message from outerspace: %d %d\n", - slen, sizeof(addr)); + fprintf(stderr, "Gateway received message from outerspace: %u %zu\n", + (unsigned int) slen, sizeof(addr)); return -1; } diff --git a/src/msc_conn.c b/src/msc_conn.c index 82ca811..703c761 100644 --- a/src/msc_conn.c +++ b/src/msc_conn.c @@ -605,7 +605,7 @@ len = msgb_l2len(msg) - 4; if (len != strlen(msc->token)) { - LOGP(DMSC, LOGL_ERROR, "Wrong length %u vs. %u\n", + LOGP(DMSC, LOGL_ERROR, "Wrong length %u vs. %zu\n", len, strlen(msc->token)); goto clean; } diff --git a/src/sctp_m3ua_client.c b/src/sctp_m3ua_client.c index 01f2af7..3726dab 100644 --- a/src/sctp_m3ua_client.c +++ b/src/sctp_m3ua_client.c @@ -569,7 +569,7 @@ dpc = ntohl(proto->dpc); sls = proto->sls; si = proto->si; - LOGP(DINP, LOGL_DEBUG, "Got data for OPC(%d)/DPC(%d)/SLS(%d) len(%d)\n", + LOGP(DINP, LOGL_DEBUG, "Got data for OPC(%d)/DPC(%d)/SLS(%d) len(%zu)\n", opc, dpc, sls, msgb_l2len(msg) - sizeof(*proto)); diff --git a/tests/patching/patching_test.c b/tests/patching/patching_test.c index 9208788..26d4a52 100644 --- a/tests/patching/patching_test.c +++ b/tests/patching/patching_test.c @@ -368,7 +368,7 @@ } if (msgb_l2len(outp) != sizeof(dt1_ass_compl_hardcoded)) { - printf("The length's don't match on %u != %u\n", + printf("The length's don't match on %u != %zu\n", msgb_l2len(outp), sizeof(dt1_ass_compl_hardcoded)); printf("hex: %s\n", osmo_hexdump(outp->l2h, msgb_l2len(outp))); abort(); -- To view, visit https://gerrit.osmocom.org/697 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I4ed058aba15d9fdc22dde99d60df0aabd6585b75 Gerrit-PatchSet: 3 Gerrit-Project: cellmgr-ng Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 15 12:08:02 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 15 Aug 2016 12:08:02 +0000 Subject: [PATCH] cellmgr-ng[master]: misc: Ignore some of the generated files Message-ID: Review at https://gerrit.osmocom.org/698 misc: Ignore some of the generated files Change-Id: Ib50b6df0d843b730418a98907666aba42d20dd1a --- M .gitignore 1 file changed, 3 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/cellmgr-ng refs/changes/98/698/1 diff --git a/.gitignore b/.gitignore index 6435a26..8496d88 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ install-sh missing stamp-h1 +compile # compiled stuff *.o @@ -31,12 +32,13 @@ patching_test mtp_parse_test udt_relay -osmo_stp +osmo-stp .version aclocal.m4 autom4te.cache/ configure.lineno +writtenconfig tests/atconfig tests/dtmf/dtmf_test tests/isup/isup_parse_test -- To view, visit https://gerrit.osmocom.org/698 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ib50b6df0d843b730418a98907666aba42d20dd1a Gerrit-PatchSet: 1 Gerrit-Project: cellmgr-ng Gerrit-Branch: master Gerrit-Owner: Holger Freyther From gerrit-no-reply at lists.osmocom.org Mon Aug 15 12:08:02 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 15 Aug 2016 12:08:02 +0000 Subject: [PATCH] cellmgr-ng[master]: jenkins: Disable building doxygen help in libosmocore Message-ID: Review at https://gerrit.osmocom.org/699 jenkins: Disable building doxygen help in libosmocore Change-Id: Iec6ad62c01aaaa7300086d130cc5512683f6c565 --- M contrib/jenkins.sh 1 file changed, 1 insertion(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/cellmgr-ng refs/changes/99/699/1 diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index 4aa644c..679df6a 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -9,7 +9,7 @@ cd libosmocore autoreconf --install --force -./configure --prefix=$PWD/../install +./configure --prefix=$PWD/../install ac_cv_path_DOXYGEN=false $MAKE $PARALLEL_MAKE install cd ../ -- To view, visit https://gerrit.osmocom.org/699 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Iec6ad62c01aaaa7300086d130cc5512683f6c565 Gerrit-PatchSet: 1 Gerrit-Project: cellmgr-ng Gerrit-Branch: master Gerrit-Owner: Holger Freyther From gerrit-no-reply at lists.osmocom.org Mon Aug 15 12:08:02 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 15 Aug 2016 12:08:02 +0000 Subject: [PATCH] cellmgr-ng[master]: debian: Make a new release with systemd service file Message-ID: Review at https://gerrit.osmocom.org/700 debian: Make a new release with systemd service file Change-Id: I51dccafb01c47a543f3223c3502f7b02819bd33f --- M debian/changelog 1 file changed, 8 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/cellmgr-ng refs/changes/00/700/1 diff --git a/debian/changelog b/debian/changelog index 2d21305..b956406 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +cellmgr-ng (1.4.7) unstable; urgency=medium + + * misc: Fix compiler warnings for amd64 + * debian: Provide systemd.service file + * vty: Fix writing configuration and enable config tests + + -- Holger Hans Peter Freyther Mon, 15 Aug 2016 13:55:26 +0200 + cellmgr-ng (1.4.6) unstable; urgency=medium * m3ua: Start timer to wait for ASPAC_ACK -- To view, visit https://gerrit.osmocom.org/700 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I51dccafb01c47a543f3223c3502f7b02819bd33f Gerrit-PatchSet: 1 Gerrit-Project: cellmgr-ng Gerrit-Branch: master Gerrit-Owner: Holger Freyther From gerrit-no-reply at lists.osmocom.org Mon Aug 15 12:10:31 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 15 Aug 2016 12:10:31 +0000 Subject: cellmgr-ng[master]: jenkins: Disable building doxygen help in libosmocore In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/699 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Iec6ad62c01aaaa7300086d130cc5512683f6c565 Gerrit-PatchSet: 1 Gerrit-Project: cellmgr-ng Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 15 12:10:34 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 15 Aug 2016 12:10:34 +0000 Subject: cellmgr-ng[master]: debian: Make a new release with systemd service file In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/700 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I51dccafb01c47a543f3223c3502f7b02819bd33f Gerrit-PatchSet: 1 Gerrit-Project: cellmgr-ng Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 15 12:10:43 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 15 Aug 2016 12:10:43 +0000 Subject: cellmgr-ng[master]: misc: Ignore some of the generated files In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/698 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ib50b6df0d843b730418a98907666aba42d20dd1a Gerrit-PatchSet: 1 Gerrit-Project: cellmgr-ng Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 15 12:10:51 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 15 Aug 2016 12:10:51 +0000 Subject: [MERGED] cellmgr-ng[master]: misc: Ignore some of the generated files In-Reply-To: References: Message-ID: Holger Freyther has submitted this change and it was merged. Change subject: misc: Ignore some of the generated files ...................................................................... misc: Ignore some of the generated files Change-Id: Ib50b6df0d843b730418a98907666aba42d20dd1a --- M .gitignore 1 file changed, 3 insertions(+), 1 deletion(-) Approvals: Jenkins Builder: Verified Holger Freyther: Looks good to me, approved diff --git a/.gitignore b/.gitignore index 6435a26..8496d88 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ install-sh missing stamp-h1 +compile # compiled stuff *.o @@ -31,12 +32,13 @@ patching_test mtp_parse_test udt_relay -osmo_stp +osmo-stp .version aclocal.m4 autom4te.cache/ configure.lineno +writtenconfig tests/atconfig tests/dtmf/dtmf_test tests/isup/isup_parse_test -- To view, visit https://gerrit.osmocom.org/698 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ib50b6df0d843b730418a98907666aba42d20dd1a Gerrit-PatchSet: 1 Gerrit-Project: cellmgr-ng Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 15 12:10:51 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 15 Aug 2016 12:10:51 +0000 Subject: [MERGED] cellmgr-ng[master]: debian: Make a new release with systemd service file In-Reply-To: References: Message-ID: Holger Freyther has submitted this change and it was merged. Change subject: debian: Make a new release with systemd service file ...................................................................... debian: Make a new release with systemd service file Change-Id: I51dccafb01c47a543f3223c3502f7b02819bd33f --- M debian/changelog 1 file changed, 8 insertions(+), 0 deletions(-) Approvals: Jenkins Builder: Verified Holger Freyther: Looks good to me, approved diff --git a/debian/changelog b/debian/changelog index 2d21305..b956406 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +cellmgr-ng (1.4.7) unstable; urgency=medium + + * misc: Fix compiler warnings for amd64 + * debian: Provide systemd.service file + * vty: Fix writing configuration and enable config tests + + -- Holger Hans Peter Freyther Mon, 15 Aug 2016 13:55:26 +0200 + cellmgr-ng (1.4.6) unstable; urgency=medium * m3ua: Start timer to wait for ASPAC_ACK -- To view, visit https://gerrit.osmocom.org/700 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I51dccafb01c47a543f3223c3502f7b02819bd33f Gerrit-PatchSet: 1 Gerrit-Project: cellmgr-ng Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 15 12:10:52 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 15 Aug 2016 12:10:52 +0000 Subject: [MERGED] cellmgr-ng[master]: jenkins: Disable building doxygen help in libosmocore In-Reply-To: References: Message-ID: Holger Freyther has submitted this change and it was merged. Change subject: jenkins: Disable building doxygen help in libosmocore ...................................................................... jenkins: Disable building doxygen help in libosmocore Change-Id: Iec6ad62c01aaaa7300086d130cc5512683f6c565 --- M contrib/jenkins.sh 1 file changed, 1 insertion(+), 1 deletion(-) Approvals: Jenkins Builder: Verified Holger Freyther: Looks good to me, approved diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index 4aa644c..679df6a 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -9,7 +9,7 @@ cd libosmocore autoreconf --install --force -./configure --prefix=$PWD/../install +./configure --prefix=$PWD/../install ac_cv_path_DOXYGEN=false $MAKE $PARALLEL_MAKE install cd ../ -- To view, visit https://gerrit.osmocom.org/699 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: Iec6ad62c01aaaa7300086d130cc5512683f6c565 Gerrit-PatchSet: 1 Gerrit-Project: cellmgr-ng Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 15 12:37:56 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 15 Aug 2016 12:37:56 +0000 Subject: openbsc[master]: add DIU logging category In-Reply-To: References: Message-ID: Patch Set 1: Yes, adding DIU was a shortcut decision. In fact there's 5 debug logs and only one notice log. The rest of the file uses DRANAP a lot, which makes marginal sense to use instead. Only RANAP will go over that SCCP... -- To view, visit https://gerrit.osmocom.org/687 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ic2f6bb1023377c24247521dde2d2bcf14f04cfe2 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 15 12:43:17 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 15 Aug 2016 12:43:17 +0000 Subject: [PATCH] openbsc[master]: add libiu In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/192 to look at the new patch set (#6). add libiu Co-Authored by dwillmann, laforge, nhofmeyr Change-Id: Iffc26f9c73cb15463948f7435b72ac1747aabdb3 --- M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/iu.h M openbsc/src/Makefile.am A openbsc/src/libiu/Makefile.am A openbsc/src/libiu/iu.c 6 files changed, 844 insertions(+), 3 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/92/192/6 diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 0980413..3d99cb8 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -203,6 +203,7 @@ src/libmgcp/Makefile src/libcommon/Makefile src/libfilter/Makefile + src/libiu/Makefile src/osmo-nitb/Makefile src/osmo-bsc/Makefile src/osmo-bsc_nat/Makefile diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index c272b14..2bca6b7 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,8 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h + gtphub.h \ + iu.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/iu.h b/openbsc/include/openbsc/iu.h new file mode 100644 index 0000000..d0ab540 --- /dev/null +++ b/openbsc/include/openbsc/iu.h @@ -0,0 +1,60 @@ +#pragma once + +#include + +struct sgsn_pdp_ctx; +struct msgb; +struct gprs_ra_id; + +struct RANAP_RAB_SetupOrModifiedItemIEs_s; +struct RANAP_GlobalRNC_ID; + +struct ue_conn_ctx { + struct llist_head list; + struct osmo_sccp_link *link; + uint32_t conn_id; + int integrity_active; + struct gprs_ra_id ra_id; +}; + +enum iu_event_type { + IU_EVENT_RAB_ASSIGN, + IU_EVENT_SECURITY_MODE_COMPLETE, + IU_EVENT_IU_RELEASE, /* An actual Iu Release message was received */ + IU_EVENT_LINK_INVALIDATED, /* A SUA link was lost or closed down */ + /* FIXME: maybe IU_EVENT_IU_RELEASE and IU_EVENT_LINK_INVALIDATED + * should be combined to one generic event that simply means the + * ue_conn_ctx should no longer be used, for whatever reason. */ +}; + +extern const struct value_string iu_event_type_names[]; +static inline const char *iu_event_type_str(enum iu_event_type e) +{ + return get_value_string(iu_event_type_names, e); +} + +/* Implementations of iu_recv_cb_t shall find the ue_conn_ctx in msg->dst. */ +typedef int (* iu_recv_cb_t )(struct msgb *msg, struct gprs_ra_id *ra_id, + /* TODO "gprs_" in generic CS+PS domain ^ */ + uint16_t *sai); + +typedef int (* iu_event_cb_t )(struct ue_conn_ctx *ue_ctx, + enum iu_event_type type, void *data); + +typedef int (* iu_rab_ass_resp_cb_t )(struct ue_conn_ctx *ue_ctx, uint8_t rab_id, + struct RANAP_RAB_SetupOrModifiedItemIEs_s *setup_ies); + +int iu_init(void *ctx, const char *listen_addr, uint16_t listen_port, + iu_recv_cb_t iu_recv_cb, iu_event_cb_t iu_event_cb); + +void iu_link_del(struct osmo_sccp_link *link); + +int iu_tx(struct msgb *msg, uint8_t sapi); + +int iu_page_cs(const char *imsi, const uint32_t *tmsi, uint16_t lac); +int iu_page_ps(const char *imsi, const uint32_t *ptmsi, uint16_t lac, uint8_t rac); + +int iu_rab_act(struct ue_conn_ctx *ue_ctx, struct msgb *msg); +int iu_rab_deact(struct ue_conn_ctx *ue_ctx, uint8_t rab_id); +int iu_tx_sec_mode_cmd(struct ue_conn_ctx *uectx, struct gsm_auth_tuple *tp, + int send_ck, int new_key); diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 6f6174e..4aa880f 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -2,9 +2,18 @@ AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(COVERAGE_CFLAGS) AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(COVERAGE_LDFLAGS) -SUBDIRS = libcommon libmgcp libbsc libmsc libtrau libfilter osmo-nitb osmo-bsc_mgcp utils ipaccess gprs +# Libraries +SUBDIRS = libcommon libmgcp libbsc libmsc libtrau libfilter -# Conditional modules +# Conditional Libraries +if BUILD_IU +SUBDIRS += libiu +endif + +# Programs +SUBDIRS += osmo-nitb osmo-bsc_mgcp utils ipaccess gprs + +# Conditional Programs if BUILD_NAT SUBDIRS += osmo-bsc_nat endif diff --git a/openbsc/src/libiu/Makefile.am b/openbsc/src/libiu/Makefile.am new file mode 100644 index 0000000..7b1ba4d --- /dev/null +++ b/openbsc/src/libiu/Makefile.am @@ -0,0 +1,10 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) +AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) \ + $(LIBOSMOGSM_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) $(LIBCRYPTO_CFLAGS) \ + $(LIBASN1C_CFLAGS) \ + $(LIBOSMOSIGTRAN_CFLAGS) $(LIBOSMORANAP_CFLAGS) + +noinst_LIBRARIES = libiu.a + +libiu_a_SOURCES = iu.c + diff --git a/openbsc/src/libiu/iu.c b/openbsc/src/libiu/iu.c new file mode 100644 index 0000000..837385e --- /dev/null +++ b/openbsc/src/libiu/iu.c @@ -0,0 +1,760 @@ +/* Common parts of IuCS and IuPS interfaces implementation */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +/* Parsed global RNC id. See also struct RANAP_GlobalRNC_ID, and note that the + * PLMN identity is a BCD representation of the MCC and MNC. + * See iu_grnc_id_parse(). */ +struct iu_grnc_id { + uint16_t mcc; + uint16_t mnc; + uint16_t rnc_id; +}; + +/* A remote RNC (Radio Network Controller, like BSC but for UMTS) that has + * called us and is currently reachable at the given osmo_sccp_link. So, when we + * know a LAC for a subscriber, we can page it at the RNC matching that LAC or + * RAC. An HNB-GW typically presents itself as if it were a single RNC, even + * though it may have several RNCs in hNodeBs connected to it. Those will then + * share the same RNC id, which they actually receive and adopt from the HNB-GW + * in the HNBAP HNB REGISTER ACCEPT message. */ +struct iu_rnc { + struct llist_head entry; + + uint16_t rnc_id; + uint16_t lac; /* Location Area Code (used for CS and PS) */ + uint8_t rac; /* Routing Area Code (used for PS only) */ + struct osmo_sccp_link *link; +}; + +void *talloc_iu_ctx; + +int asn1_xer_print = 1; +void *talloc_asn1_ctx; + +iu_recv_cb_t global_iu_recv_cb = NULL; +iu_event_cb_t global_iu_event_cb = NULL; + +static LLIST_HEAD(ue_conn_ctx_list); +static LLIST_HEAD(rnc_list); + +const struct value_string iu_event_type_names[] = { +#define IU_EVT_STR(X) { X, #X } + IU_EVT_STR(IU_EVENT_RAB_ASSIGN), + IU_EVT_STR(IU_EVENT_SECURITY_MODE_COMPLETE), + IU_EVT_STR(IU_EVENT_IU_RELEASE), + IU_EVT_STR(IU_EVENT_LINK_INVALIDATED), +#undef IU_EVT_STR +}; + +struct ue_conn_ctx *ue_conn_ctx_alloc(struct osmo_sccp_link *link, uint32_t conn_id) +{ + struct ue_conn_ctx *ctx = talloc_zero(talloc_iu_ctx, struct ue_conn_ctx); + + ctx->link = link; + ctx->conn_id = conn_id; + llist_add(&ctx->list, &ue_conn_ctx_list); + + return ctx; +} + +struct ue_conn_ctx *ue_conn_ctx_find(struct osmo_sccp_link *link, + uint32_t conn_id) +{ + struct ue_conn_ctx *ctx; + + llist_for_each_entry(ctx, &ue_conn_ctx_list, list) { + if (ctx->link == link && ctx->conn_id == conn_id) + return ctx; + } + return NULL; +} + +static struct iu_rnc *iu_rnc_alloc(uint16_t rnc_id, uint16_t lac, uint8_t rac, + struct osmo_sccp_link *link) +{ + struct iu_rnc *rnc = talloc_zero(talloc_iu_ctx, struct iu_rnc); + + rnc->rnc_id = rnc_id; + rnc->lac = lac; + rnc->rac = rac; + rnc->link = link; + llist_add(&rnc->entry, &rnc_list); + + LOGP(DRANAP, LOGL_NOTICE, "New RNC %d (LAC=%d RAC=%d)\n", + rnc->rnc_id, rnc->lac, rnc->rac); + + return rnc; +} + +static struct iu_rnc *iu_rnc_register(uint16_t rnc_id, uint16_t lac, + uint8_t rac, struct osmo_sccp_link *link) +{ + struct iu_rnc *rnc; + llist_for_each_entry(rnc, &rnc_list, entry) { + if (rnc->rnc_id != rnc_id) + continue; + + /* We have this RNC Id registered already. Make sure that the + * details match. */ + + /* TODO should a mismatch be an error? */ + if (rnc->lac != lac || rnc->rac != rac) + LOGP(DRANAP, LOGL_NOTICE, "RNC %d changes its details:" + " LAC=%d RAC=%d --> LAC=%d RAC=%d\n", + rnc->rnc_id, rnc->lac, rnc->rac, + lac, rac); + rnc->lac = lac; + rnc->rac = rac; + + if (link && rnc->link != link) + LOGP(DRANAP, LOGL_NOTICE, "RNC %d on new link" + " (LAC=%d RAC=%d)\n", + rnc->rnc_id, rnc->lac, rnc->rac); + rnc->link = link; + return rnc; + } + + /* Not found, make a new one. */ + return iu_rnc_alloc(rnc_id, lac, rac, link); +} + +/* Discard/invalidate all ue_conn_ctx and iu_rnc entries that reference the + * given link, since this link is invalid and about to be deallocated. For + * each ue_conn_ctx, invoke the iu_event_cb_t with IU_EVENT_LINK_INVALIDATED. + */ +void iu_link_del(struct osmo_sccp_link *link) +{ + struct iu_rnc *rnc, *rnc_next; + llist_for_each_entry_safe(rnc, rnc_next, &rnc_list, entry) { + if (!rnc->link) + continue; + if (rnc->link != link) + continue; + rnc->link = NULL; + llist_del(&rnc->entry); + talloc_free(rnc); + } + + struct ue_conn_ctx *uec, *uec_next; + llist_for_each_entry_safe(uec, uec_next, &ue_conn_ctx_list, list) { + if (uec->link != link) + continue; + uec->link = NULL; + global_iu_event_cb(uec, IU_EVENT_LINK_INVALIDATED, NULL); + } +} + +/*********************************************************************** + * RANAP handling + ***********************************************************************/ + +int iu_rab_act(struct ue_conn_ctx *ue_ctx, struct msgb *msg) +{ + struct osmo_scu_prim *prim; + + /* wrap RANAP message in SCCP N-DATA.req */ + prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim)); + prim->u.data.conn_id = ue_ctx->conn_id; + osmo_prim_init(&prim->oph, + SCCP_SAP_USER, + OSMO_SCU_PRIM_N_DATA, + PRIM_OP_REQUEST, + msg); + return osmo_sua_user_link_down(ue_ctx->link, &prim->oph); +} + +int iu_rab_deact(struct ue_conn_ctx *ue_ctx, uint8_t rab_id) +{ + /* FIXME */ + return -1; +} + +int iu_tx_sec_mode_cmd(struct ue_conn_ctx *uectx, struct gsm_auth_tuple *tp, + int send_ck, int new_key) +{ + struct osmo_scu_prim *prim; + struct msgb *msg; + uint8_t ik[16]; + uint8_t ck[16]; + unsigned int i; + + /* C5 function to derive IK from Kc */ + for (i = 0; i < 4; i++) + ik[i] = tp->vec.kc[i] ^ tp->vec.kc[i+4]; + memcpy(ik+4, tp->vec.kc, 8); + for (i = 12; i < 16; i++) + ik[i] = ik[i-12]; + + if (send_ck) { + /* C4 function to derive CK from Kc */ + memcpy(ck, tp->vec.kc, 8); + memcpy(ck+8, tp->vec.kc, 8); + } + + /* create RANAP message */ + msg = ranap_new_msg_sec_mod_cmd(ik, send_ck? ck : NULL, new_key ? RANAP_KeyStatus_new : RANAP_KeyStatus_old); + msg->l2h = msg->data; + /* wrap RANAP message in SCCP N-DATA.req */ + prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim)); + prim->u.data.conn_id = uectx->conn_id; + osmo_prim_init(&prim->oph, SCCP_SAP_USER, + OSMO_SCU_PRIM_N_DATA, + PRIM_OP_REQUEST, msg); + osmo_sua_user_link_down(uectx->link, &prim->oph); + + return 0; +} + +static int iu_grnc_id_parse(struct iu_grnc_id *dst, + struct RANAP_GlobalRNC_ID *src) +{ + /* The size is coming from arbitrary sender, check it gracefully */ + if (src->pLMNidentity.size != 3) { + LOGP(DRANAP, LOGL_ERROR, "Invalid PLMN Identity size:" + " should be 3, is %d\n", src->pLMNidentity.size); + return -1; + } + gsm48_mcc_mnc_from_bcd(&src->pLMNidentity.buf[0], + &dst->mcc, &dst->mnc); + dst->rnc_id = (uint16_t)src->rNC_ID; + return 0; +} + +#if 0 + -- not used at present -- +static int iu_grnc_id_compose(struct iu_grnc_id *src, + struct RANAP_GlobalRNC_ID *dst) +{ + /* The caller must ensure proper size */ + OSMO_ASSERT(dst->pLMNidentity.size == 3); + gsm48_mcc_mnc_to_bcd(&dst->pLMNidentity.buf[0], + src->mcc, src->mnc); + dst->rNC_ID = src->rnc_id; + return 0; +} +#endif + +static int ranap_handle_co_initial_ue(void *ctx, RANAP_InitialUE_MessageIEs_t *ies) +{ + struct ue_conn_ctx *ue_conn = ctx; + struct gprs_ra_id ra_id; + struct iu_grnc_id grnc_id; + uint16_t sai; + struct msgb *msg = msgb_alloc(256, "RANAP->NAS"); + + if (ranap_parse_lai(&ra_id, &ies->lai) != 0) { + LOGP(DRANAP, LOGL_ERROR, "Failed to parse RANAP LAI IE\n"); + return -1; + } + + if (ies->presenceMask & INITIALUE_MESSAGEIES_RANAP_RAC_PRESENT) { + ra_id.rac = asn1str_to_u8(&ies->rac); + } + + if (iu_grnc_id_parse(&grnc_id, &ies->globalRNC_ID) != 0) { + LOGP(DRANAP, LOGL_ERROR, + "Failed to parse RANAP Global-RNC-ID IE\n"); + return -1; + } + + sai = asn1str_to_u16(&ies->sai.sAC); + msgb_gmmh(msg) = msgb_put(msg, ies->nas_pdu.size); + memcpy(msgb_gmmh(msg), ies->nas_pdu.buf, ies->nas_pdu.size); + + /* Make sure we know the RNC Id and LAC+RAC coming in on this connection. */ + iu_rnc_register(grnc_id.rnc_id, ra_id.lac, ra_id.rac, ue_conn->link); + ue_conn->ra_id = ra_id; + + /* Feed into the MM layer */ + msg->dst = ctx; + global_iu_recv_cb(msg, &ra_id, &sai); + + msgb_free(msg); + + return 0; +} + +static int ranap_handle_co_dt(void *ctx, RANAP_DirectTransferIEs_t *ies) +{ + struct gprs_ra_id _ra_id, *ra_id = NULL; + uint16_t _sai, *sai = NULL; + struct msgb *msg = msgb_alloc(256, "RANAP->NAS"); + + if (ies->presenceMask & DIRECTTRANSFERIES_RANAP_LAI_PRESENT) { + if (ranap_parse_lai(&_ra_id, &ies->lai) != 0) { + LOGP(DRANAP, LOGL_ERROR, "Failed to parse RANAP LAI IE\n"); + return -1; + } + ra_id = &_ra_id; + if (ies->presenceMask & DIRECTTRANSFERIES_RANAP_RAC_PRESENT) { + _ra_id.rac = asn1str_to_u8(&ies->rac); + } + if (ies->presenceMask & DIRECTTRANSFERIES_RANAP_SAI_PRESENT) { + _sai = asn1str_to_u16(&ies->sai.sAC); + sai = &_sai; + } + } + + msgb_gmmh(msg) = msgb_put(msg, ies->nas_pdu.size); + memcpy(msgb_gmmh(msg), ies->nas_pdu.buf, ies->nas_pdu.size); + + /* Feed into the MM/CC/SMS-CP layer */ + msg->dst = ctx; + global_iu_recv_cb(msg, ra_id, sai); + + msgb_free(msg); + + return 0; +} + +static int ranap_handle_co_err_ind(void *ctx, RANAP_ErrorIndicationIEs_t *ies) +{ + if (ies->presenceMask & ERRORINDICATIONIES_RANAP_CAUSE_PRESENT) + LOGP(DRANAP, LOGL_ERROR, "Rx Error Indication (%s)\n", + ranap_cause_str(&ies->cause)); + else + LOGP(DRANAP, LOGL_ERROR, "Rx Error Indication\n"); + + return 0; +} + +int iu_tx(struct msgb *msg_nas, uint8_t sapi) +{ + struct ue_conn_ctx *uectx = msg_nas->dst; + struct msgb *msg; + struct osmo_scu_prim *prim; + + LOGP(DRANAP, LOGL_INFO, "Transmitting L3 Message as RANAP DT (SUA link %p conn_id %u)\n", + uectx->link, uectx->conn_id); + + msg = ranap_new_msg_dt(sapi, msg_nas->data, msgb_length(msg_nas)); + msgb_free(msg_nas); + msg->l2h = msg->data; + prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim)); + prim->u.data.conn_id = uectx->conn_id; + osmo_prim_init(&prim->oph, SCCP_SAP_USER, + OSMO_SCU_PRIM_N_DATA, + PRIM_OP_REQUEST, msg); + osmo_sua_user_link_down(uectx->link, &prim->oph); + return 0; +} + +static int ranap_handle_co_iu_rel_req(struct ue_conn_ctx *ctx, RANAP_Iu_ReleaseRequestIEs_t *ies) +{ + struct msgb *msg; + struct osmo_scu_prim *prim; + + LOGP(DRANAP, LOGL_INFO, "Received Iu Release Request, Sending Release Command\n"); + msg = ranap_new_msg_iu_rel_cmd(&ies->cause); + msg->l2h = msg->data; + prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim)); + prim->u.data.conn_id = ctx->conn_id; + osmo_prim_init(&prim->oph, SCCP_SAP_USER, + OSMO_SCU_PRIM_N_DATA, + PRIM_OP_REQUEST, msg); + osmo_sua_user_link_down(ctx->link, &prim->oph); + return 0; +} + +static int ranap_handle_co_rab_ass_resp(struct ue_conn_ctx *ctx, RANAP_RAB_AssignmentResponseIEs_t *ies) +{ + int rc = -1; + + LOGP(DRANAP, LOGL_INFO, "RAB Asignment Response:"); + if (ies->presenceMask & RAB_ASSIGNMENTRESPONSEIES_RANAP_RAB_SETUPORMODIFIEDLIST_PRESENT) { + /* TODO: Iterate over list of SetupOrModifiedList IEs and handle each one */ + RANAP_IE_t *ranap_ie = ies->raB_SetupOrModifiedList.raB_SetupOrModifiedList_ies.list.array[0]; + RANAP_RAB_SetupOrModifiedItemIEs_t setup_ies; + + rc = ranap_decode_rab_setupormodifieditemies_fromlist(&setup_ies, &ranap_ie->value); + if (rc) { + LOGP(DRANAP, LOGL_ERROR, "Error in ranap_decode_rab_setupormodifieditemies()\n"); + return rc; + } + + rc = global_iu_event_cb(ctx, IU_EVENT_RAB_ASSIGN, &setup_ies); + + ranap_free_rab_setupormodifieditemies(&setup_ies); + } + + LOGPC(DRANAP, LOGL_INFO, "\n"); + + return rc; +} + +/* Entry point for connection-oriented RANAP message */ +static void cn_ranap_handle_co(void *ctx, ranap_message *message) +{ + int rc; + + LOGP(DRANAP, LOGL_NOTICE, "handle_co(dir=%u, proc=%u)\n", message->direction, message->procedureCode); + + switch (message->direction) { + case RANAP_RANAP_PDU_PR_initiatingMessage: + switch (message->procedureCode) { + case RANAP_ProcedureCode_id_InitialUE_Message: + rc = ranap_handle_co_initial_ue(ctx, &message->msg.initialUE_MessageIEs); + break; + case RANAP_ProcedureCode_id_DirectTransfer: + rc = ranap_handle_co_dt(ctx, &message->msg.directTransferIEs); + break; + case RANAP_ProcedureCode_id_ErrorIndication: + rc = ranap_handle_co_err_ind(ctx, &message->msg.errorIndicationIEs); + break; + case RANAP_ProcedureCode_id_Iu_ReleaseRequest: + /* Iu Release Request */ + rc = ranap_handle_co_iu_rel_req(ctx, &message->msg.iu_ReleaseRequestIEs); + break; + default: + LOGP(DRANAP, LOGL_ERROR, "Received Initiating Message: unknown Procedure Code %d\n", + message->procedureCode); + rc = -1; + break; + } + break; + case RANAP_RANAP_PDU_PR_successfulOutcome: + switch (message->procedureCode) { + case RANAP_ProcedureCode_id_SecurityModeControl: + /* Security Mode Complete */ + rc = global_iu_event_cb(ctx, IU_EVENT_SECURITY_MODE_COMPLETE, NULL); + break; + case RANAP_ProcedureCode_id_Iu_Release: + /* Iu Release Complete */ + rc = global_iu_event_cb(ctx, IU_EVENT_IU_RELEASE, NULL); + if (rc) { + LOGP(DRANAP, LOGL_ERROR, "Iu Release event: Iu Event callback returned %d\n", + rc); + } + break; + default: + LOGP(DRANAP, LOGL_ERROR, "Received Successful Outcome: unknown Procedure Code %d\n", + message->procedureCode); + rc = -1; + break; + } + break; + case RANAP_RANAP_PDU_PR_outcome: + switch (message->procedureCode) { + case RANAP_ProcedureCode_id_RAB_Assignment: + /* RAB Assignment Response */ + rc = ranap_handle_co_rab_ass_resp(ctx, &message->msg.raB_AssignmentResponseIEs); + break; + default: + LOGP(DRANAP, LOGL_ERROR, "Received Outcome: unknown Procedure Code %d\n", + message->procedureCode); + rc = -1; + break; + } + break; + case RANAP_RANAP_PDU_PR_unsuccessfulOutcome: + default: + LOGP(DRANAP, LOGL_ERROR, "Received Unsuccessful Outcome: Procedure Code %d\n", + message->procedureCode); + rc = -1; + break; + } + + if (rc) { + LOGP(DRANAP, LOGL_ERROR, "Error in cn_ranap_handle_co (%d)\n", + rc); + /* TODO handling of the error? */ + } +} + +static int ranap_handle_cl_reset_req(void *ctx, RANAP_ResetIEs_t *ies) +{ + /* FIXME: send reset response */ + return -1; +} + +static int ranap_handle_cl_err_ind(void *ctx, RANAP_ErrorIndicationIEs_t *ies) +{ + if (ies->presenceMask & ERRORINDICATIONIES_RANAP_CAUSE_PRESENT) + LOGP(DRANAP, LOGL_ERROR, "Rx Error Indication (%s)\n", + ranap_cause_str(&ies->cause)); + else + LOGP(DRANAP, LOGL_ERROR, "Rx Error Indication\n"); + + return 0; +} + +/* Entry point for connection-less RANAP message */ +static void cn_ranap_handle_cl(void *ctx, ranap_message *message) +{ + int rc; + + switch (message->direction) { + case RANAP_RANAP_PDU_PR_initiatingMessage: + switch (message->procedureCode) { + case RANAP_ProcedureCode_id_Reset: + /* received reset.req, send reset.resp */ + rc = ranap_handle_cl_reset_req(ctx, &message->msg.resetIEs); + break; + case RANAP_ProcedureCode_id_ErrorIndication: + rc = ranap_handle_cl_err_ind(ctx, &message->msg.errorIndicationIEs); + break; + default: + rc = -1; + break; + } + break; + case RANAP_RANAP_PDU_PR_successfulOutcome: + case RANAP_RANAP_PDU_PR_unsuccessfulOutcome: + case RANAP_RANAP_PDU_PR_outcome: + default: + rc = -1; + break; + } + + if (rc) { + LOGP(DRANAP, LOGL_ERROR, "Error in cn_ranap_handle_cl (%d)\n", + rc); + /* TODO handling of the error? */ + } +} + +/*********************************************************************** + * Paging + ***********************************************************************/ + +/* Send a paging command down a given SUA link. tmsi and paging_cause are + * optional and may be passed NULL and 0, respectively, to disable their use. + * See enum RANAP_PagingCause. + * + * If TMSI is given, the IMSI is not sent over the air interface. Nevertheless, + * the IMSI is still required for resolution in the HNB-GW and/or(?) RNC. */ +static int iu_tx_paging_cmd(struct osmo_sccp_link *link, + const char *imsi, const uint32_t *tmsi, + bool is_ps, uint32_t paging_cause) +{ + struct msgb *msg; + msg = ranap_new_msg_paging_cmd(imsi, tmsi, is_ps? 1 : 0, paging_cause); + msg->l2h = msg->data; + return osmo_sccp_tx_unitdata_ranap(link, 1, 2, msg->data, + msgb_length(msg)); +} + +static int iu_page(const char *imsi, const uint32_t *tmsi_or_ptimsi, + uint16_t lac, uint8_t rac, bool is_ps) +{ + struct iu_rnc *rnc; + int pagings_sent = 0; + + if (tmsi_or_ptimsi) { + LOGP(DRANAP, LOGL_DEBUG, "%s: Looking for RNCs to page for IMSI %s" + " (paging will use %s %x)\n", + is_ps? "IuPS" : "IuCS", + imsi, + is_ps? "PTMSI" : "TMSI", + *tmsi_or_ptimsi); + } else { + LOGP(DRANAP, LOGL_DEBUG, "%s: Looking for RNCs to page for IMSI %s" + " (paging will use IMSI)\n", + is_ps? "IuPS" : "IuCS", + imsi + ); + } + + llist_for_each_entry(rnc, &rnc_list, entry) { + if (!rnc->link) { + /* Not actually connected, don't count it. */ + continue; + } + if (rnc->lac != lac) + continue; + if (is_ps && rnc->rac != rac) + continue; + + /* Found a match! */ + if (iu_tx_paging_cmd(rnc->link, imsi, tmsi_or_ptimsi, is_ps, 0) + == 0) { + LOGP(DRANAP, LOGL_DEBUG, + "%s: Paged for IMSI %s on RNC %d, on SUA link %p\n", + is_ps? "IuPS" : "IuCS", + imsi, rnc->rnc_id, rnc->link); + pagings_sent ++; + } + } + + /* Some logging... */ + if (pagings_sent > 0) { + LOGP(DRANAP, LOGL_DEBUG, + "%s: %d RNCs were paged for IMSI %s.\n", + is_ps? "IuPS" : "IuCS", + pagings_sent, imsi); + } + else { + if (is_ps) { + LOGP(DRANAP, LOGL_ERROR, "IuPS: Found no RNC to page for" + " LAC %d RAC %d (would have paged IMSI %s)\n", + lac, rac, imsi); + } + else { + LOGP(DRANAP, LOGL_ERROR, "IuCS: Found no RNC to page for" + " LAC %d (would have paged IMSI %s)\n", + lac, imsi); + } + } + + return pagings_sent; +} + +int iu_page_cs(const char *imsi, const uint32_t *tmsi, uint16_t lac) +{ + return iu_page(imsi, tmsi, lac, 0, false); +} + +int iu_page_ps(const char *imsi, const uint32_t *ptmsi, uint16_t lac, uint8_t rac) +{ + return iu_page(imsi, ptmsi, lac, rac, true); +} + + +/*********************************************************************** + * + ***********************************************************************/ + +int tx_unitdata(struct osmo_sccp_link *link); +int tx_conn_req(struct osmo_sccp_link *link, uint32_t conn_id); + +struct osmo_prim_hdr *make_conn_req(uint32_t conn_id); +struct osmo_prim_hdr *make_dt1_req(uint32_t conn_id, const uint8_t *data, unsigned int len); + +struct osmo_prim_hdr *make_conn_resp(struct osmo_scu_connect_param *param) +{ + struct msgb *msg = msgb_alloc(1024, "conn_resp"); + struct osmo_scu_prim *prim; + + prim = (struct osmo_scu_prim *) msgb_put(msg, sizeof(*prim)); + osmo_prim_init(&prim->oph, SCCP_SAP_USER, + OSMO_SCU_PRIM_N_CONNECT, + PRIM_OP_RESPONSE, msg); + memcpy(&prim->u.connect, param, sizeof(prim->u.connect)); + return &prim->oph; +} + +static int sccp_sap_up(struct osmo_prim_hdr *oph, void *link) +{ + struct osmo_scu_prim *prim = (struct osmo_scu_prim *) oph; + struct osmo_prim_hdr *resp = NULL; + int rc; + struct ue_conn_ctx *ue; + + DEBUGP(DRANAP, "sccp_sap_up(%s)\n", osmo_scu_prim_name(oph)); + + switch (OSMO_PRIM_HDR(oph)) { + case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_CONFIRM): + /* confirmation of outbound connection */ + rc = -1; + break; + case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_INDICATION): + /* indication of new inbound connection request*/ + DEBUGP(DRANAP, "N-CONNECT.ind(X->%u)\n", prim->u.connect.conn_id); + if (/* prim->u.connect.called_addr.ssn != OSMO_SCCP_SSN_RANAP || */ + !msgb_l2(oph->msg) || msgb_l2len(oph->msg) == 0) { + LOGP(DRANAP, LOGL_NOTICE, + "Received invalid N-CONNECT.ind\n"); + return 0; + } + ue = ue_conn_ctx_alloc(link, prim->u.connect.conn_id); + /* first ensure the local SUA/SCCP socket is ACTIVE */ + resp = make_conn_resp(&prim->u.connect); + osmo_sua_user_link_down(link, resp); + /* then handle the RANAP payload */ + rc = ranap_cn_rx_co(cn_ranap_handle_co, ue, msgb_l2(oph->msg), msgb_l2len(oph->msg)); + break; + case OSMO_PRIM(OSMO_SCU_PRIM_N_DISCONNECT, PRIM_OP_INDICATION): + /* indication of disconnect */ + DEBUGP(DRANAP, "N-DISCONNECT.ind(%u)\n", + prim->u.disconnect.conn_id); + ue = ue_conn_ctx_find(link, prim->u.disconnect.conn_id); + rc = ranap_cn_rx_co(cn_ranap_handle_co, ue, msgb_l2(oph->msg), msgb_l2len(oph->msg)); + break; + case OSMO_PRIM(OSMO_SCU_PRIM_N_DATA, PRIM_OP_INDICATION): + /* connection-oriented data received */ + DEBUGP(DRANAP, "N-DATA.ind(%u, %s)\n", prim->u.data.conn_id, + osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg))); + /* resolve UE context */ + ue = ue_conn_ctx_find(link, prim->u.data.conn_id); + rc = ranap_cn_rx_co(cn_ranap_handle_co, ue, msgb_l2(oph->msg), msgb_l2len(oph->msg)); + break; + case OSMO_PRIM(OSMO_SCU_PRIM_N_UNITDATA, PRIM_OP_INDICATION): + /* connection-less data received */ + DEBUGP(DRANAP, "N-UNITDATA.ind(%s)\n", + osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg))); + rc = ranap_cn_rx_cl(cn_ranap_handle_cl, link, msgb_l2(oph->msg), msgb_l2len(oph->msg)); + break; + default: + rc = -1; + break; + } + + msgb_free(oph->msg); + return rc; +} + +int iu_init(void *ctx, const char *listen_addr, uint16_t listen_port, + iu_recv_cb_t iu_recv_cb, iu_event_cb_t iu_event_cb) +{ + struct osmo_sccp_user *user; + talloc_iu_ctx = talloc_named_const(ctx, 1, "iu"); + talloc_asn1_ctx = talloc_named_const(talloc_iu_ctx, 1, "asn1"); + + global_iu_recv_cb = iu_recv_cb; + global_iu_event_cb = iu_event_cb; + osmo_sua_set_log_area(DSUA); + user = osmo_sua_user_create(talloc_iu_ctx, sccp_sap_up, talloc_iu_ctx); + return osmo_sua_server_listen(user, listen_addr, listen_port); +} + -- To view, visit https://gerrit.osmocom.org/192 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Iffc26f9c73cb15463948f7435b72ac1747aabdb3 Gerrit-PatchSet: 6 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 15 12:43:45 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 15 Aug 2016 12:43:45 +0000 Subject: [ABANDON] openbsc[master]: add DIU logging category In-Reply-To: References: Message-ID: Neels Hofmeyr has abandoned this change. Change subject: add DIU logging category ...................................................................... Abandoned -- To view, visit https://gerrit.osmocom.org/687 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: abandon Gerrit-Change-Id: Ic2f6bb1023377c24247521dde2d2bcf14f04cfe2 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 15 12:44:53 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 15 Aug 2016 12:44:53 +0000 Subject: openbsc[master]: add libiu In-Reply-To: References: Message-ID: Patch Set 5: Instead of DIU, I'm using DRANAP logging now. Could be nicer but I don't want to spend too much time on it at this point... -- To view, visit https://gerrit.osmocom.org/192 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Iffc26f9c73cb15463948f7435b72ac1747aabdb3 Gerrit-PatchSet: 5 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 15 17:39:28 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 15 Aug 2016 17:39:28 +0000 Subject: [MERGED] openbsc[master]: ci: Attempt to disable doxygen warnings of dependencies In-Reply-To: References: Message-ID: Holger Freyther has submitted this change and it was merged. Change subject: ci: Attempt to disable doxygen warnings of dependencies ...................................................................... ci: Attempt to disable doxygen warnings of dependencies We do not want to see doxygen warnings when building the libosmocore dependency. Change-Id: I4640cb5b91d54641e8e5b2f096c3bca49bfff60e --- M contrib/jenkins.sh 1 file changed, 3 insertions(+), 2 deletions(-) Approvals: Neels Hofmeyr: Looks good to me, approved Jenkins Builder: Verified diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index 755ff1c..3c60996 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -12,6 +12,7 @@ build_dep() { project="$1" branch="$2" + cfg="$3" set +x echo echo @@ -32,11 +33,11 @@ fi git rev-parse HEAD autoreconf --install --force - ./configure --prefix="$inst" + ./configure --prefix="$inst" $cfg $MAKE $PARALLEL_MAKE install } -build_dep libosmocore +build_dep libosmocore "" ac_cv_path_DOXYGEN=false # All below builds want this PKG_CONFIG_PATH export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH" -- To view, visit https://gerrit.osmocom.org/616 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I4640cb5b91d54641e8e5b2f096c3bca49bfff60e Gerrit-PatchSet: 4 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 15 17:39:40 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 15 Aug 2016 17:39:40 +0000 Subject: [ABANDON] osmo-pcu[master]: wip.. discard pcu patch to see build log In-Reply-To: References: Message-ID: Holger Freyther has abandoned this change. Change subject: wip.. discard pcu patch to see build log ...................................................................... Abandoned -- To view, visit https://gerrit.osmocom.org/678 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: abandon Gerrit-Change-Id: I935f06ea0d428fd24b23c4581f8d42209cd5a73d Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 15 17:57:12 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 15 Aug 2016 17:57:12 +0000 Subject: [PATCH] openbsc[master]: ussd: Add band-aid for interrogationSS In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/503 to look at the new patch set (#2). ussd: Add band-aid for interrogationSS This is a speculative change for interrogateSS and by not answering the request the radio connection would remain open long. The SS/USSD code is from a time where none of knew much about GSM. We do not support SS but should reject it. We have checked for an empty string in the text field to guess if it is a result/release to not send more information. The right way forward is to decode the ASN1 into the fields REQUEST/RESULT(last). Fix an issue and make the code worse. Assume ss_code > 0 to see if this is a interrogate invoke. The issue is that code 0 is a well defined value but unlikely to be used. MAP ASN1 definition: SS-Code ::= OCTET STRING (SIZE (1)) -- This type is used to represent the code identifying a single -- supplementary service, a group of supplementary services, or -- all supplementary services. The services and abbreviations -- used are defined in TS 3GPP TS 22.004 [5]. The internal structure is -- defined as follows: -- -- bits 87654321: group (bits 8765), and specific service -- (bits 4321) allSS SS-Code ::= '00000000'B Change-Id: Ib0dc4485388f030eb172fe21f5327b7ab94751f5 --- M openbsc/include/openbsc/gsm_04_80.h M openbsc/src/libmsc/gsm_04_80.c M openbsc/src/libmsc/ussd.c 3 files changed, 15 insertions(+), 8 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/03/503/2 diff --git a/openbsc/include/openbsc/gsm_04_80.h b/openbsc/include/openbsc/gsm_04_80.h index 0a60652..13bc60e 100644 --- a/openbsc/include/openbsc/gsm_04_80.h +++ b/openbsc/include/openbsc/gsm_04_80.h @@ -12,7 +12,7 @@ const struct ussd_request *req); int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn, const struct msgb *msg, - const struct ussd_request *request); + const struct ss_request *request); int gsm0480_send_ussdNotify(struct gsm_subscriber_connection *conn, int level, const char *text); int gsm0480_send_releaseComplete(struct gsm_subscriber_connection *conn); diff --git a/openbsc/src/libmsc/gsm_04_80.c b/openbsc/src/libmsc/gsm_04_80.c index f1d75f2..a19cd9d 100644 --- a/openbsc/src/libmsc/gsm_04_80.c +++ b/openbsc/src/libmsc/gsm_04_80.c @@ -111,7 +111,7 @@ int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn, const struct msgb *in_msg, - const struct ussd_request *req) + const struct ss_request *req) { struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 USSD REJ"); struct gsm48_hdr *gh; diff --git a/openbsc/src/libmsc/ussd.c b/openbsc/src/libmsc/ussd.c index 7f01eae..784e001 100644 --- a/openbsc/src/libmsc/ussd.c +++ b/openbsc/src/libmsc/ussd.c @@ -45,12 +45,12 @@ int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg) { int rc; - struct ussd_request req; + struct ss_request req; struct gsm48_hdr *gh; memset(&req, 0, sizeof(req)); gh = msgb_l3(msg); - rc = gsm0480_decode_ussd_request(gh, msgb_l3len(msg), &req); + rc = gsm0480_decode_ss_request(gh, msgb_l3len(msg), &req); if (!rc) { DEBUGP(DMM, "Unhandled SS\n"); rc = gsm0480_send_ussd_reject(conn, msg, &req); @@ -58,15 +58,22 @@ return rc; } - /* Release-Complete */ - if (req.text[0] == '\0') + if (req.ussd_text[0] == '\0') { + if (req.ss_code > 0) { + /* Assume interrogateSS or modification of it and reject */ + rc = gsm0480_send_ussd_reject(conn, msg, &req); + msc_release_connection(conn); + return rc; + } + /* Still assuming a Release-Complete and returning */ return 0; + } - if (!strcmp(USSD_TEXT_OWN_NUMBER, (const char *)req.text)) { + if (!strcmp(USSD_TEXT_OWN_NUMBER, (const char *)req.ussd_text)) { DEBUGP(DMM, "USSD: Own number requested\n"); rc = send_own_number(conn, msg, &req); } else { - DEBUGP(DMM, "Unhandled USSD %s\n", req.text); + DEBUGP(DMM, "Unhandled USSD %s\n", req.ussd_text); rc = gsm0480_send_ussd_reject(conn, msg, &req); } -- To view, visit https://gerrit.osmocom.org/503 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ib0dc4485388f030eb172fe21f5327b7ab94751f5 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 15 18:44:18 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 15 Aug 2016 18:44:18 +0000 Subject: [PATCH] openbsc[master]: ussd: Add band-aid for interrogationSS In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/503 to look at the new patch set (#3). ussd: Add band-aid for interrogationSS This is a speculative change for interrogateSS and by not answering the request the radio connection would remain open long. The SS/USSD code is from a time where none of knew much about GSM. We do not support SS but should reject it. We have checked for an empty string in the text field to guess if it is a result/release to not send more information. The right way forward is to decode the ASN1 into the fields REQUEST/RESULT(last). Fix an issue and make the code worse. Assume ss_code > 0 to see if this is a interrogate invoke. The issue is that code 0 is a well defined value but unlikely to be used. MAP ASN1 definition: SS-Code ::= OCTET STRING (SIZE (1)) -- This type is used to represent the code identifying a single -- supplementary service, a group of supplementary services, or -- all supplementary services. The services and abbreviations -- used are defined in TS 3GPP TS 22.004 [5]. The internal structure is -- defined as follows: -- -- bits 87654321: group (bits 8765), and specific service -- (bits 4321) allSS SS-Code ::= '00000000'B Change-Id: Ib0dc4485388f030eb172fe21f5327b7ab94751f5 --- M openbsc/include/openbsc/gsm_04_80.h M openbsc/src/libmsc/gsm_04_80.c M openbsc/src/libmsc/ussd.c 3 files changed, 19 insertions(+), 12 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/03/503/3 diff --git a/openbsc/include/openbsc/gsm_04_80.h b/openbsc/include/openbsc/gsm_04_80.h index 0a60652..74701ac 100644 --- a/openbsc/include/openbsc/gsm_04_80.h +++ b/openbsc/include/openbsc/gsm_04_80.h @@ -9,10 +9,10 @@ int gsm0480_send_ussd_response(struct gsm_subscriber_connection *conn, const struct msgb *in_msg, const char* response_text, - const struct ussd_request *req); + const struct ss_request *req); int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn, const struct msgb *msg, - const struct ussd_request *request); + const struct ss_request *request); int gsm0480_send_ussdNotify(struct gsm_subscriber_connection *conn, int level, const char *text); int gsm0480_send_releaseComplete(struct gsm_subscriber_connection *conn); diff --git a/openbsc/src/libmsc/gsm_04_80.c b/openbsc/src/libmsc/gsm_04_80.c index f1d75f2..1744455 100644 --- a/openbsc/src/libmsc/gsm_04_80.c +++ b/openbsc/src/libmsc/gsm_04_80.c @@ -63,7 +63,7 @@ /* Send response to a mobile-originated ProcessUnstructuredSS-Request */ int gsm0480_send_ussd_response(struct gsm_subscriber_connection *conn, const struct msgb *in_msg, const char *response_text, - const struct ussd_request *req) + const struct ss_request *req) { struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 USSD RSP"); struct gsm48_hdr *gh; @@ -111,7 +111,7 @@ int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn, const struct msgb *in_msg, - const struct ussd_request *req) + const struct ss_request *req) { struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 USSD REJ"); struct gsm48_hdr *gh; diff --git a/openbsc/src/libmsc/ussd.c b/openbsc/src/libmsc/ussd.c index 7f01eae..6b86dcf 100644 --- a/openbsc/src/libmsc/ussd.c +++ b/openbsc/src/libmsc/ussd.c @@ -38,19 +38,19 @@ const char USSD_TEXT_OWN_NUMBER[] = "*#100#"; /* Forward declarations of network-specific handler functions */ -static int send_own_number(struct gsm_subscriber_connection *conn, const struct msgb *msg, const struct ussd_request *req); +static int send_own_number(struct gsm_subscriber_connection *conn, const struct msgb *msg, const struct ss_request *req); /* Entrypoint - handler function common to all mobile-originated USSDs */ int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg) { int rc; - struct ussd_request req; + struct ss_request req; struct gsm48_hdr *gh; memset(&req, 0, sizeof(req)); gh = msgb_l3(msg); - rc = gsm0480_decode_ussd_request(gh, msgb_l3len(msg), &req); + rc = gsm0480_decode_ss_request(gh, msgb_l3len(msg), &req); if (!rc) { DEBUGP(DMM, "Unhandled SS\n"); rc = gsm0480_send_ussd_reject(conn, msg, &req); @@ -58,15 +58,22 @@ return rc; } - /* Release-Complete */ - if (req.text[0] == '\0') + if (req.ussd_text[0] == '\0') { + if (req.ss_code > 0) { + /* Assume interrogateSS or modification of it and reject */ + rc = gsm0480_send_ussd_reject(conn, msg, &req); + msc_release_connection(conn); + return rc; + } + /* Still assuming a Release-Complete and returning */ return 0; + } - if (!strcmp(USSD_TEXT_OWN_NUMBER, (const char *)req.text)) { + if (!strcmp(USSD_TEXT_OWN_NUMBER, (const char *)req.ussd_text)) { DEBUGP(DMM, "USSD: Own number requested\n"); rc = send_own_number(conn, msg, &req); } else { - DEBUGP(DMM, "Unhandled USSD %s\n", req.text); + DEBUGP(DMM, "Unhandled USSD %s\n", req.ussd_text); rc = gsm0480_send_ussd_reject(conn, msg, &req); } @@ -76,7 +83,7 @@ } /* A network-specific handler function */ -static int send_own_number(struct gsm_subscriber_connection *conn, const struct msgb *msg, const struct ussd_request *req) +static int send_own_number(struct gsm_subscriber_connection *conn, const struct msgb *msg, const struct ss_request *req) { char *own_number = conn->subscr->extension; char response_string[GSM_EXTENSION_LENGTH + 20]; -- To view, visit https://gerrit.osmocom.org/503 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ib0dc4485388f030eb172fe21f5327b7ab94751f5 Gerrit-PatchSet: 3 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Tue Aug 16 06:08:46 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 16 Aug 2016 06:08:46 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 13: Hi Harald, I hope I have addressed all the review comments raised. Let me know if any other comments. If everything is fine please merge the changes to master. Thanks, Aravind Sirsikar -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 13 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 16 08:24:40 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 16 Aug 2016 08:24:40 +0000 Subject: osmo-pcu[master]: Add data structure to handle SPB for EGPRS DL In-Reply-To: References: Message-ID: Patch Set 3: (1 comment) https://gerrit.osmocom.org/#/c/654/3/src/rlc.h File src/rlc.h: Line 202: * The MCS of initial transmission of a BSN (whitespace ... the '*' should line up, sort of like a paper scroll. Add a single space before each '*') -- To view, visit https://gerrit.osmocom.org/654 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I57673e53a9da2affa7e8aaa6551ac4b271c3d525 Gerrit-PatchSet: 3 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 16 08:59:29 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 16 Aug 2016 08:59:29 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 13: (9 comments) I have only cosmetic comments, but their number has some weight. I wouldn't block the commit on these, but would be nice-to-have. Some are definitely "wrong" while others are just my opinion. https://gerrit.osmocom.org/#/c/655/13/src/pcu_vty.c File src/pcu_vty.c: Line 488: cfg_pcu_dl_arq_cmd, the other DEFUN() in this file indent the arguments to line up with the first argument, i.e. 6 spaces instead of a tab. https://gerrit.osmocom.org/#/c/655/13/src/rlc.h File src/rlc.h: Line 113: enum egprs_rlcmac_dl_spb_values { an enum always contains "values", so this name could be shortened by dropping the "_values" part. https://gerrit.osmocom.org/#/c/655/13/src/tbf.h File src/tbf.h: Line 424: enum egprs_rlc_dl_reseg_bsn_state egprs_dl_get_data_buffer data is always in a buffer, maybe drop the "_buffer" https://gerrit.osmocom.org/#/c/655/13/src/tbf_dl.cpp File src/tbf_dl.cpp: Line 383: bts->bts_data()->dl_arq_type); I would add another tab indent for the arguments of get_retx_mcs() Line 392: bts->bts_data()->dl_arq_type, bsn); I would add another 5-spaces indent for the arguments of LOGP(). If the 80 characters width is too tight in this nested if(), it would be good to move this code block to a new function. Line 660: EGPRS_RESEG_SECOND_SEG_SENT)) I find the indenting of the if condition confusing. IMHO this would improve readability: if (get_egprs_dl_spb_status(index) == EGPRS_RESEG_DL_DEFAULT || get_egprs_dl_spb_status(index) == EGPRS_RESEG_SECOND_SEG_SENT) The rest of this file does not use braces around '==' conditionals. Line 1292: (const int bsn) if you also drop the "_value" from "get_egprs_dl_spb_value", this will fit on one line. https://gerrit.osmocom.org/#/c/655/13/tests/tbf/TbfTest.cpp File tests/tbf/TbfTest.cpp: Line 1839: if ((mcs == 6) && (demanded_mcs == 3)) { basically the entire function is in an if {} block. Remove the indent by doing if (!(mcs == 6 && demanded_mcs == 3)) return; here ... unless you expect more else if() branches to be added later? Line 1937: ((mcs == 4) && (demanded_mcs == 1))) { again, remove indent by if (![...]) return; -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 13 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 16 09:00:56 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 16 Aug 2016 09:00:56 +0000 Subject: openbsc[master]: move ts_sublots() to gsm_data_shared.c, it will be used by o... In-Reply-To: References: Message-ID: Patch Set 1: bump ... would be nice to get the dyn TS stuff out of the way -- To view, visit https://gerrit.osmocom.org/669 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I8ba06d7dd6e0ceab3d8d18bb565354d6ed461f7e Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 16 09:05:36 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 16 Aug 2016 09:05:36 +0000 Subject: [PATCH] osmo-pcu[master]: Add data structure to handle SPB for EGPRS DL In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/654 to look at the new patch set (#4). Add data structure to handle SPB for EGPRS DL Modify the header files with necessary data structure to handle Split block for EGPRS DL TBF. The EGPRS resegmentation feature allows PCU to retransmit RLC blocks of HeaderType1, HeaderType2 by segmenting them to 2 HeaderType3 blocks(Example MCS5 will be retransmitted as 2 MCS2 blocks). Table 10.4.8b.2 of 44.060 explains the possible values of SPB in HeadrType3 for DL direction. The PCU decides to retransmit the blocks by resegmenting it based on Table 8.1.1.1 of 44.060. The retransmission MCS is calculated based on current MCS of the Block and demanded MCS by PCU. Section 10.3a.3.3 of 44.060 shows the HeadrType3 with SPB field present in it Change-Id: I57673e53a9da2affa7e8aaa6551ac4b271c3d525 --- M src/bts.h M src/rlc.h 2 files changed, 45 insertions(+), 4 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/54/654/4 diff --git a/src/bts.h b/src/bts.h index 807ce08..38896c8 100644 --- a/src/bts.h +++ b/src/bts.h @@ -186,6 +186,10 @@ uint8_t alpha, gamma; uint8_t egprs_enabled; uint32_t dl_tbf_idle_msec; /* hold time for idle DL TBFs */ + + /* 0 to support resegmentation in DL, 1 for no reseg */ + uint8_t dl_arq_type; + uint32_t ms_idle_sec; uint8_t cs_adj_enabled; uint8_t cs_adj_upper_limit; diff --git a/src/rlc.h b/src/rlc.h index bf2d70a..9efd418 100644 --- a/src/rlc.h +++ b/src/rlc.h @@ -84,6 +84,39 @@ }; /* + * EGPRS resegment status information for DL + * When only first segment is sent, bsn state + * will be set to EGPRS_RESEG_FIRST_SEG_SENT and when + * second segment is sent the state will be + * set to EGPRS_RESEG_SECOND_SEG_SENT. + * EGPRS_RESEG_DL_INVALID is set to 8 considering there is a scope for + * 3rd segment according to Table 10.4.8b.2 of 44.060 + * The EGPRS resegmentation feature allows PCU to retransmit + * RLC blocks of HeaderType1, HeaderType2 by segmenting + * them to 2 HeaderType3 blocks(Example MCS5 will be + * retransmitted as 2 MCS2 blocks). Table 10.4.8b.2 of 44.060 + * explains the possible values of SPB in HeadrType3 for DL + * direction.The PCU decides to retransmit the + * blocks by resegmenting it based on Table 8.1.1.1 of 44.060. + * The retransmission MCS is calculated based on current MCS of + * the Block and demanded MCS by PCU. Section 10.3a.3.3 of 44.060 + * shows the HeadrType3 with SPB field present in it +*/ +enum egprs_rlc_dl_reseg_bsn_state { + EGPRS_RESEG_DL_DEFAULT = 0, + EGPRS_RESEG_FIRST_SEG_SENT = 0x01, + EGPRS_RESEG_SECOND_SEG_SENT = 0x02, + EGPRS_RESEG_DL_INVALID = 0x08 +}; + +/* Table 10.4.8b.2 of 44.060 */ +enum egprs_rlcmac_dl_spb_values { + EGPRS_RLCMAC_DL_NO_RETX = 0, + EGPRS_RLCMAC_DL_FIRST_SEG = 2, + EGPRS_RLCMAC_DL_SEC_SEG = 3, +}; + +/* * Valid puncturing scheme values * TS 44.060 10.4.8a.3.1, 10.4.8a.2.1, 10.4.8a.1.1 */ @@ -140,10 +173,7 @@ /* holds the current status of the block w.r.t UL/DL split blocks */ union split_block_status { egprs_rlc_ul_reseg_bsn_state block_status_ul; - /* - * TODO: DL split block status need to be supported - * for EGPRS DL - */ + egprs_rlc_dl_reseg_bsn_state block_status_dl; }; struct gprs_rlc_data { @@ -168,6 +198,13 @@ GprsCodingScheme cs_current_trans; GprsCodingScheme cs_last; + /* + * The MCS of initial transmission of a BSN + * This variable is used for split block + * processing in DL + */ + GprsCodingScheme cs_init; + /* puncturing scheme value to be used for next transmission*/ enum egprs_puncturing_values next_ps; -- To view, visit https://gerrit.osmocom.org/654 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I57673e53a9da2affa7e8aaa6551ac4b271c3d525 Gerrit-PatchSet: 4 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Tue Aug 16 09:07:05 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 16 Aug 2016 09:07:05 +0000 Subject: osmo-pcu[master]: Add data structure to handle SPB for EGPRS DL In-Reply-To: References: Message-ID: Patch Set 4: (1 comment) https://gerrit.osmocom.org/#/c/654/3/src/rlc.h File src/rlc.h: Line 202: * The MCS of initial transmission of a BSN > (whitespace ... the '*' should line up, sort of like a paper scroll. Add a Done -- To view, visit https://gerrit.osmocom.org/654 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I57673e53a9da2affa7e8aaa6551ac4b271c3d525 Gerrit-PatchSet: 4 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 16 09:08:04 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 16 Aug 2016 09:08:04 +0000 Subject: [PATCH] osmo-pcu[master]: Add data structure to handle SPB for EGPRS DL In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/654 to look at the new patch set (#5). Add data structure to handle SPB for EGPRS DL Modify the header files with necessary data structure to handle Split block for EGPRS DL TBF. The EGPRS resegmentation feature allows PCU to retransmit RLC blocks of HeaderType1, HeaderType2 by segmenting them to 2 HeaderType3 blocks(Example MCS5 will be retransmitted as 2 MCS2 blocks). Table 10.4.8b.2 of 44.060 explains the possible values of SPB in HeadrType3 for DL direction. The PCU decides to retransmit the blocks by resegmenting it based on Table 8.1.1.1 of 44.060. The retransmission MCS is calculated based on current MCS of the Block and demanded MCS by PCU. Section 10.3a.3.3 of 44.060 shows the HeadrType3 with SPB field present in it Change-Id: I57673e53a9da2affa7e8aaa6551ac4b271c3d525 --- M src/bts.h M src/rlc.h 2 files changed, 45 insertions(+), 4 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/54/654/5 diff --git a/src/bts.h b/src/bts.h index 807ce08..38896c8 100644 --- a/src/bts.h +++ b/src/bts.h @@ -186,6 +186,10 @@ uint8_t alpha, gamma; uint8_t egprs_enabled; uint32_t dl_tbf_idle_msec; /* hold time for idle DL TBFs */ + + /* 0 to support resegmentation in DL, 1 for no reseg */ + uint8_t dl_arq_type; + uint32_t ms_idle_sec; uint8_t cs_adj_enabled; uint8_t cs_adj_upper_limit; diff --git a/src/rlc.h b/src/rlc.h index bf2d70a..c4acb98 100644 --- a/src/rlc.h +++ b/src/rlc.h @@ -84,6 +84,39 @@ }; /* + * EGPRS resegment status information for DL + * When only first segment is sent, bsn state + * will be set to EGPRS_RESEG_FIRST_SEG_SENT and when + * second segment is sent the state will be + * set to EGPRS_RESEG_SECOND_SEG_SENT. + * EGPRS_RESEG_DL_INVALID is set to 8 considering there is a scope for + * 3rd segment according to Table 10.4.8b.2 of 44.060 + * The EGPRS resegmentation feature allows PCU to retransmit + * RLC blocks of HeaderType1, HeaderType2 by segmenting + * them to 2 HeaderType3 blocks(Example MCS5 will be + * retransmitted as 2 MCS2 blocks). Table 10.4.8b.2 of 44.060 + * explains the possible values of SPB in HeadrType3 for DL + * direction.The PCU decides to retransmit the + * blocks by resegmenting it based on Table 8.1.1.1 of 44.060. + * The retransmission MCS is calculated based on current MCS of + * the Block and demanded MCS by PCU. Section 10.3a.3.3 of 44.060 + * shows the HeadrType3 with SPB field present in it + */ +enum egprs_rlc_dl_reseg_bsn_state { + EGPRS_RESEG_DL_DEFAULT = 0, + EGPRS_RESEG_FIRST_SEG_SENT = 0x01, + EGPRS_RESEG_SECOND_SEG_SENT = 0x02, + EGPRS_RESEG_DL_INVALID = 0x08 +}; + +/* Table 10.4.8b.2 of 44.060 */ +enum egprs_rlcmac_dl_spb_values { + EGPRS_RLCMAC_DL_NO_RETX = 0, + EGPRS_RLCMAC_DL_FIRST_SEG = 2, + EGPRS_RLCMAC_DL_SEC_SEG = 3, +}; + +/* * Valid puncturing scheme values * TS 44.060 10.4.8a.3.1, 10.4.8a.2.1, 10.4.8a.1.1 */ @@ -140,10 +173,7 @@ /* holds the current status of the block w.r.t UL/DL split blocks */ union split_block_status { egprs_rlc_ul_reseg_bsn_state block_status_ul; - /* - * TODO: DL split block status need to be supported - * for EGPRS DL - */ + egprs_rlc_dl_reseg_bsn_state block_status_dl; }; struct gprs_rlc_data { @@ -168,6 +198,13 @@ GprsCodingScheme cs_current_trans; GprsCodingScheme cs_last; + /* + * The MCS of initial transmission of a BSN + * This variable is used for split block + * processing in DL + */ + GprsCodingScheme cs_init; + /* puncturing scheme value to be used for next transmission*/ enum egprs_puncturing_values next_ps; -- To view, visit https://gerrit.osmocom.org/654 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I57673e53a9da2affa7e8aaa6551ac4b271c3d525 Gerrit-PatchSet: 5 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Tue Aug 16 09:11:23 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 16 Aug 2016 09:11:23 +0000 Subject: [PATCH] osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/655 to look at the new patch set (#14). Modify EGPRS DL TBF flow to support SPB Modify the EGPRS DL TBF flow to support Split block during Retx. This patch will also Upgrade the test suite with test cases to validate the EGPRS Downlink SPB for Retransmission Scenarios like MCS6->MCS3, MCS4->MCS1, MCS5->MCS2, MCS9->MCS3 MCS7->MCS2, MCS8->MCS3 have been simulated and Integration tested in NuRAN 1.0 hardware thoroughly. Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 --- M src/gprs_coding_scheme.h M src/pcu_main.cpp M src/pcu_vty.c M src/rlc.cpp M src/rlc.h M src/tbf.h M src/tbf_dl.cpp M tests/edge/EdgeTest.cpp M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 11 files changed, 951 insertions(+), 77 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/55/655/14 diff --git a/src/gprs_coding_scheme.h b/src/gprs_coding_scheme.h index 60a8e79..3b15372 100644 --- a/src/gprs_coding_scheme.h +++ b/src/gprs_coding_scheme.h @@ -113,7 +113,8 @@ static const char *modeName(Mode mode); static Scheme get_retx_mcs(const GprsCodingScheme mcs, - const GprsCodingScheme retx_mcs); + const GprsCodingScheme retx_mcs, + const unsigned arq_type); static enum Scheme egprs_mcs_retx_tbl[MAX_NUM_ARQ] [MAX_NUM_MCS][MAX_NUM_MCS]; @@ -232,8 +233,9 @@ } inline GprsCodingScheme::Scheme GprsCodingScheme::get_retx_mcs( const GprsCodingScheme mcs, - const GprsCodingScheme demanded_mcs) + const GprsCodingScheme demanded_mcs, + const unsigned arq_type) { - return egprs_mcs_retx_tbl[EGPRS_ARQ2][mcs.to_num() - 1] + return egprs_mcs_retx_tbl[arq_type][mcs.to_num() - 1] [demanded_mcs.to_num() - 1]; } diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2d86cda..e34d534 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -210,6 +210,12 @@ bts->dl_tbf_idle_msec = 2000; bts->llc_idle_ack_csec = 10; + /* + * By default resegmentation is supported in DL + * can also be configured through VTY + */ + bts->dl_arq_type = EGPRS_ARQ1; + msgb_set_talloc_ctx(tall_pcu_ctx); osmo_init_logging(&gprs_log_info); diff --git a/src/pcu_vty.c b/src/pcu_vty.c index 58fea99..5854b32 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -129,6 +129,10 @@ vty_out(vty, " window-size %d %d%s", bts->ws_base, bts->ws_pdch, VTY_NEWLINE); + if (bts->dl_arq_type) + vty_out(vty, " dl arq-type %d%s", bts->dl_arq_type, + VTY_NEWLINE); + if (bts->force_llc_lifetime == 0xffff) vty_out(vty, " queue lifetime infinite%s", VTY_NEWLINE); else if (bts->force_llc_lifetime) @@ -477,6 +481,20 @@ bts->max_mcs_dl = 0; bts->max_mcs_ul = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_pcu_dl_arq_type, + cfg_pcu_dl_arq_cmd, + "dl arq-type (0|1)", + EGPRS_STR "DL ARQ options\n" + "enable DL SPB support\n" + "enable DL ARQ2 support") +{ + struct gprs_rlcmac_bts *bts = bts_main_data(); + uint8_t dl_arq_type = atoi(argv[0]); + + bts->dl_arq_type = dl_arq_type; return CMD_SUCCESS; } @@ -954,6 +972,7 @@ install_element(PCU_NODE, &cfg_pcu_no_cs_downgrade_thrsh_cmd); install_element(PCU_NODE, &cfg_pcu_cs_lqual_ranges_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_cmd); + install_element(PCU_NODE, &cfg_pcu_dl_arq_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_max_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_max_cmd); diff --git a/src/rlc.cpp b/src/rlc.cpp index 6770043..60f392e 100644 --- a/src/rlc.cpp +++ b/src/rlc.cpp @@ -285,7 +285,8 @@ } static void gprs_rlc_data_header_init(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding, unsigned int header_bits) + GprsCodingScheme cs, bool with_padding, unsigned int header_bits, + const unsigned int spb) { unsigned int i; unsigned int padding_bits = with_padding ? cs.optionalPaddingBits() : 0; @@ -300,7 +301,7 @@ for (i = 0; i < rlc->num_data_blocks; i++) { gprs_rlc_data_block_info_init(&rlc->block_info[i], cs, - with_padding); + with_padding, spb); rlc->data_offs_bits[i] = header_bits + padding_bits + @@ -310,21 +311,25 @@ } void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsDL()); + cs.numDataHeaderBitsDL(), spb); } void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding) { + /* + * last parameter is sent as 0 since common function used + * for both DL and UL + */ return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsUL()); + cs.numDataHeaderBitsUL(), 0); } void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { unsigned int data_len = cs.maxDataBlockBytes(); if (with_padding) @@ -336,7 +341,7 @@ rdbi->e = 1; rdbi->cv = 15; rdbi->pi = 0; - rdbi->spb = 0; + rdbi->spb = spb; } unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, @@ -411,8 +416,18 @@ enum egprs_puncturing_values gprs_get_punct_scheme( enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current) + const GprsCodingScheme &cs_current, + const enum egprs_rlcmac_dl_spb_values spb) { + + /* + * 10.4.8b of TS 44.060 + * If it is second segment of the block + * dont change the puncturing scheme + */ + if (spb == EGPRS_RLCMAC_DL_SEC_SEG) + return punct; + /* TS 44.060 9.3.2.1.1 */ if ((GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS9) && (GprsCodingScheme::Scheme(cs_current) == GprsCodingScheme::MCS6)) { diff --git a/src/rlc.h b/src/rlc.h index 4d57c88..098c930 100644 --- a/src/rlc.h +++ b/src/rlc.h @@ -213,18 +213,19 @@ }; void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding); void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, enum egprs_puncturing_values punct, enum egprs_puncturing_values punct2, int with_padding); void gprs_rlc_mcs_cps_decode(unsigned int cps, GprsCodingScheme cs, int *punct, int *punct2, int *with_padding); enum egprs_puncturing_values gprs_get_punct_scheme(enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current_trans); + const GprsCodingScheme &cs_current_trans, + const enum egprs_rlcmac_dl_spb_values spb); void gprs_update_punct_scheme(enum egprs_puncturing_values *punct, const GprsCodingScheme &cs); /* diff --git a/src/tbf.h b/src/tbf.h index 1bd7878..cd820b9 100644 --- a/src/tbf.h +++ b/src/tbf.h @@ -421,6 +421,11 @@ int analyse_errors(char *show_rbb, uint8_t ssn, ana_result *res); void schedule_next_frame(); + enum egprs_rlc_dl_reseg_bsn_state egprs_dl_get_data_buffer + (int bsn, uint8_t **block_data); + unsigned int get_egprs_dl_spb_status(int bsn); + enum egprs_rlcmac_dl_spb_values get_egprs_dl_spb_value(int bsn); + struct osmo_timer_list m_llc_timer; }; diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp index 07a747a..f01a9ec 100644 --- a/src/tbf_dl.cpp +++ b/src/tbf_dl.cpp @@ -375,21 +375,27 @@ return -1; if (is_egprs_enabled()) { + /* Table 8.1.1.2 and Table 8.1.1.1 of 44.060 */ m_rlc.block(bsn)->cs_current_trans = - GprsCodingScheme::get_retx_mcs( - m_rlc.block(bsn)->cs_last, ms()->current_cs_dl()); + GprsCodingScheme::get_retx_mcs( + m_rlc.block(bsn)->cs_init, + ms()->current_cs_dl(), + bts->bts_data()->dl_arq_type); LOGP(DRLCMACDL, LOGL_DEBUG, - "- current_cs_dl(%d) demanded_mcs(%d) cs_trans(%d)\n", + "- initial_cs_dl(%d) last_mcs(%d) demanded_mcs(%d)" + "cs_trans(%d) arq_type(%d) bsn(%d)\n", + m_rlc.block(bsn)->cs_init.to_num(), m_rlc.block(bsn)->cs_last.to_num(), ms()->current_cs_dl().to_num(), - m_rlc.block(bsn)->cs_current_trans.to_num()); + m_rlc.block(bsn)->cs_current_trans.to_num(), + bts->bts_data()->dl_arq_type, bsn); /* TODO: Need to remove this check when MCS-8 -> MCS-6 * transistion is handled. * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 */ - if (m_rlc.block(bsn)->cs_last == GprsCodingScheme::MCS8) + if (m_rlc.block(bsn)->cs_init == GprsCodingScheme::MCS8) m_rlc.block(bsn)->cs_current_trans = GprsCodingScheme::MCS8; } else @@ -523,6 +529,11 @@ data = rlc_data->prepare(block_data_len); rlc_data->cs_last = cs; rlc_data->cs_current_trans = cs; + + /* Initialise the variable related to DL SPB */ + rlc_data->spb_status.block_status_dl = EGPRS_RESEG_DL_DEFAULT; + rlc_data->cs_init = cs; + rlc_data->len = block_data_len; rdbi = &(rlc_data->block_info); @@ -616,6 +627,7 @@ unsigned num_bsns; enum egprs_puncturing_values punct[ARRAY_SIZE(rlc.block_info)]; bool need_padding = false; + enum egprs_rlcmac_dl_spb_values spb = EGPRS_RLCMAC_DL_NO_RETX; /* * TODO: This is an experimental work-around to put 2 BSN into @@ -626,6 +638,7 @@ * the current limit. */ cs = m_rlc.block(index)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(index)->cs_init; bsns[0] = index; num_bsns = 1; @@ -634,7 +647,19 @@ num_bsns += 1; } - if (num_bsns == 1) { + /* + * if the intial mcs is 8 and retransmission mcs is either 6 or 3 + * we have to include the padding of 6 octets in first segment + */ + if ((GprsCodingScheme::Scheme(cs_init) == GprsCodingScheme::MCS8) && + (GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS6 || + GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS3)) { + if ((get_egprs_dl_spb_status(index) == + EGPRS_RESEG_DL_DEFAULT) || + (get_egprs_dl_spb_status(index) == + EGPRS_RESEG_SECOND_SEG_SENT)) + need_padding = true; + } else if (num_bsns == 1) { /* TODO: remove the conditional when MCS-6 padding isn't * failing to be decoded by MEs anymore */ /* TODO: support of MCS-8 -> MCS-6 transition should be @@ -646,7 +671,14 @@ cs.decToSingleBlock(&need_padding); } - gprs_rlc_data_info_init_dl(&rlc, cs, need_padding); + spb = get_egprs_dl_spb_value(index); + + LOGP(DRLCMACDL, LOGL_DEBUG, "- need_padding %d spb_status %d spb %d" + "(BSN1 %d BSN2 %d)\n", + need_padding, + get_egprs_dl_spb_status(index), spb, index, index2); + + gprs_rlc_data_info_init_dl(&rlc, cs, need_padding, spb); rlc.usf = 7; /* will be set at scheduler */ rlc.pr = 0; /* FIXME: power reduction */ @@ -665,10 +697,9 @@ data_block_idx++) { int bsn; - GprsCodingScheme cs_enc; uint8_t *block_data; gprs_rlc_data_block_info *rdbi, *block_info; - enum egprs_puncturing_values punct_scheme; + enum egprs_rlc_dl_reseg_bsn_state reseg_status; /* Check if there are more blocks than BSNs */ if (data_block_idx < num_bsns) @@ -676,38 +707,43 @@ else bsn = bsns[0]; - cs_enc = m_rlc.block(bsn)->cs_current_trans; - /* get data and header from current block */ - block_data = m_rlc.block(bsn)->block; - /* Get current puncturing scheme from block */ - punct_scheme = gprs_get_punct_scheme( + + m_rlc.block(bsn)->next_ps = gprs_get_punct_scheme( m_rlc.block(bsn)->next_ps, - m_rlc.block(bsn)->cs_last, cs); + m_rlc.block(bsn)->cs_last, cs, spb); if (cs.isEgprs()) { - OSMO_ASSERT(punct_scheme >= EGPRS_PS_1); - OSMO_ASSERT(punct_scheme <= EGPRS_PS_3); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps >= EGPRS_PS_1); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps <= EGPRS_PS_3); } - punct[data_block_idx] = punct_scheme; + punct[data_block_idx] = m_rlc.block(bsn)->next_ps; rdbi = &rlc.block_info[data_block_idx]; block_info = &m_rlc.block(bsn)->block_info; - if(rdbi->data_len != m_rlc.block(bsn)->len) { - LOGP(DRLCMACDL, LOGL_ERROR, - "ERROR: Expected len = %d for %s instead of " - "%d in data unit %d (BSN %d, %s)\n", - rdbi->data_len, cs.name(), m_rlc.block(bsn)->len, - data_block_idx, bsn, cs_enc.name()); - OSMO_ASSERT(rdbi->data_len == m_rlc.block(bsn)->len); - } - - /* TODO: Need to handle 2 same bsns - * in header type 1 + /* + * get data and header from current block + * function returns the reseg status */ - gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, - cs); + reseg_status = egprs_dl_get_data_buffer(bsn, &block_data); + m_rlc.block(bsn)->spb_status.block_status_dl = reseg_status; + + /* + * If it is first segment of the split block set the state of + * bsn to nacked. If it is the first segment dont update the + * next ps value of bsn. since next segment also needs same cps + */ + if (spb == EGPRS_RLCMAC_DL_FIRST_SEG) + m_window.m_v_b.mark_nacked(bsn); + else { + /* + * TODO: Need to handle 2 same bsns + * in header type 1 + */ + gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, + cs); + } m_rlc.block(bsn)->cs_last = cs; rdbi->e = block_info->e; @@ -1169,3 +1205,120 @@ keep_time_frames = msecs_to_frames(bts_data()->dl_tbf_idle_msec); return frames_since_last_drain(fn) <= keep_time_frames; } + +/* + * This function returns the pointer to data which needs + * to be copied. Also updates the status of the block related to + * Split block handling in the RLC/MAC block. + */ +enum egprs_rlc_dl_reseg_bsn_state + gprs_rlcmac_dl_tbf::egprs_dl_get_data_buffer(int bsn, + uint8_t **block_data) +{ + gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state *block_status_dl = + &rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + *block_data = &rlc_data->block[0]; + + /* + * Table 10.3a.0.1 of 44.060 + * MCS6,9: second segment starts at 74/2 = 37 + * MCS5,7: second segment starts at 56/2 = 28 + * MCS8: second segment starts at 31 + * MCS4: second segment starts at 44/2 = 22 + */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + if (*block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + switch (GprsCodingScheme::Scheme(cs_init)) { + case GprsCodingScheme::MCS6 : + case GprsCodingScheme::MCS9 : + *block_data = &rlc_data->block[37]; + break; + case GprsCodingScheme::MCS7 : + case GprsCodingScheme::MCS5 : + *block_data = &rlc_data->block[28]; + break; + case GprsCodingScheme::MCS8 : + *block_data = &rlc_data->block[31]; + break; + case GprsCodingScheme::MCS4 : + *block_data = &rlc_data->block[22]; + break; + default: + LOGP(DRLCMACDL, LOGL_ERROR, "Software error: " + "--%s hit invalid condition. headerType(%d) " + " blockstatus(%d) cs(%s) PLEASE FIX!\n", name(), + cs_current_trans.headerTypeData(), + *block_status_dl, cs_init.name()); + break; + + } + return EGPRS_RESEG_SECOND_SEG_SENT; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } + } + return EGPRS_RESEG_DL_DEFAULT; +} + +/* + * This function returns the status of split block + * for RLC/MAC block. + */ +unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_status(const int bsn) +{ + const gprs_rlc_data *rlc_data = m_rlc.block(bsn); + + return rlc_data->spb_status.block_status_dl; +} + +/* + * This function returns the spb value to be sent OTA + * for RLC/MAC block. + */ +enum egprs_rlcmac_dl_spb_values gprs_rlcmac_dl_tbf::get_egprs_dl_spb_value + (const int bsn) +{ + struct gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state block_status_dl = + rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + + /* Table 10.4.8b.1 of 44.060 */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + /* + * if we are sending the second segment the spb should be 3 + * other wise it should be 2 + */ + if (block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + return EGPRS_RLCMAC_DL_SEC_SEG; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RLCMAC_DL_FIRST_SEG; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RLCMAC_DL_FIRST_SEG; + } + } + /* Non SPB cases 0 is reurned */ + return EGPRS_RLCMAC_DL_NO_RETX; +} diff --git a/tests/edge/EdgeTest.cpp b/tests/edge/EdgeTest.cpp index 807102c..9081d4d 100644 --- a/tests/edge/EdgeTest.cpp +++ b/tests/edge/EdgeTest.cpp @@ -517,7 +517,7 @@ /* TS 44.060, B.1 */ cs = GprsCodingScheme::CS4; - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -570,7 +570,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -592,7 +592,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -630,7 +630,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -669,7 +669,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -694,7 +694,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -719,7 +719,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -740,7 +740,7 @@ OSMO_ASSERT(data[0] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -777,7 +777,7 @@ cs = GprsCodingScheme::MCS4; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -835,7 +835,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -872,7 +872,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -923,7 +923,7 @@ OSMO_ASSERT(data[3] == 0); /* Block 3 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -967,7 +967,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -993,7 +993,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1020,7 +1020,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1074,7 +1074,7 @@ block_idx++) { struct gprs_rlc_data_info rlc; - gprs_rlc_data_info_init_dl(&rlc, cs, false); + gprs_rlc_data_info_init_dl(&rlc, cs, false, 0); memset(bits, pattern, sizeof(bits)); Decoding::rlc_copy_to_aligned_buffer( @@ -1118,12 +1118,14 @@ struct gprs_rlc_data_info rlc; printf("=== start %s ===\n", __func__); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::CS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::CS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 24); OSMO_ASSERT(rlc.block_info[0].data_len == 20); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::MCS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::MCS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 33); OSMO_ASSERT(rlc.block_info[0].data_len == 22); diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..18cc5cb 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -1814,6 +1814,201 @@ } +static void egprs_spb_to_normal_validation(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + uint16_t bsn1, bsn2, bsn3; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + struct gprs_rlc_dl_header_egprs_2 *egprs2; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + if ((mcs == 6) && (demanded_mcs == 3)) { + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + bsn1 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) + || (egprs2->bsn1_lo); + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(bsn1 == 0); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + bsn2 = (egprs3->bsn1_hi << 9) || (egprs3->bsn1_mid << 1) || + (egprs3->bsn1_lo); + OSMO_ASSERT(bsn2 == bsn1); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Handle (MCS3, MCS3) -> MCS6 case */ + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + mcs)); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs2->cps == 0); + bsn3 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) || + (egprs2->bsn1_lo); + OSMO_ASSERT(bsn3 == bsn2); + + tbf_cleanup(dl_tbf); + } +} +static void establish_and_use_egprs_dl_tbf_for_spb(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + /* TODO: Need to support of MCS8 -> MCS6 ->MCS3 transistion + * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 + * dated 2016-02-07 23:45:40 (UTC) + */ + if (((mcs == 5) && (demanded_mcs == 2)) || + ((mcs == 6) && (demanded_mcs == 3)) || + ((mcs == 4) && (demanded_mcs == 1))) { + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + tbf_cleanup(dl_tbf); + } +} + static void establish_and_use_egprs_dl_tbf_for_retx(BTS *the_bts, int mcs, int demanded_mcs) { @@ -1972,6 +2167,9 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; + /* First parameter is current MCS, second one is demanded_mcs */ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 6); @@ -1981,6 +2179,38 @@ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 9); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 7, 5); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 9, 6); + + printf("=== end %s ===\n", __func__); +} + +static void test_tbf_egprs_spb_dl(void) +{ + BTS the_bts; + gprs_rlcmac_bts *bts; + uint8_t ts_no = 4; + int i, j; + + printf("=== start %s ===\n", __func__); + + bts = the_bts.bts_data(); + bts->cs_downgrade_threshold = 0; + setup_bts(&the_bts, ts_no); + bts->dl_tbf_idle_msec = 200; + bts->egprs_enabled = 1; + + /* ARQ I resegmentation support */ + bts->dl_arq_type = EGPRS_ARQ1; + + /* + * First parameter is current MCS, second one is demanded_mcs + * currently only MCS5->MCS2, MCS6->3, MCS4->MCS1 is tested in UT + * rest scenarios has been integration tested + */ + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 6, 3); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 5, 2); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 4, 1); + /* check MCS6->(MCS3+MCS3)->MCS6 case */ + egprs_spb_to_normal_validation(&the_bts, 6, 3); printf("=== end %s ===\n", __func__); } @@ -1999,6 +2229,8 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; for (i = 1; i <= 9; i++) establish_and_use_egprs_dl_tbf(&the_bts, i); @@ -2071,6 +2303,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_egprs_spb_dl(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..7b3f339 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -72,6 +72,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -81,6 +82,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -157,6 +159,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -166,6 +169,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -242,6 +246,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -251,6 +256,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -259,6 +265,7 @@ - Sending new block at BSN 2, CS=CS-1 -- Chunk with length 160 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=13 block=3 data=07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b @@ -267,6 +274,7 @@ - Sending new block at BSN 3, CS=CS-1 -- Chunk with length 140 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=17 block=4 data=07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @@ -275,6 +283,7 @@ - Sending new block at BSN 4, CS=CS-1 -- Chunk with length 120 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=21 block=5 data=07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 @@ -283,6 +292,7 @@ - Sending new block at BSN 5, CS=CS-1 -- Chunk with length 100 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=26 block=6 data=07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 @@ -291,6 +301,7 @@ - Sending new block at BSN 6, CS=CS-1 -- Chunk with length 80 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=30 block=7 data=07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b @@ -299,6 +310,7 @@ - Sending new block at BSN 7, CS=CS-1 -- Chunk with length 60 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=34 block=8 data=07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f @@ -307,6 +319,7 @@ - Sending new block at BSN 8, CS=CS-1 -- Chunk with length 40 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=39 block=9 data=07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 @@ -315,6 +328,7 @@ - Sending new block at BSN 9, CS=CS-1 -- Chunk with length 20 would exactly fit into space (20): add length header with LI=0, to make frame extend to next block, and we are done data block (BSN 9, CS-1): 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=43 block=10 data=07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 @@ -326,6 +340,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=47 block=11 data=07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 @@ -334,6 +349,7 @@ - Sending new block at BSN 11, CS=CS-1 -- Chunk with length 182 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=52 block=0 data=07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 @@ -342,6 +358,7 @@ - Sending new block at BSN 12, CS=CS-1 -- Chunk with length 162 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=56 block=1 data=07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 @@ -350,6 +367,7 @@ - Sending new block at BSN 13, CS=CS-1 -- Chunk with length 142 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 13, CS-1): 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=60 block=2 data=07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d @@ -358,6 +376,7 @@ - Sending new block at BSN 14, CS=CS-1 -- Chunk with length 122 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=65 block=3 data=07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 @@ -366,6 +385,7 @@ - Sending new block at BSN 15, CS=CS-1 -- Chunk with length 102 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=69 block=4 data=07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 @@ -374,6 +394,7 @@ - Sending new block at BSN 16, CS=CS-1 -- Chunk with length 82 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=73 block=5 data=07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 @@ -382,6 +403,7 @@ - Sending new block at BSN 17, CS=CS-1 -- Chunk with length 62 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=78 block=6 data=07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d @@ -390,6 +412,7 @@ - Sending new block at BSN 18, CS=CS-1 -- Chunk with length 42 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=82 block=7 data=07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 @@ -398,6 +421,7 @@ - Sending new block at BSN 19, CS=CS-1 -- Chunk with length 22 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=86 block=8 data=07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 @@ -411,6 +435,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=16 data block (BSN 20, CS-1): 0a 41 c6 c7 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -449,6 +474,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 data block (BSN 21, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -468,6 +494,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 22, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FINISHED) @@ -1481,6 +1508,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 0, CS-1): 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 MSG = 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 @@ -1491,6 +1519,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 1, CS-1): 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 MSG = 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 @@ -1501,6 +1530,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FINISHED data block (BSN 2, CS-1): 4d 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling cannot be scheduled in this TS 7 (first control TS 4) @@ -1784,6 +1814,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=10 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 0, CS-4): 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654292 TS 7 @@ -1797,6 +1828,7 @@ TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) downlink (V(A)==0 .. V(S)==1) - Restarting at BSN 0, because all blocks have been transmitted. - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-4): 07 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 @@ -2365,6 +2397,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654279 block=10 data=00 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 @@ -2384,6 +2417,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -2406,6 +2440,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654288 block=0 data=00 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 @@ -2425,6 +2460,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654292 block=1 data=00 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2447,6 +2483,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654296 block=2 data=00 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c @@ -2466,6 +2503,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654301 block=3 data=00 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b @@ -2488,6 +2526,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 6, CS-1): 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654305 block=4 data=00 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 @@ -2507,6 +2546,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654309 block=5 data=00 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 @@ -2526,6 +2566,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654314 block=6 data=00 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 @@ -2548,6 +2589,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654318 block=7 data=00 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 @@ -2567,6 +2609,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654322 block=8 data=00 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2589,6 +2632,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654327 block=9 data=00 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c @@ -2608,6 +2652,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654331 block=10 data=00 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b @@ -2630,6 +2675,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 13, CS-1): 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654335 block=11 data=00 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 @@ -2649,6 +2695,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654340 block=0 data=00 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 @@ -2668,6 +2715,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654344 block=1 data=00 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 @@ -2690,6 +2738,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654348 block=2 data=00 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 @@ -2709,6 +2758,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654353 block=3 data=00 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2731,6 +2781,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654357 block=4 data=00 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c @@ -2750,6 +2801,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654361 block=5 data=00 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b @@ -2772,6 +2824,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 20, CS-1): 16 35 45 54 20 32 38 4c 4c 43 20 50 41 43 4b 45 54 20 32 39 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because 20 blocks sent. TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW): Scheduling polling at FN 2654379 TS 7 @@ -2795,6 +2848,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 21, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) msg block (BSN 21, CS-1): 07 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654370 block=7 data=00 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 @@ -2814,6 +2868,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 22, CS-1): 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) msg block (BSN 22, CS-1): 07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654374 block=8 data=07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 @@ -2836,6 +2891,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 23, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) msg block (BSN 23, CS-1): 07 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654379 block=9 data=00 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 @@ -2855,6 +2911,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 24, CS-1): 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) msg block (BSN 24, CS-1): 07 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654383 block=10 data=00 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2877,6 +2934,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 25, CS-1): 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 25 BSN2 -1) - Copying data unit 0 (BSN 25) msg block (BSN 25, CS-1): 07 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654387 block=11 data=00 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c @@ -2896,6 +2954,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 26, CS-1): 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 26 BSN2 -1) - Copying data unit 0 (BSN 26) msg block (BSN 26, CS-1): 07 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654392 block=0 data=00 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b @@ -2918,6 +2977,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 27, CS-1): 16 35 45 54 20 33 38 4c 4c 43 20 50 41 43 4b 45 54 20 33 39 +- need_padding 0 spb_status 0 spb 0(BSN1 27 BSN2 -1) - Copying data unit 0 (BSN 27) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) @@ -3028,6 +3088,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654405 block=3 data=00 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 @@ -3047,6 +3108,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654409 block=4 data=00 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 @@ -3066,6 +3128,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (16) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654413 block=5 data=00 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 @@ -3085,6 +3148,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (14) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654418 block=6 data=00 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 @@ -3104,6 +3168,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654422 block=7 data=00 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -3123,6 +3188,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654426 block=8 data=00 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 @@ -3142,6 +3208,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654431 block=9 data=00 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b @@ -3161,6 +3228,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654435 block=10 data=00 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 @@ -3180,6 +3248,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654439 block=11 data=00 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 @@ -3199,6 +3268,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654444 block=0 data=00 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c @@ -3218,6 +3288,7 @@ Complete DL frame for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=21 TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 10, CS-1): 4d 43 20 50 41 43 4b 45 54 20 30 39 20 28 54 42 46 20 32 29 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654461 TS 7 @@ -3698,6 +3769,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 0, MCS-1): 14 15 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3711,6 +3783,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3721,6 +3794,7 @@ - Sending new block at BSN 2, CS=MCS-1 -- Chunk with length 490 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3731,6 +3805,7 @@ - Sending new block at BSN 3, CS=MCS-1 -- Chunk with length 468 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3741,6 +3816,7 @@ - Sending new block at BSN 4, CS=MCS-1 -- Chunk with length 446 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3751,6 +3827,7 @@ - Sending new block at BSN 5, CS=MCS-1 -- Chunk with length 424 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3761,6 +3838,7 @@ - Sending new block at BSN 6, CS=MCS-1 -- Chunk with length 402 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3771,6 +3849,7 @@ - Sending new block at BSN 7, CS=MCS-1 -- Chunk with length 380 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3781,6 +3860,7 @@ - Sending new block at BSN 8, CS=MCS-1 -- Chunk with length 358 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3791,6 +3871,7 @@ - Sending new block at BSN 9, CS=MCS-1 -- Chunk with length 336 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3801,6 +3882,7 @@ - Sending new block at BSN 10, CS=MCS-1 -- Chunk with length 314 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3811,6 +3893,7 @@ - Sending new block at BSN 11, CS=MCS-1 -- Chunk with length 292 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3821,6 +3904,7 @@ - Sending new block at BSN 12, CS=MCS-1 -- Chunk with length 270 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3831,6 +3915,7 @@ - Sending new block at BSN 13, CS=MCS-1 -- Chunk with length 248 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3841,6 +3926,7 @@ - Sending new block at BSN 14, CS=MCS-1 -- Chunk with length 226 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3851,6 +3937,7 @@ - Sending new block at BSN 15, CS=MCS-1 -- Chunk with length 204 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3861,6 +3948,7 @@ - Sending new block at BSN 16, CS=MCS-1 -- Chunk with length 182 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3871,6 +3959,7 @@ - Sending new block at BSN 17, CS=MCS-1 -- Chunk with length 160 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3881,6 +3970,7 @@ - Sending new block at BSN 18, CS=MCS-1 -- Chunk with length 138 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3891,6 +3981,7 @@ - Sending new block at BSN 19, CS=MCS-1 -- Chunk with length 116 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 19, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3901,6 +3992,7 @@ - Sending new block at BSN 20, CS=MCS-1 -- Chunk with length 94 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 20, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3911,6 +4003,7 @@ - Sending new block at BSN 21, CS=MCS-1 -- Chunk with length 72 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 21, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3921,6 +4014,7 @@ - Sending new block at BSN 22, CS=MCS-1 -- Chunk with length 50 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 22, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3931,6 +4025,7 @@ - Sending new block at BSN 23, CS=MCS-1 -- Chunk with length 28 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 23, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3946,6 +4041,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 24, MCS-1): 0c 1d 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4006,6 +4102,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=16 data block (BSN 0, MCS-2): 14 21 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4019,6 +4116,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4029,6 +4127,7 @@ - Sending new block at BSN 2, CS=MCS-2 -- Chunk with length 484 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4039,6 +4138,7 @@ - Sending new block at BSN 3, CS=MCS-2 -- Chunk with length 456 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4049,6 +4149,7 @@ - Sending new block at BSN 4, CS=MCS-2 -- Chunk with length 428 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4059,6 +4160,7 @@ - Sending new block at BSN 5, CS=MCS-2 -- Chunk with length 400 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4069,6 +4171,7 @@ - Sending new block at BSN 6, CS=MCS-2 -- Chunk with length 372 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4079,6 +4182,7 @@ - Sending new block at BSN 7, CS=MCS-2 -- Chunk with length 344 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4089,6 +4193,7 @@ - Sending new block at BSN 8, CS=MCS-2 -- Chunk with length 316 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4099,6 +4204,7 @@ - Sending new block at BSN 9, CS=MCS-2 -- Chunk with length 288 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4109,6 +4215,7 @@ - Sending new block at BSN 10, CS=MCS-2 -- Chunk with length 260 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4119,6 +4226,7 @@ - Sending new block at BSN 11, CS=MCS-2 -- Chunk with length 232 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4129,6 +4237,7 @@ - Sending new block at BSN 12, CS=MCS-2 -- Chunk with length 204 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4139,6 +4248,7 @@ - Sending new block at BSN 13, CS=MCS-2 -- Chunk with length 176 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4149,6 +4259,7 @@ - Sending new block at BSN 14, CS=MCS-2 -- Chunk with length 148 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4159,6 +4270,7 @@ - Sending new block at BSN 15, CS=MCS-2 -- Chunk with length 120 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4169,6 +4281,7 @@ - Sending new block at BSN 16, CS=MCS-2 -- Chunk with length 92 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4179,6 +4292,7 @@ - Sending new block at BSN 17, CS=MCS-2 -- Chunk with length 64 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4189,6 +4303,7 @@ - Sending new block at BSN 18, CS=MCS-2 -- Chunk with length 36 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4204,6 +4319,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=18 data block (BSN 19, MCS-2): 10 25 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4264,6 +4380,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=25 data block (BSN 0, MCS-3): 14 33 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4277,6 +4394,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4287,6 +4405,7 @@ - Sending new block at BSN 2, CS=MCS-3 -- Chunk with length 475 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4297,6 +4416,7 @@ - Sending new block at BSN 3, CS=MCS-3 -- Chunk with length 438 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4307,6 +4427,7 @@ - Sending new block at BSN 4, CS=MCS-3 -- Chunk with length 401 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4317,6 +4438,7 @@ - Sending new block at BSN 5, CS=MCS-3 -- Chunk with length 364 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4327,6 +4449,7 @@ - Sending new block at BSN 6, CS=MCS-3 -- Chunk with length 327 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4337,6 +4460,7 @@ - Sending new block at BSN 7, CS=MCS-3 -- Chunk with length 290 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4347,6 +4471,7 @@ - Sending new block at BSN 8, CS=MCS-3 -- Chunk with length 253 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4357,6 +4482,7 @@ - Sending new block at BSN 9, CS=MCS-3 -- Chunk with length 216 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4367,6 +4493,7 @@ - Sending new block at BSN 10, CS=MCS-3 -- Chunk with length 179 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4377,6 +4504,7 @@ - Sending new block at BSN 11, CS=MCS-3 -- Chunk with length 142 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4387,6 +4515,7 @@ - Sending new block at BSN 12, CS=MCS-3 -- Chunk with length 105 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4397,6 +4526,7 @@ - Sending new block at BSN 13, CS=MCS-3 -- Chunk with length 68 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4410,6 +4540,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-3): 3f 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4425,6 +4556,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=34 data block (BSN 15, MCS-3): 02 45 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4485,6 +4617,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=32 data block (BSN 0, MCS-4): 14 41 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4498,6 +4631,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4508,6 +4642,7 @@ - Sending new block at BSN 2, CS=MCS-4 -- Chunk with length 468 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4518,6 +4653,7 @@ - Sending new block at BSN 3, CS=MCS-4 -- Chunk with length 424 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4528,6 +4664,7 @@ - Sending new block at BSN 4, CS=MCS-4 -- Chunk with length 380 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4538,6 +4675,7 @@ - Sending new block at BSN 5, CS=MCS-4 -- Chunk with length 336 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4548,6 +4686,7 @@ - Sending new block at BSN 6, CS=MCS-4 -- Chunk with length 292 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4558,6 +4697,7 @@ - Sending new block at BSN 7, CS=MCS-4 -- Chunk with length 248 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4568,6 +4708,7 @@ - Sending new block at BSN 8, CS=MCS-4 -- Chunk with length 204 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4578,6 +4719,7 @@ - Sending new block at BSN 9, CS=MCS-4 -- Chunk with length 160 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4588,6 +4730,7 @@ - Sending new block at BSN 10, CS=MCS-4 -- Chunk with length 116 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4598,6 +4741,7 @@ - Sending new block at BSN 11, CS=MCS-4 -- Chunk with length 72 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4613,6 +4757,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 12, MCS-4): 38 1d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4673,6 +4818,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-5): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4686,6 +4832,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4696,6 +4843,7 @@ - Sending new block at BSN 2, CS=MCS-5 -- Chunk with length 456 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4706,6 +4854,7 @@ - Sending new block at BSN 3, CS=MCS-5 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4716,6 +4865,7 @@ - Sending new block at BSN 4, CS=MCS-5 -- Chunk with length 344 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4726,6 +4876,7 @@ - Sending new block at BSN 5, CS=MCS-5 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4736,6 +4887,7 @@ - Sending new block at BSN 6, CS=MCS-5 -- Chunk with length 232 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4746,6 +4898,7 @@ - Sending new block at BSN 7, CS=MCS-5 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4756,6 +4909,7 @@ - Sending new block at BSN 8, CS=MCS-5 -- Chunk with length 120 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4766,6 +4920,7 @@ - Sending new block at BSN 9, CS=MCS-5 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4781,6 +4936,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-5): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4841,6 +4997,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-6): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4854,6 +5011,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4864,6 +5022,7 @@ - Sending new block at BSN 2, CS=MCS-6 -- Chunk with length 438 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4874,6 +5033,7 @@ - Sending new block at BSN 3, CS=MCS-6 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4884,6 +5044,7 @@ - Sending new block at BSN 4, CS=MCS-6 -- Chunk with length 290 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4894,6 +5055,7 @@ - Sending new block at BSN 5, CS=MCS-6 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4904,6 +5066,7 @@ - Sending new block at BSN 6, CS=MCS-6 -- Chunk with length 142 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4917,6 +5080,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-6): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4932,6 +5096,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-6): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4993,6 +5158,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-7): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5002,12 +5168,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(7) last_mcs(5) demanded_mcs(7)cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-7 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5022,6 +5189,7 @@ - Sending new block at BSN 3, CS=MCS-7 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5036,6 +5204,7 @@ - Sending new block at BSN 5, CS=MCS-7 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5050,6 +5219,7 @@ - Sending new block at BSN 7, CS=MCS-7 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5064,6 +5234,7 @@ - Sending new block at BSN 9, CS=MCS-7 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 9) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5081,6 +5252,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-7): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5142,6 +5314,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=56 data block (BSN 0, MCS-8): 14 71 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5152,12 +5325,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(8) demanded_mcs(8) cs_trans(8) +- initial_cs_dl(8) last_mcs(8) demanded_mcs(8)cs_trans(8) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-8 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5172,6 +5346,7 @@ - Sending new block at BSN 3, CS=MCS-8 -- Chunk with length 376 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5186,6 +5361,7 @@ - Sending new block at BSN 5, CS=MCS-8 -- Chunk with length 240 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5200,6 +5376,7 @@ - Sending new block at BSN 7, CS=MCS-8 -- Chunk with length 104 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5217,6 +5394,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=30 data block (BSN 8, MCS-8): 48 3d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5279,6 +5457,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-9): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5288,12 +5467,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(9) last_mcs(6) demanded_mcs(9)cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-9 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5308,6 +5488,7 @@ - Sending new block at BSN 3, CS=MCS-9 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5322,6 +5503,7 @@ - Sending new block at BSN 5, CS=MCS-9 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5339,6 +5521,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-9): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5356,6 +5539,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-9): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5402,11 +5586,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(6)cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5450,11 +5636,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 96 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(1) demanded_mcs(1) cs_trans(1) +- initial_cs_dl(1) last_mcs(1) demanded_mcs(1)cs_trans(1) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 98 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5498,11 +5686,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-2): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 92 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(2) demanded_mcs(2) cs_trans(2) +- initial_cs_dl(2) last_mcs(2) demanded_mcs(2)cs_trans(2) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 94 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5546,6 +5736,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5557,6 +5748,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-5): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5564,10 +5756,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-5): 0f 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7)cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7)cs_trans(7) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-7): 07 00 00 02 c0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 @@ -5612,6 +5805,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5623,6 +5817,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-6): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5630,10 +5825,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-6): 0f 40 00 00 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9)cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9)cs_trans(9) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-9): 07 00 00 02 28 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 @@ -5686,6 +5882,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-7): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5694,13 +5891,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-7): 0f 00 00 02 a0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5)cs_trans(5) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5)cs_trans(5) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-5): 07 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5752,6 +5951,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-9): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5760,13 +5960,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-9): 0f 00 00 02 00 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6)cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6)cs_trans(6) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-6): 07 40 00 02 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5780,3 +5982,233 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-5 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(2)cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 d2 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(2) demanded_mcs(2)cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 f2 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-4 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (44) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-4): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-4): 07 00 00 80 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(4) demanded_mcs(1)cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 d6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(1) demanded_mcs(1)cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 f6 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3)cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(6)cs_trans(6) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 2 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..c38417d 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,9 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_egprs_spb_dl === +Testing retx for MCS 6 to reseg_mcs 3 +Testing retx for MCS 5 to reseg_mcs 2 +Testing retx for MCS 4 to reseg_mcs 1 +Testing retx for MCS 6 to reseg_mcs 3 +=== end test_tbf_egprs_spb_dl === -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 14 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Tue Aug 16 09:12:24 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 16 Aug 2016 09:12:24 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 14: (1 comment) https://gerrit.osmocom.org/#/c/655/13/src/pcu_vty.c File src/pcu_vty.c: Line 488: cfg_pcu_dl_arq_cmd, > the other DEFUN() in this file indent the arguments to line up with the fir Done -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 14 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 16 10:49:42 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 16 Aug 2016 10:49:42 +0000 Subject: [PATCH] osmo-pcu[master]: jenkins.sh: drop compat with old matrix params Message-ID: Review at https://gerrit.osmocom.org/701 jenkins.sh: drop compat with old matrix params Change-Id: I7b50a24cf5879cb473a5cf929768bdd30e863a26 --- M contrib/jenkins.sh 1 file changed, 0 insertions(+), 9 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/01/701/1 diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index 7826911..7b456c2 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -7,15 +7,6 @@ exit 1 fi -# Compat: to be able to smoothly reconfigure the jenkins job, handle both -# old and new matrix variables -if [ -z "$with_dsp" -a "$sysmodsp" = yes ]; then - with_dsp="sysmo" -else - with_vty="yes" -fi -# end of compat part - base="$PWD" deps="$base/deps" inst="$deps/install" -- To view, visit https://gerrit.osmocom.org/701 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I7b50a24cf5879cb473a5cf929768bdd30e863a26 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Tue Aug 16 11:08:20 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 16 Aug 2016 11:08:20 +0000 Subject: [PATCH] osmo-pcu[master]: Add data structure to handle SPB for EGPRS DL In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/654 to look at the new patch set (#6). Add data structure to handle SPB for EGPRS DL Modify the header files with necessary data structure to handle Split block for EGPRS DL TBF. The EGPRS resegmentation feature allows PCU to retransmit RLC blocks of HeaderType1, HeaderType2 by segmenting them to 2 HeaderType3 blocks(Example MCS5 will be retransmitted as 2 MCS2 blocks). Table 10.4.8b.2 of 44.060 explains the possible values of SPB in HeadrType3 for DL direction. The PCU decides to retransmit the blocks by resegmenting it based on Table 8.1.1.1 of 44.060. The retransmission MCS is calculated based on current MCS of the Block and demanded MCS by PCU. Section 10.3a.3.3 of 44.060 shows the HeadrType3 with SPB field present in it Change-Id: I57673e53a9da2affa7e8aaa6551ac4b271c3d525 --- M src/bts.h M src/rlc.h 2 files changed, 45 insertions(+), 4 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/54/654/6 diff --git a/src/bts.h b/src/bts.h index 807ce08..38896c8 100644 --- a/src/bts.h +++ b/src/bts.h @@ -186,6 +186,10 @@ uint8_t alpha, gamma; uint8_t egprs_enabled; uint32_t dl_tbf_idle_msec; /* hold time for idle DL TBFs */ + + /* 0 to support resegmentation in DL, 1 for no reseg */ + uint8_t dl_arq_type; + uint32_t ms_idle_sec; uint8_t cs_adj_enabled; uint8_t cs_adj_upper_limit; diff --git a/src/rlc.h b/src/rlc.h index bf2d70a..b1a1fba 100644 --- a/src/rlc.h +++ b/src/rlc.h @@ -84,6 +84,39 @@ }; /* + * EGPRS resegment status information for DL + * When only first segment is sent, bsn state + * will be set to EGPRS_RESEG_FIRST_SEG_SENT and when + * second segment is sent the state will be + * set to EGPRS_RESEG_SECOND_SEG_SENT. + * EGPRS_RESEG_DL_INVALID is set to 8 considering there is a scope for + * 3rd segment according to Table 10.4.8b.2 of 44.060 + * The EGPRS resegmentation feature allows PCU to retransmit + * RLC blocks of HeaderType1, HeaderType2 by segmenting + * them to 2 HeaderType3 blocks(Example MCS5 will be + * retransmitted as 2 MCS2 blocks). Table 10.4.8b.2 of 44.060 + * explains the possible values of SPB in HeadrType3 for DL + * direction.The PCU decides to retransmit the + * blocks by resegmenting it based on Table 8.1.1.1 of 44.060. + * The retransmission MCS is calculated based on current MCS of + * the Block and demanded MCS by PCU. Section 10.3a.3.3 of 44.060 + * shows the HeadrType3 with SPB field present in it + */ +enum egprs_rlc_dl_reseg_bsn_state { + EGPRS_RESEG_DL_DEFAULT = 0, + EGPRS_RESEG_FIRST_SEG_SENT = 0x01, + EGPRS_RESEG_SECOND_SEG_SENT = 0x02, + EGPRS_RESEG_DL_INVALID = 0x08 +}; + +/* Table 10.4.8b.2 of 44.060 */ +enum egprs_rlcmac_dl_spb { + EGPRS_RLCMAC_DL_NO_RETX = 0, + EGPRS_RLCMAC_DL_FIRST_SEG = 2, + EGPRS_RLCMAC_DL_SEC_SEG = 3, +}; + +/* * Valid puncturing scheme values * TS 44.060 10.4.8a.3.1, 10.4.8a.2.1, 10.4.8a.1.1 */ @@ -140,10 +173,7 @@ /* holds the current status of the block w.r.t UL/DL split blocks */ union split_block_status { egprs_rlc_ul_reseg_bsn_state block_status_ul; - /* - * TODO: DL split block status need to be supported - * for EGPRS DL - */ + egprs_rlc_dl_reseg_bsn_state block_status_dl; }; struct gprs_rlc_data { @@ -168,6 +198,13 @@ GprsCodingScheme cs_current_trans; GprsCodingScheme cs_last; + /* + * The MCS of initial transmission of a BSN + * This variable is used for split block + * processing in DL + */ + GprsCodingScheme cs_init; + /* puncturing scheme value to be used for next transmission*/ enum egprs_puncturing_values next_ps; -- To view, visit https://gerrit.osmocom.org/654 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I57673e53a9da2affa7e8aaa6551ac4b271c3d525 Gerrit-PatchSet: 6 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Tue Aug 16 11:08:20 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 16 Aug 2016 11:08:20 +0000 Subject: [PATCH] osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/655 to look at the new patch set (#15). Modify EGPRS DL TBF flow to support SPB Modify the EGPRS DL TBF flow to support Split block during Retx. This patch will also Upgrade the test suite with test cases to validate the EGPRS Downlink SPB for Retransmission Scenarios like MCS6->MCS3, MCS4->MCS1, MCS5->MCS2, MCS9->MCS3 MCS7->MCS2, MCS8->MCS3 have been simulated and Integration tested in NuRAN 1.0 hardware thoroughly. Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 --- M src/gprs_coding_scheme.h M src/pcu_main.cpp M src/pcu_vty.c M src/rlc.cpp M src/rlc.h M src/tbf.h M src/tbf_dl.cpp M tests/edge/EdgeTest.cpp M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 11 files changed, 954 insertions(+), 80 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/55/655/15 diff --git a/src/gprs_coding_scheme.h b/src/gprs_coding_scheme.h index 60a8e79..3b15372 100644 --- a/src/gprs_coding_scheme.h +++ b/src/gprs_coding_scheme.h @@ -113,7 +113,8 @@ static const char *modeName(Mode mode); static Scheme get_retx_mcs(const GprsCodingScheme mcs, - const GprsCodingScheme retx_mcs); + const GprsCodingScheme retx_mcs, + const unsigned arq_type); static enum Scheme egprs_mcs_retx_tbl[MAX_NUM_ARQ] [MAX_NUM_MCS][MAX_NUM_MCS]; @@ -232,8 +233,9 @@ } inline GprsCodingScheme::Scheme GprsCodingScheme::get_retx_mcs( const GprsCodingScheme mcs, - const GprsCodingScheme demanded_mcs) + const GprsCodingScheme demanded_mcs, + const unsigned arq_type) { - return egprs_mcs_retx_tbl[EGPRS_ARQ2][mcs.to_num() - 1] + return egprs_mcs_retx_tbl[arq_type][mcs.to_num() - 1] [demanded_mcs.to_num() - 1]; } diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2d86cda..e34d534 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -210,6 +210,12 @@ bts->dl_tbf_idle_msec = 2000; bts->llc_idle_ack_csec = 10; + /* + * By default resegmentation is supported in DL + * can also be configured through VTY + */ + bts->dl_arq_type = EGPRS_ARQ1; + msgb_set_talloc_ctx(tall_pcu_ctx); osmo_init_logging(&gprs_log_info); diff --git a/src/pcu_vty.c b/src/pcu_vty.c index 58fea99..5854b32 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -129,6 +129,10 @@ vty_out(vty, " window-size %d %d%s", bts->ws_base, bts->ws_pdch, VTY_NEWLINE); + if (bts->dl_arq_type) + vty_out(vty, " dl arq-type %d%s", bts->dl_arq_type, + VTY_NEWLINE); + if (bts->force_llc_lifetime == 0xffff) vty_out(vty, " queue lifetime infinite%s", VTY_NEWLINE); else if (bts->force_llc_lifetime) @@ -477,6 +481,20 @@ bts->max_mcs_dl = 0; bts->max_mcs_ul = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_pcu_dl_arq_type, + cfg_pcu_dl_arq_cmd, + "dl arq-type (0|1)", + EGPRS_STR "DL ARQ options\n" + "enable DL SPB support\n" + "enable DL ARQ2 support") +{ + struct gprs_rlcmac_bts *bts = bts_main_data(); + uint8_t dl_arq_type = atoi(argv[0]); + + bts->dl_arq_type = dl_arq_type; return CMD_SUCCESS; } @@ -954,6 +972,7 @@ install_element(PCU_NODE, &cfg_pcu_no_cs_downgrade_thrsh_cmd); install_element(PCU_NODE, &cfg_pcu_cs_lqual_ranges_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_cmd); + install_element(PCU_NODE, &cfg_pcu_dl_arq_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_max_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_max_cmd); diff --git a/src/rlc.cpp b/src/rlc.cpp index 6770043..e69d1fc 100644 --- a/src/rlc.cpp +++ b/src/rlc.cpp @@ -285,7 +285,8 @@ } static void gprs_rlc_data_header_init(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding, unsigned int header_bits) + GprsCodingScheme cs, bool with_padding, unsigned int header_bits, + const unsigned int spb) { unsigned int i; unsigned int padding_bits = with_padding ? cs.optionalPaddingBits() : 0; @@ -300,7 +301,7 @@ for (i = 0; i < rlc->num_data_blocks; i++) { gprs_rlc_data_block_info_init(&rlc->block_info[i], cs, - with_padding); + with_padding, spb); rlc->data_offs_bits[i] = header_bits + padding_bits + @@ -310,21 +311,25 @@ } void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsDL()); + cs.numDataHeaderBitsDL(), spb); } void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding) { + /* + * last parameter is sent as 0 since common function used + * for both DL and UL + */ return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsUL()); + cs.numDataHeaderBitsUL(), 0); } void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { unsigned int data_len = cs.maxDataBlockBytes(); if (with_padding) @@ -336,7 +341,7 @@ rdbi->e = 1; rdbi->cv = 15; rdbi->pi = 0; - rdbi->spb = 0; + rdbi->spb = spb; } unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, @@ -411,8 +416,18 @@ enum egprs_puncturing_values gprs_get_punct_scheme( enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current) + const GprsCodingScheme &cs_current, + const enum egprs_rlcmac_dl_spb spb) { + + /* + * 10.4.8b of TS 44.060 + * If it is second segment of the block + * dont change the puncturing scheme + */ + if (spb == EGPRS_RLCMAC_DL_SEC_SEG) + return punct; + /* TS 44.060 9.3.2.1.1 */ if ((GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS9) && (GprsCodingScheme::Scheme(cs_current) == GprsCodingScheme::MCS6)) { diff --git a/src/rlc.h b/src/rlc.h index b1a1fba..b693418 100644 --- a/src/rlc.h +++ b/src/rlc.h @@ -213,18 +213,19 @@ }; void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding); void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, enum egprs_puncturing_values punct, enum egprs_puncturing_values punct2, int with_padding); void gprs_rlc_mcs_cps_decode(unsigned int cps, GprsCodingScheme cs, int *punct, int *punct2, int *with_padding); enum egprs_puncturing_values gprs_get_punct_scheme(enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current_trans); + const GprsCodingScheme &cs_current_trans, + const enum egprs_rlcmac_dl_spb spb); void gprs_update_punct_scheme(enum egprs_puncturing_values *punct, const GprsCodingScheme &cs); /* diff --git a/src/tbf.h b/src/tbf.h index 1bd7878..2a1bfe8 100644 --- a/src/tbf.h +++ b/src/tbf.h @@ -421,6 +421,11 @@ int analyse_errors(char *show_rbb, uint8_t ssn, ana_result *res); void schedule_next_frame(); + enum egprs_rlc_dl_reseg_bsn_state egprs_dl_get_data + (int bsn, uint8_t **block_data); + unsigned int get_egprs_dl_spb_status(int bsn); + enum egprs_rlcmac_dl_spb get_egprs_dl_spb(int bsn); + struct osmo_timer_list m_llc_timer; }; diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp index 07a747a..f256f31 100644 --- a/src/tbf_dl.cpp +++ b/src/tbf_dl.cpp @@ -375,21 +375,28 @@ return -1; if (is_egprs_enabled()) { + /* Table 8.1.1.2 and Table 8.1.1.1 of 44.060 */ m_rlc.block(bsn)->cs_current_trans = - GprsCodingScheme::get_retx_mcs( - m_rlc.block(bsn)->cs_last, ms()->current_cs_dl()); + GprsCodingScheme::get_retx_mcs( + m_rlc.block(bsn)->cs_init, + ms()->current_cs_dl(), + bts->bts_data()->dl_arq_type); LOGP(DRLCMACDL, LOGL_DEBUG, - "- current_cs_dl(%d) demanded_mcs(%d) cs_trans(%d)\n", - m_rlc.block(bsn)->cs_last.to_num(), - ms()->current_cs_dl().to_num(), - m_rlc.block(bsn)->cs_current_trans.to_num()); + "- initial_cs_dl(%d) last_mcs(%d)" + " demanded_mcs(%d) cs_trans(%d)" + " arq_type(%d) bsn(%d)\n", + m_rlc.block(bsn)->cs_init.to_num(), + m_rlc.block(bsn)->cs_last.to_num(), + ms()->current_cs_dl().to_num(), + m_rlc.block(bsn)->cs_current_trans.to_num(), + bts->bts_data()->dl_arq_type, bsn); /* TODO: Need to remove this check when MCS-8 -> MCS-6 * transistion is handled. * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 */ - if (m_rlc.block(bsn)->cs_last == GprsCodingScheme::MCS8) + if (m_rlc.block(bsn)->cs_init == GprsCodingScheme::MCS8) m_rlc.block(bsn)->cs_current_trans = GprsCodingScheme::MCS8; } else @@ -523,6 +530,11 @@ data = rlc_data->prepare(block_data_len); rlc_data->cs_last = cs; rlc_data->cs_current_trans = cs; + + /* Initialise the variable related to DL SPB */ + rlc_data->spb_status.block_status_dl = EGPRS_RESEG_DL_DEFAULT; + rlc_data->cs_init = cs; + rlc_data->len = block_data_len; rdbi = &(rlc_data->block_info); @@ -616,7 +628,8 @@ unsigned num_bsns; enum egprs_puncturing_values punct[ARRAY_SIZE(rlc.block_info)]; bool need_padding = false; - + enum egprs_rlcmac_dl_spb spb = EGPRS_RLCMAC_DL_NO_RETX; + unsigned int spb_status = get_egprs_dl_spb_status(index); /* * TODO: This is an experimental work-around to put 2 BSN into * MSC-7 to MCS-9 encoded messages. It just sends the same BSN @@ -626,6 +639,7 @@ * the current limit. */ cs = m_rlc.block(index)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(index)->cs_init; bsns[0] = index; num_bsns = 1; @@ -634,7 +648,17 @@ num_bsns += 1; } - if (num_bsns == 1) { + /* + * if the intial mcs is 8 and retransmission mcs is either 6 or 3 + * we have to include the padding of 6 octets in first segment + */ + if ((GprsCodingScheme::Scheme(cs_init) == GprsCodingScheme::MCS8) && + (GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS6 || + GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS3)) { + if (spb_status == EGPRS_RESEG_DL_DEFAULT || + spb_status == EGPRS_RESEG_SECOND_SEG_SENT) + need_padding = true; + } else if (num_bsns == 1) { /* TODO: remove the conditional when MCS-6 padding isn't * failing to be decoded by MEs anymore */ /* TODO: support of MCS-8 -> MCS-6 transition should be @@ -646,7 +670,14 @@ cs.decToSingleBlock(&need_padding); } - gprs_rlc_data_info_init_dl(&rlc, cs, need_padding); + spb = get_egprs_dl_spb(index); + + LOGP(DRLCMACDL, LOGL_DEBUG, "- need_padding %d spb_status %d spb %d" + "(BSN1 %d BSN2 %d)\n", + need_padding, + spb_status, spb, index, index2); + + gprs_rlc_data_info_init_dl(&rlc, cs, need_padding, spb); rlc.usf = 7; /* will be set at scheduler */ rlc.pr = 0; /* FIXME: power reduction */ @@ -665,10 +696,9 @@ data_block_idx++) { int bsn; - GprsCodingScheme cs_enc; uint8_t *block_data; gprs_rlc_data_block_info *rdbi, *block_info; - enum egprs_puncturing_values punct_scheme; + enum egprs_rlc_dl_reseg_bsn_state reseg_status; /* Check if there are more blocks than BSNs */ if (data_block_idx < num_bsns) @@ -676,38 +706,43 @@ else bsn = bsns[0]; - cs_enc = m_rlc.block(bsn)->cs_current_trans; - /* get data and header from current block */ - block_data = m_rlc.block(bsn)->block; - /* Get current puncturing scheme from block */ - punct_scheme = gprs_get_punct_scheme( + + m_rlc.block(bsn)->next_ps = gprs_get_punct_scheme( m_rlc.block(bsn)->next_ps, - m_rlc.block(bsn)->cs_last, cs); + m_rlc.block(bsn)->cs_last, cs, spb); if (cs.isEgprs()) { - OSMO_ASSERT(punct_scheme >= EGPRS_PS_1); - OSMO_ASSERT(punct_scheme <= EGPRS_PS_3); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps >= EGPRS_PS_1); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps <= EGPRS_PS_3); } - punct[data_block_idx] = punct_scheme; + punct[data_block_idx] = m_rlc.block(bsn)->next_ps; rdbi = &rlc.block_info[data_block_idx]; block_info = &m_rlc.block(bsn)->block_info; - if(rdbi->data_len != m_rlc.block(bsn)->len) { - LOGP(DRLCMACDL, LOGL_ERROR, - "ERROR: Expected len = %d for %s instead of " - "%d in data unit %d (BSN %d, %s)\n", - rdbi->data_len, cs.name(), m_rlc.block(bsn)->len, - data_block_idx, bsn, cs_enc.name()); - OSMO_ASSERT(rdbi->data_len == m_rlc.block(bsn)->len); - } - - /* TODO: Need to handle 2 same bsns - * in header type 1 + /* + * get data and header from current block + * function returns the reseg status */ - gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, - cs); + reseg_status = egprs_dl_get_data(bsn, &block_data); + m_rlc.block(bsn)->spb_status.block_status_dl = reseg_status; + + /* + * If it is first segment of the split block set the state of + * bsn to nacked. If it is the first segment dont update the + * next ps value of bsn. since next segment also needs same cps + */ + if (spb == EGPRS_RLCMAC_DL_FIRST_SEG) + m_window.m_v_b.mark_nacked(bsn); + else { + /* + * TODO: Need to handle 2 same bsns + * in header type 1 + */ + gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, + cs); + } m_rlc.block(bsn)->cs_last = cs; rdbi->e = block_info->e; @@ -1169,3 +1204,119 @@ keep_time_frames = msecs_to_frames(bts_data()->dl_tbf_idle_msec); return frames_since_last_drain(fn) <= keep_time_frames; } + +/* + * This function returns the pointer to data which needs + * to be copied. Also updates the status of the block related to + * Split block handling in the RLC/MAC block. + */ +enum egprs_rlc_dl_reseg_bsn_state + gprs_rlcmac_dl_tbf::egprs_dl_get_data(int bsn, + uint8_t **block_data) +{ + gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state *block_status_dl = + &rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + *block_data = &rlc_data->block[0]; + + /* + * Table 10.3a.0.1 of 44.060 + * MCS6,9: second segment starts at 74/2 = 37 + * MCS5,7: second segment starts at 56/2 = 28 + * MCS8: second segment starts at 31 + * MCS4: second segment starts at 44/2 = 22 + */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + if (*block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + switch (GprsCodingScheme::Scheme(cs_init)) { + case GprsCodingScheme::MCS6 : + case GprsCodingScheme::MCS9 : + *block_data = &rlc_data->block[37]; + break; + case GprsCodingScheme::MCS7 : + case GprsCodingScheme::MCS5 : + *block_data = &rlc_data->block[28]; + break; + case GprsCodingScheme::MCS8 : + *block_data = &rlc_data->block[31]; + break; + case GprsCodingScheme::MCS4 : + *block_data = &rlc_data->block[22]; + break; + default: + LOGP(DRLCMACDL, LOGL_ERROR, "Software error: " + "--%s hit invalid condition. headerType(%d) " + " blockstatus(%d) cs(%s) PLEASE FIX!\n", name(), + cs_current_trans.headerTypeData(), + *block_status_dl, cs_init.name()); + break; + + } + return EGPRS_RESEG_SECOND_SEG_SENT; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } + } + return EGPRS_RESEG_DL_DEFAULT; +} + +/* + * This function returns the status of split block + * for RLC/MAC block. + */ +unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_status(const int bsn) +{ + const gprs_rlc_data *rlc_data = m_rlc.block(bsn); + + return rlc_data->spb_status.block_status_dl; +} + +/* + * This function returns the spb value to be sent OTA + * for RLC/MAC block. + */ +enum egprs_rlcmac_dl_spb gprs_rlcmac_dl_tbf::get_egprs_dl_spb(const int bsn) +{ + struct gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state block_status_dl = + rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + + /* Table 10.4.8b.1 of 44.060 */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + /* + * if we are sending the second segment the spb should be 3 + * other wise it should be 2 + */ + if (block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + return EGPRS_RLCMAC_DL_SEC_SEG; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RLCMAC_DL_FIRST_SEG; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RLCMAC_DL_FIRST_SEG; + } + } + /* Non SPB cases 0 is reurned */ + return EGPRS_RLCMAC_DL_NO_RETX; +} diff --git a/tests/edge/EdgeTest.cpp b/tests/edge/EdgeTest.cpp index 807102c..9081d4d 100644 --- a/tests/edge/EdgeTest.cpp +++ b/tests/edge/EdgeTest.cpp @@ -517,7 +517,7 @@ /* TS 44.060, B.1 */ cs = GprsCodingScheme::CS4; - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -570,7 +570,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -592,7 +592,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -630,7 +630,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -669,7 +669,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -694,7 +694,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -719,7 +719,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -740,7 +740,7 @@ OSMO_ASSERT(data[0] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -777,7 +777,7 @@ cs = GprsCodingScheme::MCS4; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -835,7 +835,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -872,7 +872,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -923,7 +923,7 @@ OSMO_ASSERT(data[3] == 0); /* Block 3 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -967,7 +967,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -993,7 +993,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1020,7 +1020,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1074,7 +1074,7 @@ block_idx++) { struct gprs_rlc_data_info rlc; - gprs_rlc_data_info_init_dl(&rlc, cs, false); + gprs_rlc_data_info_init_dl(&rlc, cs, false, 0); memset(bits, pattern, sizeof(bits)); Decoding::rlc_copy_to_aligned_buffer( @@ -1118,12 +1118,14 @@ struct gprs_rlc_data_info rlc; printf("=== start %s ===\n", __func__); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::CS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::CS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 24); OSMO_ASSERT(rlc.block_info[0].data_len == 20); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::MCS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::MCS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 33); OSMO_ASSERT(rlc.block_info[0].data_len == 22); diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..5e45506 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -1814,6 +1814,203 @@ } +static void egprs_spb_to_normal_validation(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + uint16_t bsn1, bsn2, bsn3; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + struct gprs_rlc_dl_header_egprs_2 *egprs2; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + if (!(mcs == 6 && demanded_mcs == 3)) + return; + + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + bsn1 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) + || (egprs2->bsn1_lo); + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(bsn1 == 0); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + bsn2 = (egprs3->bsn1_hi << 9) || (egprs3->bsn1_mid << 1) || + (egprs3->bsn1_lo); + OSMO_ASSERT(bsn2 == bsn1); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Handle (MCS3, MCS3) -> MCS6 case */ + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + mcs)); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs2->cps == 0); + bsn3 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) || + (egprs2->bsn1_lo); + OSMO_ASSERT(bsn3 == bsn2); + + tbf_cleanup(dl_tbf); +} +static void establish_and_use_egprs_dl_tbf_for_spb(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + /* TODO: Need to support of MCS8 -> MCS6 ->MCS3 transistion + * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 + * dated 2016-02-07 23:45:40 (UTC) + */ + if (!(((mcs == 5) && (demanded_mcs == 2)) || + ((mcs == 6) && (demanded_mcs == 3)) || + ((mcs == 4) && (demanded_mcs == 1)))) + return; + + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + tbf_cleanup(dl_tbf); +} + static void establish_and_use_egprs_dl_tbf_for_retx(BTS *the_bts, int mcs, int demanded_mcs) { @@ -1972,6 +2169,9 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; + /* First parameter is current MCS, second one is demanded_mcs */ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 6); @@ -1981,6 +2181,38 @@ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 9); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 7, 5); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 9, 6); + + printf("=== end %s ===\n", __func__); +} + +static void test_tbf_egprs_spb_dl(void) +{ + BTS the_bts; + gprs_rlcmac_bts *bts; + uint8_t ts_no = 4; + int i, j; + + printf("=== start %s ===\n", __func__); + + bts = the_bts.bts_data(); + bts->cs_downgrade_threshold = 0; + setup_bts(&the_bts, ts_no); + bts->dl_tbf_idle_msec = 200; + bts->egprs_enabled = 1; + + /* ARQ I resegmentation support */ + bts->dl_arq_type = EGPRS_ARQ1; + + /* + * First parameter is current MCS, second one is demanded_mcs + * currently only MCS5->MCS2, MCS6->3, MCS4->MCS1 is tested in UT + * rest scenarios has been integration tested + */ + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 6, 3); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 5, 2); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 4, 1); + /* check MCS6->(MCS3+MCS3)->MCS6 case */ + egprs_spb_to_normal_validation(&the_bts, 6, 3); printf("=== end %s ===\n", __func__); } @@ -1999,6 +2231,8 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; for (i = 1; i <= 9; i++) establish_and_use_egprs_dl_tbf(&the_bts, i); @@ -2071,6 +2305,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_egprs_spb_dl(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..1ba4189 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -72,6 +72,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -81,6 +82,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -157,6 +159,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -166,6 +169,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -242,6 +246,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -251,6 +256,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -259,6 +265,7 @@ - Sending new block at BSN 2, CS=CS-1 -- Chunk with length 160 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=13 block=3 data=07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b @@ -267,6 +274,7 @@ - Sending new block at BSN 3, CS=CS-1 -- Chunk with length 140 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=17 block=4 data=07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @@ -275,6 +283,7 @@ - Sending new block at BSN 4, CS=CS-1 -- Chunk with length 120 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=21 block=5 data=07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 @@ -283,6 +292,7 @@ - Sending new block at BSN 5, CS=CS-1 -- Chunk with length 100 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=26 block=6 data=07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 @@ -291,6 +301,7 @@ - Sending new block at BSN 6, CS=CS-1 -- Chunk with length 80 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=30 block=7 data=07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b @@ -299,6 +310,7 @@ - Sending new block at BSN 7, CS=CS-1 -- Chunk with length 60 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=34 block=8 data=07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f @@ -307,6 +319,7 @@ - Sending new block at BSN 8, CS=CS-1 -- Chunk with length 40 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=39 block=9 data=07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 @@ -315,6 +328,7 @@ - Sending new block at BSN 9, CS=CS-1 -- Chunk with length 20 would exactly fit into space (20): add length header with LI=0, to make frame extend to next block, and we are done data block (BSN 9, CS-1): 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=43 block=10 data=07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 @@ -326,6 +340,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=47 block=11 data=07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 @@ -334,6 +349,7 @@ - Sending new block at BSN 11, CS=CS-1 -- Chunk with length 182 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=52 block=0 data=07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 @@ -342,6 +358,7 @@ - Sending new block at BSN 12, CS=CS-1 -- Chunk with length 162 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=56 block=1 data=07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 @@ -350,6 +367,7 @@ - Sending new block at BSN 13, CS=CS-1 -- Chunk with length 142 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 13, CS-1): 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=60 block=2 data=07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d @@ -358,6 +376,7 @@ - Sending new block at BSN 14, CS=CS-1 -- Chunk with length 122 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=65 block=3 data=07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 @@ -366,6 +385,7 @@ - Sending new block at BSN 15, CS=CS-1 -- Chunk with length 102 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=69 block=4 data=07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 @@ -374,6 +394,7 @@ - Sending new block at BSN 16, CS=CS-1 -- Chunk with length 82 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=73 block=5 data=07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 @@ -382,6 +403,7 @@ - Sending new block at BSN 17, CS=CS-1 -- Chunk with length 62 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=78 block=6 data=07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d @@ -390,6 +412,7 @@ - Sending new block at BSN 18, CS=CS-1 -- Chunk with length 42 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=82 block=7 data=07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 @@ -398,6 +421,7 @@ - Sending new block at BSN 19, CS=CS-1 -- Chunk with length 22 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=86 block=8 data=07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 @@ -411,6 +435,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=16 data block (BSN 20, CS-1): 0a 41 c6 c7 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -449,6 +474,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 data block (BSN 21, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -468,6 +494,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 22, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FINISHED) @@ -1481,6 +1508,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 0, CS-1): 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 MSG = 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 @@ -1491,6 +1519,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 1, CS-1): 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 MSG = 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 @@ -1501,6 +1530,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FINISHED data block (BSN 2, CS-1): 4d 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling cannot be scheduled in this TS 7 (first control TS 4) @@ -1784,6 +1814,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=10 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 0, CS-4): 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654292 TS 7 @@ -1797,6 +1828,7 @@ TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) downlink (V(A)==0 .. V(S)==1) - Restarting at BSN 0, because all blocks have been transmitted. - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-4): 07 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 @@ -2365,6 +2397,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654279 block=10 data=00 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 @@ -2384,6 +2417,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -2406,6 +2440,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654288 block=0 data=00 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 @@ -2425,6 +2460,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654292 block=1 data=00 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2447,6 +2483,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654296 block=2 data=00 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c @@ -2466,6 +2503,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654301 block=3 data=00 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b @@ -2488,6 +2526,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 6, CS-1): 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654305 block=4 data=00 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 @@ -2507,6 +2546,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654309 block=5 data=00 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 @@ -2526,6 +2566,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654314 block=6 data=00 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 @@ -2548,6 +2589,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654318 block=7 data=00 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 @@ -2567,6 +2609,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654322 block=8 data=00 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2589,6 +2632,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654327 block=9 data=00 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c @@ -2608,6 +2652,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654331 block=10 data=00 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b @@ -2630,6 +2675,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 13, CS-1): 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654335 block=11 data=00 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 @@ -2649,6 +2695,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654340 block=0 data=00 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 @@ -2668,6 +2715,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654344 block=1 data=00 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 @@ -2690,6 +2738,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654348 block=2 data=00 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 @@ -2709,6 +2758,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654353 block=3 data=00 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2731,6 +2781,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654357 block=4 data=00 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c @@ -2750,6 +2801,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654361 block=5 data=00 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b @@ -2772,6 +2824,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 20, CS-1): 16 35 45 54 20 32 38 4c 4c 43 20 50 41 43 4b 45 54 20 32 39 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because 20 blocks sent. TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW): Scheduling polling at FN 2654379 TS 7 @@ -2795,6 +2848,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 21, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) msg block (BSN 21, CS-1): 07 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654370 block=7 data=00 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 @@ -2814,6 +2868,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 22, CS-1): 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) msg block (BSN 22, CS-1): 07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654374 block=8 data=07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 @@ -2836,6 +2891,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 23, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) msg block (BSN 23, CS-1): 07 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654379 block=9 data=00 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 @@ -2855,6 +2911,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 24, CS-1): 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) msg block (BSN 24, CS-1): 07 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654383 block=10 data=00 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2877,6 +2934,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 25, CS-1): 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 25 BSN2 -1) - Copying data unit 0 (BSN 25) msg block (BSN 25, CS-1): 07 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654387 block=11 data=00 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c @@ -2896,6 +2954,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 26, CS-1): 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 26 BSN2 -1) - Copying data unit 0 (BSN 26) msg block (BSN 26, CS-1): 07 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654392 block=0 data=00 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b @@ -2918,6 +2977,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 27, CS-1): 16 35 45 54 20 33 38 4c 4c 43 20 50 41 43 4b 45 54 20 33 39 +- need_padding 0 spb_status 0 spb 0(BSN1 27 BSN2 -1) - Copying data unit 0 (BSN 27) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) @@ -3028,6 +3088,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654405 block=3 data=00 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 @@ -3047,6 +3108,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654409 block=4 data=00 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 @@ -3066,6 +3128,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (16) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654413 block=5 data=00 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 @@ -3085,6 +3148,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (14) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654418 block=6 data=00 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 @@ -3104,6 +3168,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654422 block=7 data=00 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -3123,6 +3188,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654426 block=8 data=00 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 @@ -3142,6 +3208,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654431 block=9 data=00 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b @@ -3161,6 +3228,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654435 block=10 data=00 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 @@ -3180,6 +3248,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654439 block=11 data=00 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 @@ -3199,6 +3268,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654444 block=0 data=00 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c @@ -3218,6 +3288,7 @@ Complete DL frame for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=21 TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 10, CS-1): 4d 43 20 50 41 43 4b 45 54 20 30 39 20 28 54 42 46 20 32 29 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654461 TS 7 @@ -3698,6 +3769,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 0, MCS-1): 14 15 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3711,6 +3783,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3721,6 +3794,7 @@ - Sending new block at BSN 2, CS=MCS-1 -- Chunk with length 490 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3731,6 +3805,7 @@ - Sending new block at BSN 3, CS=MCS-1 -- Chunk with length 468 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3741,6 +3816,7 @@ - Sending new block at BSN 4, CS=MCS-1 -- Chunk with length 446 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3751,6 +3827,7 @@ - Sending new block at BSN 5, CS=MCS-1 -- Chunk with length 424 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3761,6 +3838,7 @@ - Sending new block at BSN 6, CS=MCS-1 -- Chunk with length 402 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3771,6 +3849,7 @@ - Sending new block at BSN 7, CS=MCS-1 -- Chunk with length 380 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3781,6 +3860,7 @@ - Sending new block at BSN 8, CS=MCS-1 -- Chunk with length 358 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3791,6 +3871,7 @@ - Sending new block at BSN 9, CS=MCS-1 -- Chunk with length 336 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3801,6 +3882,7 @@ - Sending new block at BSN 10, CS=MCS-1 -- Chunk with length 314 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3811,6 +3893,7 @@ - Sending new block at BSN 11, CS=MCS-1 -- Chunk with length 292 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3821,6 +3904,7 @@ - Sending new block at BSN 12, CS=MCS-1 -- Chunk with length 270 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3831,6 +3915,7 @@ - Sending new block at BSN 13, CS=MCS-1 -- Chunk with length 248 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3841,6 +3926,7 @@ - Sending new block at BSN 14, CS=MCS-1 -- Chunk with length 226 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3851,6 +3937,7 @@ - Sending new block at BSN 15, CS=MCS-1 -- Chunk with length 204 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3861,6 +3948,7 @@ - Sending new block at BSN 16, CS=MCS-1 -- Chunk with length 182 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3871,6 +3959,7 @@ - Sending new block at BSN 17, CS=MCS-1 -- Chunk with length 160 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3881,6 +3970,7 @@ - Sending new block at BSN 18, CS=MCS-1 -- Chunk with length 138 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3891,6 +3981,7 @@ - Sending new block at BSN 19, CS=MCS-1 -- Chunk with length 116 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 19, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3901,6 +3992,7 @@ - Sending new block at BSN 20, CS=MCS-1 -- Chunk with length 94 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 20, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3911,6 +4003,7 @@ - Sending new block at BSN 21, CS=MCS-1 -- Chunk with length 72 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 21, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3921,6 +4014,7 @@ - Sending new block at BSN 22, CS=MCS-1 -- Chunk with length 50 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 22, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3931,6 +4025,7 @@ - Sending new block at BSN 23, CS=MCS-1 -- Chunk with length 28 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 23, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3946,6 +4041,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 24, MCS-1): 0c 1d 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4006,6 +4102,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=16 data block (BSN 0, MCS-2): 14 21 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4019,6 +4116,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4029,6 +4127,7 @@ - Sending new block at BSN 2, CS=MCS-2 -- Chunk with length 484 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4039,6 +4138,7 @@ - Sending new block at BSN 3, CS=MCS-2 -- Chunk with length 456 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4049,6 +4149,7 @@ - Sending new block at BSN 4, CS=MCS-2 -- Chunk with length 428 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4059,6 +4160,7 @@ - Sending new block at BSN 5, CS=MCS-2 -- Chunk with length 400 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4069,6 +4171,7 @@ - Sending new block at BSN 6, CS=MCS-2 -- Chunk with length 372 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4079,6 +4182,7 @@ - Sending new block at BSN 7, CS=MCS-2 -- Chunk with length 344 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4089,6 +4193,7 @@ - Sending new block at BSN 8, CS=MCS-2 -- Chunk with length 316 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4099,6 +4204,7 @@ - Sending new block at BSN 9, CS=MCS-2 -- Chunk with length 288 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4109,6 +4215,7 @@ - Sending new block at BSN 10, CS=MCS-2 -- Chunk with length 260 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4119,6 +4226,7 @@ - Sending new block at BSN 11, CS=MCS-2 -- Chunk with length 232 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4129,6 +4237,7 @@ - Sending new block at BSN 12, CS=MCS-2 -- Chunk with length 204 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4139,6 +4248,7 @@ - Sending new block at BSN 13, CS=MCS-2 -- Chunk with length 176 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4149,6 +4259,7 @@ - Sending new block at BSN 14, CS=MCS-2 -- Chunk with length 148 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4159,6 +4270,7 @@ - Sending new block at BSN 15, CS=MCS-2 -- Chunk with length 120 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4169,6 +4281,7 @@ - Sending new block at BSN 16, CS=MCS-2 -- Chunk with length 92 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4179,6 +4292,7 @@ - Sending new block at BSN 17, CS=MCS-2 -- Chunk with length 64 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4189,6 +4303,7 @@ - Sending new block at BSN 18, CS=MCS-2 -- Chunk with length 36 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4204,6 +4319,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=18 data block (BSN 19, MCS-2): 10 25 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4264,6 +4380,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=25 data block (BSN 0, MCS-3): 14 33 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4277,6 +4394,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4287,6 +4405,7 @@ - Sending new block at BSN 2, CS=MCS-3 -- Chunk with length 475 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4297,6 +4416,7 @@ - Sending new block at BSN 3, CS=MCS-3 -- Chunk with length 438 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4307,6 +4427,7 @@ - Sending new block at BSN 4, CS=MCS-3 -- Chunk with length 401 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4317,6 +4438,7 @@ - Sending new block at BSN 5, CS=MCS-3 -- Chunk with length 364 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4327,6 +4449,7 @@ - Sending new block at BSN 6, CS=MCS-3 -- Chunk with length 327 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4337,6 +4460,7 @@ - Sending new block at BSN 7, CS=MCS-3 -- Chunk with length 290 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4347,6 +4471,7 @@ - Sending new block at BSN 8, CS=MCS-3 -- Chunk with length 253 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4357,6 +4482,7 @@ - Sending new block at BSN 9, CS=MCS-3 -- Chunk with length 216 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4367,6 +4493,7 @@ - Sending new block at BSN 10, CS=MCS-3 -- Chunk with length 179 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4377,6 +4504,7 @@ - Sending new block at BSN 11, CS=MCS-3 -- Chunk with length 142 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4387,6 +4515,7 @@ - Sending new block at BSN 12, CS=MCS-3 -- Chunk with length 105 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4397,6 +4526,7 @@ - Sending new block at BSN 13, CS=MCS-3 -- Chunk with length 68 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4410,6 +4540,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-3): 3f 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4425,6 +4556,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=34 data block (BSN 15, MCS-3): 02 45 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4485,6 +4617,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=32 data block (BSN 0, MCS-4): 14 41 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4498,6 +4631,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4508,6 +4642,7 @@ - Sending new block at BSN 2, CS=MCS-4 -- Chunk with length 468 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4518,6 +4653,7 @@ - Sending new block at BSN 3, CS=MCS-4 -- Chunk with length 424 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4528,6 +4664,7 @@ - Sending new block at BSN 4, CS=MCS-4 -- Chunk with length 380 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4538,6 +4675,7 @@ - Sending new block at BSN 5, CS=MCS-4 -- Chunk with length 336 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4548,6 +4686,7 @@ - Sending new block at BSN 6, CS=MCS-4 -- Chunk with length 292 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4558,6 +4697,7 @@ - Sending new block at BSN 7, CS=MCS-4 -- Chunk with length 248 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4568,6 +4708,7 @@ - Sending new block at BSN 8, CS=MCS-4 -- Chunk with length 204 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4578,6 +4719,7 @@ - Sending new block at BSN 9, CS=MCS-4 -- Chunk with length 160 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4588,6 +4730,7 @@ - Sending new block at BSN 10, CS=MCS-4 -- Chunk with length 116 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4598,6 +4741,7 @@ - Sending new block at BSN 11, CS=MCS-4 -- Chunk with length 72 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4613,6 +4757,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 12, MCS-4): 38 1d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4673,6 +4818,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-5): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4686,6 +4832,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4696,6 +4843,7 @@ - Sending new block at BSN 2, CS=MCS-5 -- Chunk with length 456 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4706,6 +4854,7 @@ - Sending new block at BSN 3, CS=MCS-5 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4716,6 +4865,7 @@ - Sending new block at BSN 4, CS=MCS-5 -- Chunk with length 344 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4726,6 +4876,7 @@ - Sending new block at BSN 5, CS=MCS-5 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4736,6 +4887,7 @@ - Sending new block at BSN 6, CS=MCS-5 -- Chunk with length 232 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4746,6 +4898,7 @@ - Sending new block at BSN 7, CS=MCS-5 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4756,6 +4909,7 @@ - Sending new block at BSN 8, CS=MCS-5 -- Chunk with length 120 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4766,6 +4920,7 @@ - Sending new block at BSN 9, CS=MCS-5 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4781,6 +4936,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-5): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4841,6 +4997,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-6): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4854,6 +5011,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4864,6 +5022,7 @@ - Sending new block at BSN 2, CS=MCS-6 -- Chunk with length 438 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4874,6 +5033,7 @@ - Sending new block at BSN 3, CS=MCS-6 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4884,6 +5044,7 @@ - Sending new block at BSN 4, CS=MCS-6 -- Chunk with length 290 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4894,6 +5055,7 @@ - Sending new block at BSN 5, CS=MCS-6 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4904,6 +5066,7 @@ - Sending new block at BSN 6, CS=MCS-6 -- Chunk with length 142 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4917,6 +5080,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-6): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4932,6 +5096,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-6): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4993,6 +5158,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-7): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5002,12 +5168,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(7) last_mcs(5) demanded_mcs(7) cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-7 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5022,6 +5189,7 @@ - Sending new block at BSN 3, CS=MCS-7 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5036,6 +5204,7 @@ - Sending new block at BSN 5, CS=MCS-7 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5050,6 +5219,7 @@ - Sending new block at BSN 7, CS=MCS-7 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5064,6 +5234,7 @@ - Sending new block at BSN 9, CS=MCS-7 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 9) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5081,6 +5252,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-7): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5142,6 +5314,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=56 data block (BSN 0, MCS-8): 14 71 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5152,12 +5325,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(8) demanded_mcs(8) cs_trans(8) +- initial_cs_dl(8) last_mcs(8) demanded_mcs(8) cs_trans(8) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-8 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5172,6 +5346,7 @@ - Sending new block at BSN 3, CS=MCS-8 -- Chunk with length 376 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5186,6 +5361,7 @@ - Sending new block at BSN 5, CS=MCS-8 -- Chunk with length 240 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5200,6 +5376,7 @@ - Sending new block at BSN 7, CS=MCS-8 -- Chunk with length 104 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5217,6 +5394,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=30 data block (BSN 8, MCS-8): 48 3d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5279,6 +5457,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-9): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5288,12 +5467,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(9) last_mcs(6) demanded_mcs(9) cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-9 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5308,6 +5488,7 @@ - Sending new block at BSN 3, CS=MCS-9 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5322,6 +5503,7 @@ - Sending new block at BSN 5, CS=MCS-9 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5339,6 +5521,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-9): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5356,6 +5539,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-9): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5402,11 +5586,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(6) cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5450,11 +5636,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 96 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(1) demanded_mcs(1) cs_trans(1) +- initial_cs_dl(1) last_mcs(1) demanded_mcs(1) cs_trans(1) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 98 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5498,11 +5686,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-2): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 92 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(2) demanded_mcs(2) cs_trans(2) +- initial_cs_dl(2) last_mcs(2) demanded_mcs(2) cs_trans(2) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 94 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5546,6 +5736,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5557,6 +5748,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-5): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5564,10 +5756,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-5): 0f 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7) cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7) cs_trans(7) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-7): 07 00 00 02 c0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 @@ -5612,6 +5805,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5623,6 +5817,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-6): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5630,10 +5825,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-6): 0f 40 00 00 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9) cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9) cs_trans(9) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-9): 07 00 00 02 28 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 @@ -5686,6 +5882,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-7): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5694,13 +5891,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-7): 0f 00 00 02 a0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5) cs_trans(5) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5) cs_trans(5) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-5): 07 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5752,6 +5951,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-9): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5760,13 +5960,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-9): 0f 00 00 02 00 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6) cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6) cs_trans(6) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-6): 07 40 00 02 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5780,3 +5982,233 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-5 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(2) cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 d2 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(2) demanded_mcs(2) cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 f2 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-4 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (44) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-4): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-4): 07 00 00 80 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(4) demanded_mcs(1) cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 d6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(1) demanded_mcs(1) cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 f6 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(6) cs_trans(6) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 2 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..c38417d 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,9 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_egprs_spb_dl === +Testing retx for MCS 6 to reseg_mcs 3 +Testing retx for MCS 5 to reseg_mcs 2 +Testing retx for MCS 4 to reseg_mcs 1 +Testing retx for MCS 6 to reseg_mcs 3 +=== end test_tbf_egprs_spb_dl === -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 15 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Tue Aug 16 11:15:01 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 16 Aug 2016 11:15:01 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 15: (8 comments) Hi Neels, Thanks for reviewing the changes. I have addressed all the comments raised by you. Please have a look. Thanks, Aravind Sirsikar https://gerrit.osmocom.org/#/c/655/13/src/rlc.h File src/rlc.h: Line 113: enum egprs_rlcmac_dl_spb { > an enum always contains "values", so this name could be shortened by droppi Done https://gerrit.osmocom.org/#/c/655/13/src/tbf.h File src/tbf.h: Line 424: enum egprs_rlc_dl_reseg_bsn_state egprs_dl_get_data > data is always in a buffer, maybe drop the "_buffer" Done https://gerrit.osmocom.org/#/c/655/13/src/tbf_dl.cpp File src/tbf_dl.cpp: Line 383: bts->bts_data()->dl_arq_type); > I would add another tab indent for the arguments of get_retx_mcs() Done Line 392: m_rlc.block(bsn)->cs_current_trans.to_num(), > I would add another 5-spaces indent for the arguments of LOGP(). If the 80 Done Line 660: need_padding = true; > I find the indenting of the if condition confusing. Done Line 1292: struct gprs_rlc_data *rlc_data = m_rlc.block(bsn); > if you also drop the "_value" from "get_egprs_dl_spb_value", this will fit Done https://gerrit.osmocom.org/#/c/655/13/tests/tbf/TbfTest.cpp File tests/tbf/TbfTest.cpp: Line 1839: if (!(mcs == 6 && demanded_mcs == 3)) > basically the entire function is in an if {} block. Remove the indent by do Done Line 1937: ((mcs == 6) && (demanded_mcs == 3)) || > again, remove indent by if (![...]) return; Done -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 15 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 16 15:37:37 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Tue, 16 Aug 2016 15:37:37 +0000 Subject: [PATCH] openbsc[master]: Adding SNDCP-XID encoder / decoder and unit test In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/641 to look at the new patch set (#10). Adding SNDCP-XID encoder / decoder and unit test The SNDCP-XID (or layer-3 xid) is used to exchange layer-3 parameters such as compression. The encoder encodes a bytestream that is then sent as regular XID field from LLC. We will need the SNDCP-XID to negotiate the parameters for our upcomming GPRS data and header compression features Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e --- M openbsc/.gitignore M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_sndcp_xid.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_sndcp_xid.c M openbsc/tests/Makefile.am M openbsc/tests/sgsn/Makefile.am A openbsc/tests/sndcp_xid/Makefile.am A openbsc/tests/sndcp_xid/sndcp_xid_test.c A openbsc/tests/sndcp_xid/sndcp_xid_test.ok M openbsc/tests/testsuite.at 12 files changed, 2,416 insertions(+), 5 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/41/641/10 diff --git a/openbsc/.gitignore b/openbsc/.gitignore index 0a2965d..8ce3b70 100644 --- a/openbsc/.gitignore +++ b/openbsc/.gitignore @@ -81,6 +81,8 @@ tests/oap/oap_test tests/gtphub/gtphub_test tests/mm_auth/mm_auth_test +tests/xid/xid_test +tests/sndcp_xid/sndcp_xid_test tests/atconfig tests/atlocal diff --git a/openbsc/configure.ac b/openbsc/configure.ac index fbf2930..53072bd 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -230,6 +230,7 @@ tests/gtphub/Makefile tests/mm_auth/Makefile tests/xid/Makefile + tests/sndcp_xid/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index ce5f768..e200b05 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,7 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_llc_xid.h gprs_sndcp.h + gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_sndcp_xid.h b/openbsc/include/openbsc/gprs_sndcp_xid.h new file mode 100644 index 0000000..8c5cbf4 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_xid.h @@ -0,0 +1,214 @@ +/* GPRS SNDCP XID field encoding/decoding as per 3GPP TS 44.065 */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_SNDCP_XID_H +#define _GPRS_SNDCP_XID_H + +#include +#include + +#define CURRENT_SNDCP_VERSION 0 /* See 3GPP TS 44.065, clause 8 */ +#define MAX_ENTITIES 32 /* 3GPP TS 44.065 reserves 5 bit + * for compression enitity number */ + +/* According to: 3GPP TS 44.065, 6.5.1.1 Format of the protocol control + * information compression field (Figure 7) + * 3GPP TS 44.065, 6.6.1.1 Format of the data compression + * field (Figure 9) */ +struct gprs_sndcp_comp_field { + struct llist_head list; + + /* Propose bit (P), see also: 6.5.1.1.2 and 6.6.1.1.2 */ + unsigned int p; + + /* Entity number, see also: 6.5.1.1.3 and 6.6.1.1.3 */ + unsigned int entity; + + /* Algorithm identifier, see also: 6.5.1.1.4 and 6.6.1.1.4 */ + int algo; + + /* Number of contained PCOMP / DCOMP values */ + unsigned int comp_len; + + /* PCOMP / DCOMP values, see also: 6.5.1.1.5 and 6.6.1.1.5 */ + unsigned int comp[16]; + + /* Note: Only one of the following struct pointers may, + be used unused pointers must be set to NULL! */ + struct gprs_sndcp_pcomp_rfc1144_params *rfc1144_params; + struct gprs_sndcp_pcomp_rfc2507_params *rfc2507_params; + struct gprs_sndcp_pcomp_rohc_params *rohc_params; + struct gprs_sndcp_dcomp_v42bis_params *v42bis_params; + struct gprs_sndcp_dcomp_v44_params *v44_params; +}; + +/* According to: 3GPP TS 44.065, 6.5.1.1.4 Algorithm identifier */ +enum gprs_sndcp_hdr_comp_algo { + RFC_1144, /* TCP/IP header compression, see also 6.5.2 */ + RFC_2507, /* TCP/UDP/IP header compression, see also: 6.5.3 */ + ROHC /* Robust Header Compression, see also 6.5.4 */ +}; + +/* According to: 3GPP TS 44.065, 6.5.1.1.4 Algorithm identifier */ +enum gprs_sndcp_data_comp_algo { + V42BIS, /* V.42bis data compression, see also 6.6.2 */ + V44 /* V44 data compression, see also: 6.6.3 */ +}; + +/* According to: 3GPP TS 44.065, 8 SNDCP XID parameters */ +enum gprs_sndcp_xid_param_types { + SNDCP_XID_VERSION_NUMBER, + SNDCP_XID_DATA_COMPRESSION, /* See also: subclause 6.6.1 */ + SNDCP_XID_PROTOCOL_COMPRESSION, /* See also: subclause 6.5.1 */ +}; + +/* According to: 3GPP TS 44.065, 6.5.2.1 Parameters (Table 5) */ +struct gprs_sndcp_pcomp_rfc1144_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int s01; /* (default 15) */ +}; + +/* According to: 3GPP TS 44.065, 6.5.2.2 Assignment of PCOMP values */ +enum gprs_sndcp_pcomp_rfc1144_pcomp { + RFC1144_PCOMP1, /* Uncompressed TCP */ + RFC1144_PCOMP2, /* Compressed TCP */ + RFC1144_PCOMP_NUM /* Number of pcomp values */ +}; + +/* According to: 3GPP TS 44.065, 6.5.3.1 Parameters (Table 6) */ +struct gprs_sndcp_pcomp_rfc2507_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int f_max_period; /* (default 256) */ + int f_max_time; /* (default 5) */ + int max_header; /* (default 168) */ + int tcp_space; /* (default 15) */ + int non_tcp_space; /* (default 15) */ +}; + +/* According to: 3GPP TS 44.065, 6.5.3.2 Assignment of PCOMP values for RFC2507 */ +enum gprs_sndcp_pcomp_rfc2507_pcomp { + RFC2507_PCOMP1, /* Full Header */ + RFC2507_PCOMP2, /* Compressed TCP */ + RFC2507_PCOMP3, /* Compressed TCP non delta */ + RFC2507_PCOMP4, /* Compressed non TCP */ + RFC2507_PCOMP5, /* Context state */ + RFC2507_PCOMP_NUM /* Number of pcomp values */ +}; + +/* According to: 3GPP TS 44.065, 6.5.4.1 Parameter (Table 10) */ +struct gprs_sndcp_pcomp_rohc_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int max_cid; /* (default 15) */ + int max_header; /* (default 168) */ + unsigned int profile_len; /* (default 1) */ + uint16_t profile[16]; /* (default 0, ROHC uncompressed) */ +}; + +/* According to: 3GPP TS 44.065, 6.5.4.2 Assignment of PCOMP values for ROHC */ +enum gprs_sndcp_pcomp_rohc_pcomp { + ROHC_PCOMP1, /* ROHC small CIDs */ + ROHC_PCOMP2, /* ROHC large CIDs */ + ROHC_PCOMP_NUM /* Number of pcomp values */ +}; + +/* ROHC compression profiles, see also: + http://www.iana.org/assignments/rohc-pro-ids/rohc-pro-ids.xhtml */ +enum gprs_sndcp_xid_rohc_profiles { + ROHC_UNCOMPRESSED = 0x0000, /* ROHC uncompressed [RFC5795] */ + ROHC_RTP = 0x0001, /* ROHC RTP [RFC3095] */ + ROHCV2_RTP = 0x0101, /* ROHCv2 RTP [RFC5225] */ + ROHC_UDP = 0x0002, /* ROHC UDP [RFC3095] */ + ROHCv2_UDP = 0x0102, /* ROHCv2 UDP [RFC5225] */ + ROHC_ESP = 0x0003, /* ROHC ESP [RFC3095] */ + ROHCV2_ESP = 0x0103, /* ROHCv2 ESP [RFC5225] */ + ROHC_IP = 0x0004, /* ROHC IP [RFC3843] */ + ROHCV2_IP = 0x0104, /* ROHCv2 IP [RFC5225] */ + ROHC_LLA = 0x0005, /* ROHC LLA [RFC4362] */ + ROHC_LLA_WITH_R_MODE = 0x0105, /* ROHC LLA with R-mode [RFC3408] */ + ROHC_TCP = 0x0006, /* ROHC TCP [RFC6846] */ + ROHC_RTP_UDP_LITE = 0x0007, /* ROHC RTP/UDP-Lite [RFC4019] */ + ROHCV2_RTP_UDP_LITE = 0x0107, /* ROHCv2 RTP/UDP-Lite [RFC5225] */ + ROHC_UDP_LITE = 0x0008, /* ROHC UDP-Lite [RFC4019] */ + ROHCV2_UDP_LITE = 0x0108, /* ROHCv2 UDP-Lite [RFC5225] */ +}; + +/* According to: 3GPP TS 44.065, 6.6.2.1 Parameters (Table 7a) */ +struct gprs_sndcp_dcomp_v42bis_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int p0; /* (default 3) */ + int p1; /* (default 2048) */ + int p2; /* (default 20) */ + +}; + +/* According to: 3GPP TS 44.065, 6.6.2.2 Assignment of DCOMP values */ +enum gprs_sndcp_dcomp_v42bis_dcomp { + V42BIS_DCOMP1, /* V.42bis enabled */ + V42BIS_DCOMP_NUM /* Number of dcomp values */ +}; + +/* According to: 3GPP TS 44.065, 6.6.3.1 Parameters (Table 7c) */ +struct gprs_sndcp_dcomp_v44_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int c0; /* (default 10000000) */ + int p0; /* (default 3) */ + int p1t; /* Refer to subclause 6.6.3.1.4 */ + int p1r; /* Refer to subclause 6.6.3.1.5 */ + int p3t; /* (default 3 x p1t) */ + int p3r; /* (default 3 x p1r) */ +}; + +/* According to: 3GPP TS 44.065, 6.6.3.2 Assignment of DCOMP values */ +enum gprs_sndcp_dcomp_v44_dcomp { + V44_DCOMP1, /* Packet method compressed */ + V44_DCOMP2, /* Multi packet method compressed */ + V44_DCOMP_NUM /* Number of dcomp values */ +}; + +/* Transform a list with compression fields into an SNDCP-XID message (dst) */ +int gprs_sndcp_compile_xid(uint8_t *dst, unsigned int dst_maxlen, + const struct llist_head *comp_fields); + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +struct llist_head *gprs_sndcp_parse_xid(const void *ctx, + const uint8_t * src, + unsigned int src_len, + const struct llist_head *comp_fields_req); + +/* Free a list with SNDCP-XID fields */ +struct llist_head *gprs_sndcp_free_comp_fields(struct llist_head *comp_fields); + +/* Find out to which compression class the specified comp-field belongs + * (header compression or data compression?) */ +int gprs_sndcp_get_compression_class( + const struct gprs_sndcp_comp_field *comp_field); + +/* Dump a list with SNDCP-XID fields (Debug) */ +void gprs_sndcp_dump_comp_fields(const struct llist_head *comp_fields, + unsigned int logl); + +#endif diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 1b6de46..fa4a3dd 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -26,11 +26,11 @@ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ - oap.c oap_messages.c gprs_llc_xid.c + oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ - $(LIBCRYPTO_LIBS) -lrt + $(LIBCRYPTO_LIBS) -lrt -lm osmo_gtphub_SOURCES = gtphub_main.c gtphub.c gtphub_sock.c gtphub_ares.c \ gtphub_vty.c sgsn_ares.c gprs_utils.c diff --git a/openbsc/src/gprs/gprs_sndcp_xid.c b/openbsc/src/gprs/gprs_sndcp_xid.c new file mode 100644 index 0000000..fd2a692 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_xid.c @@ -0,0 +1,1872 @@ +/* GPRS SNDCP XID field encoding/decoding as per 3GPP TS 44.065 */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* When the propose bit in an SNDCP-XID compression field is set to zero, + * the algorithm identifier is stripped. The algoritm parameters are specific + * for each algorithms. The following struct is used to pass the information + * about the referenced algorithm to the parser. */ +struct entity_algo_table { + unsigned int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + unsigned int algo; /* see also: 6.5.1.1.4 and 6.6.1.1.4 */ + unsigned int compclass; /* Can be either SNDCP_XID_DATA_COMPRESSION or + SNDCP_XID_PROTOCOL_COMPRESSION */ +}; + +/* FUNCTIONS RELATED TO SNDCP-XID ENCODING */ + +/* Encode applicable sapis (works the same in all three compression schemes) */ +static int encode_pcomp_applicable_sapis(uint8_t *dst, + const unsigned int *nsapis, + unsigned int nsapis_len) +{ + /* NOTE: Buffer *dst needs offer at 2 bytes + * of space to store the generation results */ + + uint16_t blob; + unsigned int nsapi; + int i; + + OSMO_ASSERT(dst); + OSMO_ASSERT(nsapis); + + /* Bail if number of possible nsapis exceeds valid range + * (Only 11 nsapis possible for PDP-Contexts) */ + OSMO_ASSERT(nsapis_len <= 11); + + /* Encode applicable SAPIs */ + blob = 0; + for (i = 0; i < nsapis_len; i++) { + nsapi = nsapis[i]; + /* Only NSAPI 5 to 15 are applicable for user traffic (PDP- + * contexts). Only for these NSAPIs SNDCP-XID parameters + * can apply. See also 3GPP TS 44.065, 5.1 Service primitives */ + OSMO_ASSERT(nsapi >= 5 && nsapi <= 15); + blob |= (1 << nsapi); + } + + /* Store result */ + *dst = (blob >> 8) & 0xFF; + dst++; + *dst = blob & 0xFF; + + return 2; +} + +/* Encode rfc1144 parameter field + * (see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */ +static int encode_pcomp_rfc1144_params(uint8_t *dst, unsigned int dst_maxlen, const struct + gprs_sndcp_pcomp_rfc1144_params *params) +{ + /* NOTE: Buffer *dst should offer at least 3 bytes + * of space to store the generation results */ + + int dst_counter = 0; + int rc; + + OSMO_ASSERT(params); + OSMO_ASSERT(dst); + OSMO_ASSERT(dst_maxlen >= 3); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode s01 (see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */ + OSMO_ASSERT(params->s01 >= 0); + OSMO_ASSERT(params->s01 <= 255); + *dst = params->s01; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + +/* + * Encode rfc2507 parameter field + * (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) + */ +static int encode_pcomp_rfc2507_params(uint8_t *dst, unsigned int dst_maxlen, + const struct + gprs_sndcp_pcomp_rfc2507_params *params) +{ + /* NOTE: Buffer *dst should offer at least 3 bytes + * of space to store the generation results */ + + int dst_counter = 0; + int rc; + + OSMO_ASSERT(params); + OSMO_ASSERT(dst); + OSMO_ASSERT(dst_maxlen >= 9); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode F_MAX_PERIOD (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->f_max_period >= 1); + OSMO_ASSERT(params->f_max_period <= 65535); + *dst = (params->f_max_period >> 8) & 0xFF; + dst++; + dst_counter++; + *dst = (params->f_max_period) & 0xFF; + dst++; + dst_counter++; + + /* Encode F_MAX_TIME (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->f_max_time >= 1); + OSMO_ASSERT(params->f_max_time <= 255); + *dst = params->f_max_time; + dst++; + dst_counter++; + + /* Encode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->max_header >= 60); + OSMO_ASSERT(params->max_header <= 255); + *dst = params->max_header; + dst++; + dst_counter++; + + /* Encode TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->tcp_space >= 3); + OSMO_ASSERT(params->tcp_space <= 255); + *dst = params->tcp_space; + dst++; + dst_counter++; + + /* Encode NON_TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->non_tcp_space >= 3); + OSMO_ASSERT(params->non_tcp_space <= 65535); + *dst = (params->non_tcp_space >> 8) & 0xFF; + dst++; + dst_counter++; + *dst = (params->non_tcp_space) & 0xFF; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + +/* Encode ROHC parameter field + * (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ +static int encode_pcomp_rohc_params(uint8_t *dst, unsigned int dst_maxlen, + const struct gprs_sndcp_pcomp_rohc_params + *params) +{ + /* NOTE: Buffer *dst should offer at least 36 + * (2 * 16 Profiles + 2 * 3 Parameter) bytes + * of memory space to store generation results */ + + int i; + int dst_counter = 0; + int rc; + + OSMO_ASSERT(params); + OSMO_ASSERT(dst); + OSMO_ASSERT(dst_maxlen >= 38); + + /* Bail if number of ROHC profiles exceeds limit + * (ROHC supports only a maximum of 16 different profiles) */ + OSMO_ASSERT(params->profile_len >= 0); + OSMO_ASSERT(params->profile_len <= 16); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode MAX_CID (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + OSMO_ASSERT(params->max_cid >= 0); + OSMO_ASSERT(params->max_cid <= 16383); + *dst = (params->max_cid >> 8) & 0xFF; + dst++; + *dst = params->max_cid & 0xFF; + dst++; + dst_counter += 2; + + /* Encode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + OSMO_ASSERT(params->max_header >= 60); + OSMO_ASSERT(params->max_header <= 255); + *dst = (params->max_header >> 8) & 0xFF; + dst++; + *dst = params->max_header & 0xFF; + dst++; + dst_counter += 2; + + /* Encode ROHC Profiles (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + for (i = 0; i < params->profile_len; i++) { + *dst = (params->profile[i] >> 8) & 0xFF; + dst++; + *dst = params->profile[i] & 0xFF; + dst++; + dst_counter += 2; + } + + /* Return generated length */ + return dst_counter; +} + +/* Encode V.42bis parameter field + * (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ +static int encode_dcomp_v42bis_params(uint8_t *dst, unsigned int dst_maxlen, + const struct + gprs_sndcp_dcomp_v42bis_params *params) +{ + /* NOTE: Buffer *dst should offer at least 6 bytes + * of space to store the generation results */ + + int dst_counter = 0; + int rc; + + OSMO_ASSERT(params); + OSMO_ASSERT(dst); + OSMO_ASSERT(dst_maxlen >= 6); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode P0 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + OSMO_ASSERT(params->p0 >= 0); + OSMO_ASSERT(params->p0 <= 3); + *dst = params->p0 & 0x03; + dst++; + dst_counter++; + + /* Encode P1 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + OSMO_ASSERT(params->p1 >= 512); + OSMO_ASSERT(params->p1 <= 65535); + *dst = (params->p1 >> 8) & 0xFF; + dst++; + *dst = params->p1 & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P2 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + OSMO_ASSERT(params->p2 >= 6); + OSMO_ASSERT(params->p2 <= 250); + *dst = params->p2; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + +/* Encode V44 parameter field + * (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ +static int encode_dcomp_v44_params(uint8_t *dst, unsigned int dst_maxlen, + const struct gprs_sndcp_dcomp_v44_params + *params) +{ + /* NOTE: Buffer *dst should offer at least 12 bytes + * of space to store the generation results */ + + int dst_counter = 0; + int rc; + + OSMO_ASSERT(params); + OSMO_ASSERT(dst); + OSMO_ASSERT(dst_maxlen >= 12); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode C0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->c0 == 0x80 || params->c0 == 0xC0); + *dst = params->c0 & 0xC0; + dst++; + dst_counter++; + + /* Encode P0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p0 >= 0); + OSMO_ASSERT(params->p0 <= 3); + *dst = params->p0 & 0x03; + dst++; + dst_counter++; + + /* Encode P1T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p1t >= 256); + OSMO_ASSERT(params->p1t <= 65535); + *dst = (params->p1t >> 8) & 0xFF; + dst++; + *dst = params->p1t & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P1R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p1r >= 256); + OSMO_ASSERT(params->p1r <= 65535); + *dst = (params->p1r >> 8) & 0xFF; + dst++; + *dst = params->p1r & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P3T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p3t >= 0); + OSMO_ASSERT(params->p3t <= 65535); + OSMO_ASSERT(params->p3t >= 2 * params->p1t); + *dst = (params->p3t >> 8) & 0xFF; + dst++; + *dst = params->p3t & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P3R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p3r >= 0); + OSMO_ASSERT(params->p3r <= 65535); + OSMO_ASSERT(params->p3r >= 2 * params->p1r); + *dst = (params->p3r >> 8) & 0xFF; + dst++; + *dst = params->p3r & 0xFF; + dst++; + dst_counter += 2; + + /* Return generated length */ + return dst_counter; +} + +/* Encode data or protocol control information compression field + * (see also: 3GPP TS 44.065, 6.6.1.1, Figure 9 and + * 3GPP TS 44.065, 6.5.1.1, Figure 7) */ +static int encode_comp_field(uint8_t *dst, unsigned int dst_maxlen, + const struct gprs_sndcp_comp_field *comp_field) +{ + int dst_counter = 0; + int len; + int expected_length; + int i; + + OSMO_ASSERT(dst); + OSMO_ASSERT(comp_field); + + uint8_t payload_bytes[256]; + int payload_bytes_len = -1; + + /* If possible, try do encode payload bytes first */ + if (comp_field->rfc1144_params) { + payload_bytes_len = + encode_pcomp_rfc1144_params(payload_bytes, + sizeof(payload_bytes), + comp_field->rfc1144_params); + } else if (comp_field->rfc2507_params) { + payload_bytes_len = + encode_pcomp_rfc2507_params(payload_bytes, + sizeof(payload_bytes), + comp_field->rfc2507_params); + } else if (comp_field->rohc_params) { + payload_bytes_len = + encode_pcomp_rohc_params(payload_bytes, + sizeof(payload_bytes), + comp_field->rohc_params); + } else if (comp_field->v42bis_params) { + payload_bytes_len = + encode_dcomp_v42bis_params(payload_bytes, + sizeof(payload_bytes), + comp_field->v42bis_params); + } else if (comp_field->v44_params) { + payload_bytes_len = + encode_dcomp_v44_params(payload_bytes, + sizeof(payload_bytes), + comp_field->v44_params); + } else + OSMO_ASSERT(false); + + /* Bail immediately if payload byte generation failed */ + OSMO_ASSERT(payload_bytes_len >= 0); + + /* Bail if comp_len is out of bounds */ + OSMO_ASSERT(comp_field->comp_len <= sizeof(comp_field->comp)); + + /* Calculate length field of the data block */ + if (comp_field->p) { + len = + payload_bytes_len + + ceil((double)(comp_field->comp_len) / 2.0); + expected_length = len + 3; + } else { + len = payload_bytes_len; + expected_length = len + 2; + } + + /* Bail immediately if no sufficient memory space is supplied */ + OSMO_ASSERT(dst_maxlen >= expected_length); + + /* Check if the entity number is within bounds */ + OSMO_ASSERT(comp_field->entity <= 0x1f); + + /* Check if the algorithm number is within bounds */ + OSMO_ASSERT(comp_field->algo >= 0 || comp_field->algo <= 0x1f); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode Propose bit */ + if (comp_field->p) + *dst |= (1 << 7); + + /* Encode entity number */ + *dst |= comp_field->entity & 0x1F; + dst++; + dst_counter++; + + /* Encode algorithm number */ + if (comp_field->p) { + *dst |= comp_field->algo & 0x1F; + dst++; + dst_counter++; + } + + /* Encode length field */ + *dst |= len & 0xFF; + dst++; + dst_counter++; + + /* Encode PCOMP/DCOMP values */ + if (comp_field->p) { + for (i = 0; i < comp_field->comp_len; i++) { + /* Check if submitted PCOMP/DCOMP + values are within bounds */ + if ((comp_field->comp[i] < 0) + || (comp_field->comp[i] > 0x0F)) + return -EINVAL; + + if (i & 1) { + *dst |= comp_field->comp[i] & 0x0F; + dst++; + dst_counter++; + } else + *dst |= (comp_field->comp[i] << 4) & 0xF0; + } + + if (i & 1) { + dst++; + dst_counter++; + } + } + + /* Append payload bytes */ + memcpy(dst, payload_bytes, payload_bytes_len); + dst_counter += payload_bytes_len; + + /* Return generated length */ + return dst_counter; +} + +/* Find out to which compression class the specified comp-field belongs + * (header compression or data compression?) */ +int gprs_sndcp_get_compression_class(const struct gprs_sndcp_comp_field + *comp_field) +{ + OSMO_ASSERT(comp_field); + + if (comp_field->rfc1144_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->rfc2507_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->rohc_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->v42bis_params) + return SNDCP_XID_DATA_COMPRESSION; + else if (comp_field->v44_params) + return SNDCP_XID_DATA_COMPRESSION; + else + return -EINVAL; +} + +/* Convert all compression fields to bytstreams */ +static int gprs_sndcp_pack_fields(const struct llist_head *comp_fields, + uint8_t *dst, + unsigned int dst_maxlen, int class) +{ + struct gprs_sndcp_comp_field *comp_field; + int byte_counter = 0; + int rc; + + OSMO_ASSERT(comp_fields); + OSMO_ASSERT(dst); + + llist_for_each_entry_reverse(comp_field, comp_fields, list) { + if (class == gprs_sndcp_get_compression_class(comp_field)) { + rc = encode_comp_field(dst + byte_counter, + dst_maxlen - byte_counter, + comp_field); + + /* When input data is correct, there is + * no reason for the encoder to fail! */ + OSMO_ASSERT(rc >= 0); + + byte_counter += rc; + } + } + + /* Return generated length */ + return byte_counter; +} + +/* Transform a list with compression fields into an SNDCP-XID message (dst) */ +int gprs_sndcp_compile_xid(uint8_t *dst, unsigned int dst_maxlen, + const struct llist_head *comp_fields) +{ + int rc; + int byte_counter = 0; + uint8_t comp_bytes[512]; + uint8_t xid_version_number[1] = { CURRENT_SNDCP_VERSION }; + + OSMO_ASSERT(comp_fields); + OSMO_ASSERT(dst); + + /* Exit immediately if no sufficient memory space is supplied */ + OSMO_ASSERT(dst_maxlen >= 2 + sizeof(xid_version_number)); + + /* Prepend header */ + dst = + tlv_put(dst, SNDCP_XID_VERSION_NUMBER, + sizeof(xid_version_number), xid_version_number); + byte_counter += (sizeof(xid_version_number) + 2); + + /* Add data compression fields */ + rc = gprs_sndcp_pack_fields(comp_fields, comp_bytes, + sizeof(comp_bytes), + SNDCP_XID_DATA_COMPRESSION); + OSMO_ASSERT(rc >= 0); + + if (rc > 0) { + dst = tlv_put(dst, SNDCP_XID_DATA_COMPRESSION, rc, comp_bytes); + byte_counter += rc + 2; + } + + /* Add header compression fields */ + rc = gprs_sndcp_pack_fields(comp_fields, comp_bytes, + sizeof(comp_bytes), + SNDCP_XID_PROTOCOL_COMPRESSION); + OSMO_ASSERT(rc >= 0); + + if (rc > 0) { + dst = tlv_put(dst, SNDCP_XID_PROTOCOL_COMPRESSION, rc, + comp_bytes); + byte_counter += rc + 2; + } + + /* Return generated length */ + return byte_counter; +} + +/* FUNCTIONS RELATED TO SNDCP-XID DECODING */ + +/* Decode applicable sapis (works the same in all three compression schemes) */ +static int decode_pcomp_applicable_sapis(unsigned int *nsapis, + unsigned int *nsapis_len, + const uint8_t *src, + unsigned int src_len) +{ + uint16_t blob; + int i; + int nsapi_len = 0; + + OSMO_ASSERT(src); + + /* Exit immediately if no result can be stored */ + if (!nsapis) + return -EINVAL; + + /* Exit immediately if not enough input data is available */ + if (src_len < 2) + return -EINVAL; + + /* Read bitmask */ + blob = *src; + blob = (blob << 8) & 0xFF00; + src++; + blob |= (*src) & 0xFF; + blob = (blob >> 5); + + /* Decode applicable SAPIs */ + for (i = 0; i < 15; i++) { + if ((blob >> i) & 1) { + nsapis[nsapi_len] = i + 5; + nsapi_len++; + } + } + + /* Return consumed length */ + *nsapis_len = nsapi_len; + return 2; +} + +/* Decode 16 bit field */ +static int decode_pcomp_16_bit_field(int *value_int, uint16_t * value_uint16, + const uint8_t *src, + unsigned int src_len, + int value_min, int value_max) +{ + uint16_t blob; + + OSMO_ASSERT(src); + + /* Reset values to zero (just to be sure) */ + if (value_int) + *value_int = -1; + if (value_uint16) + *value_uint16 = 0; + + /* Exit if not enough src are available */ + if (src_len < 2) + return -EINVAL; + + /* Decode bit value */ + blob = *src; + blob = (blob << 8) & 0xFF00; + src++; + blob |= *src; + + /* Check if parsed value is within bounds */ + if (blob < value_min) + return -EINVAL; + if (blob > value_max) + return -EINVAL; + + /* Hand back results to the caller */ + if (value_int) + *value_int = blob; + if (value_uint16) + *value_uint16 = blob; + + /* Return consumed length */ + return 2; +} + +/* Decode 8 bit field */ +static int decode_pcomp_8_bit_field(int *value_int, uint8_t *value_uint8, + const uint8_t *src, + unsigned int src_len, + int value_min, int value_max) +{ + uint8_t blob; + + OSMO_ASSERT(src); + + /* Reset values to invalid (just to be sure) */ + if (value_int) + *value_int = -1; + if (value_uint8) + *value_uint8 = 0; + + /* Exit if not enough src are available */ + if (src_len < 1) + return -EINVAL; + + /* Decode bit value */ + blob = *src; + + /* Check if parsed value is within bounds */ + if (blob < value_min) + return -EINVAL; + if (blob > value_max) + return -EINVAL; + + /* Hand back results to the caller */ + if (value_int) + *value_int = blob; + if (value_uint8) + *value_uint8 = blob; + + /* Return consumed length */ + return 1; +} + +/* Decode rfc1144 parameter field see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */ +static int decode_pcomp_rfc1144_params(struct gprs_sndcp_pcomp_rfc1144_params + *params, const uint8_t *src, + unsigned int src_len) +{ + int rc; + int byte_counter = 0; + + OSMO_ASSERT(params); + OSMO_ASSERT(src); + + /* Mark all optional parameters invalid by default */ + params->s01 = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode parameter S0 -1 + * (see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */ + rc = decode_pcomp_8_bit_field(¶ms->s01, NULL, src, + src_len - byte_counter, 0, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Decode rfc2507 parameter field + * (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ +static int decode_pcomp_rfc2507_params(struct gprs_sndcp_pcomp_rfc2507_params + *params, const uint8_t *src, + unsigned int src_len) +{ + int rc; + int byte_counter = 0; + + OSMO_ASSERT(params); + OSMO_ASSERT(src); + + /* Mark all optional parameters invalid by default */ + params->f_max_period = -1; + params->f_max_time = -1; + params->max_header = -1; + params->tcp_space = -1; + params->non_tcp_space = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode F_MAX_PERIOD (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_16_bit_field(¶ms->f_max_period, NULL, src, + src_len - byte_counter, 1, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode F_MAX_TIME (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_8_bit_field(¶ms->f_max_time, NULL, src, + src_len - byte_counter, 1, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_8_bit_field(¶ms->max_header, NULL, src, + src_len - byte_counter, 60, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_8_bit_field(¶ms->tcp_space, NULL, src, + src_len - byte_counter, 3, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode NON_TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_16_bit_field(¶ms->non_tcp_space, NULL, src, + src_len - byte_counter, 3, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Decode ROHC parameter field (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ +static int decode_pcomp_rohc_params(struct gprs_sndcp_pcomp_rohc_params *params, + const uint8_t *src, unsigned int src_len) +{ + int rc; + int byte_counter = 0; + int i; + + OSMO_ASSERT(params); + OSMO_ASSERT(src); + + /* Mark all optional parameters invalid by default */ + params->max_cid = -1; + params->max_header = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_CID (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + rc = decode_pcomp_16_bit_field(¶ms->max_cid, NULL, src, + src_len - byte_counter, 0, 16383); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + rc = decode_pcomp_16_bit_field(¶ms->max_header, NULL, src, + src_len - byte_counter, 60, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode Profiles (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + for (i = 0; i < 16; i++) { + params->profile_len = 0; + rc = decode_pcomp_16_bit_field(NULL, ¶ms->profile[i], src, + src_len - byte_counter, 0, + 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + params->profile_len = i + 1; + } + + /* Return consumed length */ + return byte_counter; +} + +/* Decode V.42bis parameter field + * (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ +static int decode_dcomp_v42bis_params(struct gprs_sndcp_dcomp_v42bis_params + *params, const uint8_t *src, + unsigned int src_len) +{ + int rc; + int byte_counter = 0; + + OSMO_ASSERT(params); + OSMO_ASSERT(src); + + /* Mark all optional parameters invalid by default */ + params->p0 = -1; + params->p1 = -1; + params->p2 = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode P0 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + rc = decode_pcomp_8_bit_field(¶ms->p0, NULL, src, + src_len - byte_counter, 0, 3); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + rc = decode_pcomp_16_bit_field(¶ms->p1, NULL, src, + src_len - byte_counter, 512, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P2 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + rc = decode_pcomp_8_bit_field(¶ms->p2, NULL, src, + src_len - byte_counter, 6, 250); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Decode V44 parameter field (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ +static int decode_dcomp_v44_params(struct gprs_sndcp_dcomp_v44_params *params, + const uint8_t *src, unsigned int src_len) +{ + int rc; + int byte_counter = 0; + + OSMO_ASSERT(params); + OSMO_ASSERT(src); + + /* Mark all optional parameters invalid by default */ + params->c0 = -1; + params->p0 = -1; + params->p1t = -1; + params->p1r = -1; + params->p3t = -1; + params->p3r = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode C0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_8_bit_field(¶ms->c0, NULL, src, + src_len - byte_counter, 0, 255); + if (rc <= 0) + return byte_counter; + if ((params->c0 != 0x80) && (params->c0 != 0xC0)) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Decode P0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_8_bit_field(¶ms->p0, NULL, src, + src_len - byte_counter, 0, 3); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_16_bit_field(¶ms->p1t, NULL, src, + src_len - byte_counter, 265, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_16_bit_field(¶ms->p1r, NULL, src, + src_len - byte_counter, 265, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P3T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_16_bit_field(¶ms->p3t, NULL, src, + src_len - byte_counter, 265, 65535); + if (rc <= 0) + return byte_counter; + if (params->p3t < 2 * params->p1t) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Decode P3R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_16_bit_field(¶ms->p3r, NULL, src, + src_len - byte_counter, 265, 65535); + if (rc <= 0) + return byte_counter; + if (params->p3r < 2 * params->p1r) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Lookup algorithm identfier by entity ID */ +static int lookup_algorithm_identifier(int entity, const struct + entity_algo_table + *lt, unsigned int lt_len, int compclass) +{ + int i; + + if (!lt) + return -1; + + for (i = 0; i < lt_len; i++) { + if ((lt[i].entity == entity) + && (lt[i].compclass == compclass)) + return lt[i].algo; + } + + return -1; +} + +/* Helper function for decode_comp_field(), decodes + * numeric pcomp/dcomp values */ +static int decode_comp_values(struct gprs_sndcp_comp_field *comp_field, + const uint8_t *src, int compclass) +{ + int src_counter = 0; + int i; + + OSMO_ASSERT(comp_field); + OSMO_ASSERT(src); + + if (comp_field->p) { + /* Determine the number of expected PCOMP/DCOMP values */ + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + /* For protocol compression */ + switch (comp_field->algo) { + case RFC_1144: + comp_field->comp_len = RFC1144_PCOMP_NUM; + break; + case RFC_2507: + comp_field->comp_len = RFC2507_PCOMP_NUM; + break; + case ROHC: + comp_field->comp_len = ROHC_PCOMP_NUM; + break; + + /* Exit if the algorithem type encodes + something unknown / unspecified */ + default: + return -EINVAL; + } + } else { + /* For data compression */ + switch (comp_field->algo) { + case V42BIS: + comp_field->comp_len = V42BIS_DCOMP_NUM; + break; + case V44: + comp_field->comp_len = V44_DCOMP_NUM; + break; + + /* Exit if the algorithem type encodes + something unknown / unspecified */ + default: + return -EINVAL; + } + } + + for (i = 0; i < comp_field->comp_len; i++) { + if (i & 1) { + comp_field->comp[i] = (*src) & 0x0F; + src++; + src_counter++; + } else + comp_field->comp[i] = ((*src) >> 4) & 0x0F; + } + + if (i & 1) { + src++; + src_counter++; + } + } + + return src_counter; +} + +/* Helper function for decode_comp_field(), decodes the parameters + * which are protocol compression specific */ +static int decode_pcomp_params(struct gprs_sndcp_comp_field *comp_field, + const uint8_t *src, int src_len) +{ + int rc; + + OSMO_ASSERT(comp_field); + OSMO_ASSERT(src); + + switch (comp_field->algo) { + case RFC_1144: + comp_field->rfc1144_params = talloc_zero(comp_field, struct + gprs_sndcp_pcomp_rfc1144_params); + rc = decode_pcomp_rfc1144_params(comp_field->rfc1144_params, + src, src_len); + if (rc < 0) + talloc_free(comp_field->rfc1144_params); + break; + case RFC_2507: + comp_field->rfc2507_params = talloc_zero(comp_field, struct + gprs_sndcp_pcomp_rfc2507_params); + rc = decode_pcomp_rfc2507_params(comp_field->rfc2507_params, + src, src_len); + if (rc < 0) + talloc_free(comp_field->rfc1144_params); + break; + case ROHC: + comp_field->rohc_params = talloc_zero(comp_field, struct + gprs_sndcp_pcomp_rohc_params); + rc = decode_pcomp_rohc_params(comp_field->rohc_params, src, + src_len); + if (rc < 0) + talloc_free(comp_field->rohc_params); + break; + + /* If no suitable decoder is detected, + leave the remaining bytes undecoded */ + default: + rc = src_len; + } + + if (rc < 0) { + comp_field->rfc1144_params = NULL; + comp_field->rfc2507_params = NULL; + comp_field->rohc_params = NULL; + } + + return rc; +} + +/* Helper function for decode_comp_field(), decodes the parameters + * which are data compression specific */ +static int decode_dcomp_params(struct gprs_sndcp_comp_field *comp_field, + const uint8_t *src, int src_len) +{ + int rc; + + OSMO_ASSERT(comp_field); + OSMO_ASSERT(src); + + switch (comp_field->algo) { + case V42BIS: + comp_field->v42bis_params = talloc_zero(comp_field, struct + gprs_sndcp_dcomp_v42bis_params); + rc = decode_dcomp_v42bis_params(comp_field->v42bis_params, src, + src_len); + if (rc < 0) + talloc_free(comp_field->v42bis_params); + break; + case V44: + comp_field->v44_params = talloc_zero(comp_field, struct + gprs_sndcp_dcomp_v44_params); + rc = decode_dcomp_v44_params(comp_field->v44_params, src, + src_len); + if (rc < 0) + talloc_free(comp_field->v44_params); + break; + + /* If no suitable decoder is detected, + * leave the remaining bytes undecoded */ + default: + rc = src_len; + } + + if (rc < 0) { + comp_field->v42bis_params = NULL; + comp_field->v44_params = NULL; + } + + return rc; +} + +/* Decode data or protocol control information compression field + * (see also: 3GPP TS 44.065, 6.6.1.1, Figure 9 and + * 3GPP TS 44.065, 6.5.1.1, Figure 7) */ +static int decode_comp_field(struct gprs_sndcp_comp_field *comp_field, + const uint8_t *src, unsigned int src_len, + const struct entity_algo_table *lt, + unsigned int lt_len, int compclass) +{ + int src_counter = 0; + unsigned int len; + int rc; + + OSMO_ASSERT(comp_field); + + /* Exit immediately if it is clear that no + parseable data is present */ + if (src_len < 1 || !src) + return -EINVAL; + + /* Zero out target struct */ + memset(comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + + /* Decode Propose bit and Entity number */ + if ((*src) & 0x80) + comp_field->p = 1; + comp_field->entity = (*src) & 0x1F; + src_counter++; + src++; + + /* Decode algorithm number (if present) */ + if (comp_field->p) { + comp_field->algo = (*src) & 0x1F; + src_counter++; + src++; + } + /* Alternatively take the information from the lookup table */ + else + comp_field->algo = + lookup_algorithm_identifier(comp_field->entity, lt, + lt_len, compclass); + + /* Decode length field */ + len = *src; + src_counter++; + src++; + + /* Decode PCOMP/DCOMP values */ + rc = decode_comp_values(comp_field, src, compclass); + if (rc < 0) + return -EINVAL; + src_counter += rc; + src += rc; + len -= rc; + + /* Decode algorithm specific payload data */ + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + rc = decode_pcomp_params(comp_field, src, len); + else if (compclass == SNDCP_XID_DATA_COMPRESSION) + rc = decode_dcomp_params(comp_field, src, len); + else + return -EINVAL; + + if (rc >= 0) + src_counter += rc; + else + return -EINVAL; + + /* Return consumed length */ + return src_counter; +} + +/* Helper function for gprs_sndcp_decode_xid() to decode XID blocks */ +static int decode_xid_block(struct llist_head *comp_fields, uint8_t tag, + uint16_t tag_len, const uint8_t *val, + const struct entity_algo_table *lt, + unsigned int lt_len) +{ + struct gprs_sndcp_comp_field *comp_field; + int byte_counter = 0; + int comp_field_count = 0; + int rc; + + OSMO_ASSERT(comp_fields); + OSMO_ASSERT(val); + + byte_counter = 0; + do { + /* Bail if more than the maximum number of + comp_fields is generated */ + if (comp_field_count > MAX_ENTITIES * 2) { + return -EINVAL; + } + + /* Parse and add comp_field */ + comp_field = + talloc_zero(comp_fields, struct gprs_sndcp_comp_field); + + rc = decode_comp_field(comp_field, val + byte_counter, + tag_len - byte_counter, lt, lt_len, tag); + + if (rc < 0) { + talloc_free(comp_field); + return -EINVAL; + } + + byte_counter += rc; + llist_add(&comp_field->list, comp_fields); + comp_field_count++; + } + while (tag_len - byte_counter > 0); + + return byte_counter; +} + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +static int gprs_sndcp_decode_xid(struct llist_head *comp_fields, + const uint8_t *src, unsigned int src_len, + const struct + entity_algo_table + *lt, unsigned int lt_len) +{ + int src_pos = 0; + uint8_t tag; + uint16_t tag_len; + const uint8_t *val; + int byte_counter = 0; + int rc; + int tlv_count = 0; + + OSMO_ASSERT(comp_fields); + OSMO_ASSERT(src); + + /* Valid TLV-Tag and types */ + static const struct tlv_definition sndcp_xid_def = { + .def = { + [SNDCP_XID_VERSION_NUMBER] = {TLV_TYPE_TLV,}, + [SNDCP_XID_DATA_COMPRESSION] = {TLV_TYPE_TLV,}, + [SNDCP_XID_PROTOCOL_COMPRESSION] = {TLV_TYPE_TLV,}, + }, + }; + + /* Parse TLV-Encoded SNDCP-XID message and defer payload + to the apporpiate sub-parser functions */ + while (1) { + + /* Bail if an the maximum number of TLV fields + * have been parsed */ + if (tlv_count >= 3) { + gprs_sndcp_free_comp_fields(comp_fields); + return -EINVAL; + } + + /* Parse TLV field */ + rc = tlv_parse_one(&tag, &tag_len, &val, &sndcp_xid_def, + src + src_pos, src_len - src_pos); + if (rc > 0) + src_pos += rc; + else { + gprs_sndcp_free_comp_fields(comp_fields); + return -EINVAL; + } + + /* Decode compression parameters */ + if ((tag == SNDCP_XID_PROTOCOL_COMPRESSION) + || (tag == SNDCP_XID_DATA_COMPRESSION)) { + rc = decode_xid_block(comp_fields, tag, tag_len, val, + lt, lt_len); + + if (rc < 0) { + gprs_sndcp_free_comp_fields(comp_fields); + return -EINVAL; + } else + byte_counter += rc; + } + + /* Stop when no further TLV elements can be expected */ + if (src_len - src_pos <= 2) + break; + + tlv_count++; + } + + return 0; +} + +/* Fill up lookutable from a list with comression entitiy fields */ +static int gprs_sndcp_fill_table(struct + entity_algo_table *lt, + unsigned int lt_len, + const struct llist_head *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field; + int i = 0; + + OSMO_ASSERT(lt); + OSMO_ASSERT(comp_fields); + + if (!comp_fields) + return -EINVAL; + if (!lt) + return -EINVAL; + + memset(lt, 0, lt_len * sizeof(lt)); + + llist_for_each_entry(comp_field, comp_fields, list) { + + lt[i].entity = comp_field->entity; + lt[i].algo = comp_field->algo; + lt[i].compclass = gprs_sndcp_get_compression_class(comp_field); + + if (lt[i].compclass < 0) { + memset(lt, 0, lt_len * sizeof(lt)); + return -EINVAL; + } + + i++; + } + + return i; +} + +/* Complete comp field params + * (if a param (dst) is not valid, it will be copied from source (src) */ +static int complete_comp_field_params(struct gprs_sndcp_comp_field + *comp_field_dst, const struct + gprs_sndcp_comp_field *comp_field_src) +{ + OSMO_ASSERT(comp_field_dst); + OSMO_ASSERT(comp_field_src); + + if (comp_field_dst->algo < 0) + return -EINVAL; + + if (comp_field_dst->rfc1144_params && comp_field_src->rfc1144_params) { + if (comp_field_dst->rfc1144_params->s01 < 0) { + comp_field_dst->rfc1144_params->s01 = + comp_field_src->rfc1144_params->s01; + } + return 0; + } + + if (comp_field_dst->rfc2507_params && comp_field_src->rfc2507_params) { + + if (comp_field_dst->rfc2507_params->f_max_period < 0) { + comp_field_dst->rfc2507_params->f_max_period = + comp_field_src->rfc2507_params->f_max_period; + } + if (comp_field_dst->rfc2507_params->f_max_time < 0) { + comp_field_dst->rfc2507_params->f_max_time = + comp_field_src->rfc2507_params->f_max_time; + } + if (comp_field_dst->rfc2507_params->max_header < 0) { + comp_field_dst->rfc2507_params->max_header = + comp_field_src->rfc2507_params->max_header; + } + if (comp_field_dst->rfc2507_params->tcp_space < 0) { + comp_field_dst->rfc2507_params->tcp_space = + comp_field_src->rfc2507_params->tcp_space; + } + if (comp_field_dst->rfc2507_params->non_tcp_space < 0) { + comp_field_dst->rfc2507_params->non_tcp_space = + comp_field_src->rfc2507_params->non_tcp_space; + } + return 0; + } + + if (comp_field_dst->rohc_params && comp_field_src->rohc_params) { + if (comp_field_dst->rohc_params->max_cid < 0) { + comp_field_dst->rohc_params->max_cid = + comp_field_src->rohc_params->max_cid; + } + if (comp_field_dst->rohc_params->max_header < 0) { + comp_field_dst->rohc_params->max_header = + comp_field_src->rohc_params->max_header; + } + if (comp_field_dst->rohc_params->profile_len > 0) { + memcpy(comp_field_dst->rohc_params->profile, + comp_field_src->rohc_params->profile, + sizeof(comp_field_dst->rohc_params->profile)); + comp_field_dst->rohc_params->profile_len = + comp_field_src->rohc_params->profile_len; + } + + return 0; + } + + if (comp_field_dst->v42bis_params && comp_field_src->v42bis_params) { + if (comp_field_dst->v42bis_params->p0 < 0) { + comp_field_dst->v42bis_params->p0 = + comp_field_src->v42bis_params->p0; + } + if (comp_field_dst->v42bis_params->p1 < 0) { + comp_field_dst->v42bis_params->p1 = + comp_field_src->v42bis_params->p1; + } + if (comp_field_dst->v42bis_params->p2 < 0) { + comp_field_dst->v42bis_params->p2 = + comp_field_src->v42bis_params->p2; + } + return 0; + } + + if (comp_field_dst->v44_params && comp_field_src->v44_params) { + if (comp_field_dst->v44_params->c0 < 0) { + comp_field_dst->v44_params->c0 = + comp_field_src->v44_params->c0; + } + if (comp_field_dst->v44_params->p0 < 0) { + comp_field_dst->v44_params->p0 = + comp_field_src->v44_params->p0; + } + if (comp_field_dst->v44_params->p1t < 0) { + comp_field_dst->v44_params->p1t = + comp_field_src->v44_params->p1t; + } + if (comp_field_dst->v44_params->p1r < 0) { + comp_field_dst->v44_params->p1r = + comp_field_src->v44_params->p1r; + } + if (comp_field_dst->v44_params->p3t < 0) { + comp_field_dst->v44_params->p3t = + comp_field_src->v44_params->p3t; + } + if (comp_field_dst->v44_params->p3r < 0) { + comp_field_dst->v44_params->p3r = + comp_field_src->v44_params->p3r; + } + return 0; + } + + /* There should be at least exist one param set + * in the destination struct, otherwise something + * must be wrong! */ + return -EINVAL; +} + +/* Complete missing parameters in a comp_field */ +static int gprs_sndcp_complete_comp_field(struct gprs_sndcp_comp_field + *comp_field, const struct llist_head + *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field_src; + int rc = 0; + + OSMO_ASSERT(comp_field); + OSMO_ASSERT(comp_fields); + + llist_for_each_entry(comp_field_src, comp_fields, list) { + if (comp_field_src->entity == comp_field->entity) { + + /* Complete header fields */ + if (comp_field_src->comp_len > 0) { + memcpy(comp_field->comp, + comp_field_src->comp, + sizeof(comp_field_src->comp)); + comp_field->comp_len = comp_field_src->comp_len; + } + + /* Complete parameter fields */ + rc = complete_comp_field_params(comp_field, + comp_field_src); + } + } + + return rc; +} + +/* Complete missing parameters of all comp_field in a list */ +static int gprs_sndcp_complete_comp_fields(struct llist_head + *comp_fields_incomplete, + const struct llist_head *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field_incomplete; + int rc; + + OSMO_ASSERT(comp_fields_incomplete); + OSMO_ASSERT(comp_fields); + + llist_for_each_entry(comp_field_incomplete, comp_fields_incomplete, + list) { + + rc = gprs_sndcp_complete_comp_field(comp_field_incomplete, + comp_fields); + if (rc < 0) + return -EINVAL; + + } + + return 0; +} + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +struct llist_head *gprs_sndcp_parse_xid(const void *ctx, + const uint8_t *src, + unsigned int src_len, + const struct llist_head + *comp_fields_req) +{ + int rc; + int lt_len; + struct llist_head *comp_fields; + struct entity_algo_table lt[MAX_ENTITIES * 2]; + + OSMO_ASSERT(src); + + comp_fields = talloc_zero(ctx, struct llist_head); + INIT_LLIST_HEAD(comp_fields); + + if (comp_fields_req) { + /* Generate lookup table */ + lt_len = + gprs_sndcp_fill_table(lt, MAX_ENTITIES * 2, + comp_fields_req); + if (lt_len < 0) + return gprs_sndcp_free_comp_fields(comp_fields); + + /* Parse SNDCP-CID XID-Field */ + rc = gprs_sndcp_decode_xid(comp_fields, src, src_len, lt, + lt_len); + if (rc < 0) + return gprs_sndcp_free_comp_fields(comp_fields); + + rc = gprs_sndcp_complete_comp_fields(comp_fields, + comp_fields_req); + if (rc < 0) + return gprs_sndcp_free_comp_fields(comp_fields); + + } else { + /* Parse SNDCP-CID XID-Field */ + rc = gprs_sndcp_decode_xid(comp_fields, src, src_len, NULL, 0); + if (rc < 0) + return gprs_sndcp_free_comp_fields(comp_fields); + } + + return comp_fields; +} + +/* Free a list with SNDCP-XID fields */ +struct llist_head *gprs_sndcp_free_comp_fields(struct llist_head *comp_fields) +{ + if (comp_fields != NULL) + talloc_free(comp_fields); + return NULL; +} + +/* Helper for gprs_sndcp_dump_comp_fields(), + * dumps protocol compression parameters */ +static void dump_pcomp_params(const struct gprs_sndcp_comp_field + *comp_field, unsigned int logl) +{ + int i; + + OSMO_ASSERT(comp_field); + + switch (comp_field->algo) { + case RFC_1144: + if (comp_field->rfc1144_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_pcomp_rfc1144_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_pcomp_rfc1144_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%i;\n", + comp_field->rfc1144_params->nsapi_len); + if (comp_field->rfc1144_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rfc1144_params->nsapi_len; i++) { + LOGP(DSNDCP, logl, + " nsapi[%i]=%i;\n", i, + comp_field->rfc1144_params->nsapi[i]); + } + LOGP(DSNDCP, logl, " s01=%i;\n", + comp_field->rfc1144_params->s01); + LOGP(DSNDCP, logl, " }\n"); + break; + case RFC_2507: + if (comp_field->rfc2507_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_pcomp_rfc2507_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_pcomp_rfc2507_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%i;\n", + comp_field->rfc2507_params->nsapi_len); + if (comp_field->rfc2507_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rfc2507_params->nsapi_len; i++) { + LOGP(DSNDCP, logl, + " nsapi[%i]=%i;\n", i, + comp_field->rfc2507_params->nsapi[i]); + } + LOGP(DSNDCP, logl, + " f_max_period=%i;\n", + comp_field->rfc2507_params->f_max_period); + LOGP(DSNDCP, logl, + " f_max_time=%i;\n", + comp_field->rfc2507_params->f_max_time); + LOGP(DSNDCP, logl, + " max_header=%i;\n", + comp_field->rfc2507_params->max_header); + LOGP(DSNDCP, logl, + " tcp_space=%i;\n", + comp_field->rfc2507_params->tcp_space); + LOGP(DSNDCP, logl, + " non_tcp_space=%i;\n", + comp_field->rfc2507_params->non_tcp_space); + LOGP(DSNDCP, logl, " }\n"); + break; + case ROHC: + if (comp_field->rohc_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_pcomp_rohc_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_pcomp_rohc_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%i;\n", + comp_field->rohc_params->nsapi_len); + if (comp_field->rohc_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rohc_params->nsapi_len; i++) { + LOGP(DSNDCP, logl, + " nsapi[%i]=%i;\n", i, + comp_field->rohc_params->nsapi[i]); + } + LOGP(DSNDCP, logl, + " max_cid=%i;\n", comp_field->rohc_params->max_cid); + LOGP(DSNDCP, logl, + " max_header=%i;\n", + comp_field->rohc_params->max_header); + LOGP(DSNDCP, logl, + " profile_len=%i;\n", + comp_field->rohc_params->profile_len); + if (comp_field->rohc_params->profile_len == 0) + LOGP(DSNDCP, logl, " profile[] = NULL;\n"); + for (i = 0; i < comp_field->rohc_params->profile_len; i++) + LOGP(DSNDCP, logl, + " profile[%i]=%04x;\n", + i, comp_field->rohc_params->profile[i]); + LOGP(DSNDCP, logl, " }\n"); + break; + } + +} + +/* Helper for gprs_sndcp_dump_comp_fields(), + * data protocol compression parameters */ +static void dump_dcomp_params(const struct gprs_sndcp_comp_field + *comp_field, unsigned int logl) +{ + int i; + + OSMO_ASSERT(comp_field); + + switch (comp_field->algo) { + case V42BIS: + if (comp_field->v42bis_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_dcomp_v42bis_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_dcomp_v42bis_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%i;\n", + comp_field->v42bis_params->nsapi_len); + if (comp_field->v42bis_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->v42bis_params->nsapi_len; i++) + LOGP(DSNDCP, logl, + " nsapi[%i]=%i;\n", i, + comp_field->v42bis_params->nsapi[i]); + LOGP(DSNDCP, logl, " p0=%i;\n", + comp_field->v42bis_params->p0); + LOGP(DSNDCP, logl, " p1=%i;\n", + comp_field->v42bis_params->p1); + LOGP(DSNDCP, logl, " p2=%i;\n", + comp_field->v42bis_params->p2); + LOGP(DSNDCP, logl, " }\n"); + break; + case V44: + if (comp_field->v44_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_dcomp_v44_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_dcomp_v44_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%i;\n", + comp_field->v44_params->nsapi_len); + if (comp_field->v44_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->v44_params->nsapi_len; i++) { + LOGP(DSNDCP, logl, + " nsapi[%i]=%i;\n", i, + comp_field->v44_params->nsapi[i]); + } + LOGP(DSNDCP, logl, " c0=%i;\n", + comp_field->v44_params->c0); + LOGP(DSNDCP, logl, " p0=%i;\n", + comp_field->v44_params->p0); + LOGP(DSNDCP, logl, " p1t=%i;\n", + comp_field->v44_params->p1t); + LOGP(DSNDCP, logl, " p1r=%i;\n", + comp_field->v44_params->p1r); + LOGP(DSNDCP, logl, " p3t=%i;\n", + comp_field->v44_params->p3t); + LOGP(DSNDCP, logl, " p3r=%i;\n", + comp_field->v44_params->p3r); + LOGP(DSNDCP, logl, " }\n"); + break; + } +} + +/* Dump a list with SNDCP-XID fields (Debug) */ +void gprs_sndcp_dump_comp_fields(const struct llist_head *comp_fields, + unsigned int logl) +{ + struct gprs_sndcp_comp_field *comp_field; + int i; + int compclass; + + OSMO_ASSERT(comp_fields); + + llist_for_each_entry(comp_field, comp_fields, list) { + LOGP(DSNDCP, logl, "SNDCP-XID:\n"); + LOGP(DSNDCP, logl, "struct gprs_sndcp_comp_field {\n"); + LOGP(DSNDCP, logl, " entity=%i;\n", comp_field->entity); + LOGP(DSNDCP, logl, " algo=%i;\n", comp_field->algo); + LOGP(DSNDCP, logl, " comp_len=%i;\n", comp_field->comp_len); + if (comp_field->comp_len == 0) + LOGP(DSNDCP, logl, " comp[] = NULL;\n"); + for (i = 0; i < comp_field->comp_len; i++) { + LOGP(DSNDCP, logl, " comp[%i]=%i;\n", i, + comp_field->comp[i]); + } + + compclass = gprs_sndcp_get_compression_class(comp_field); + + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + dump_pcomp_params(comp_field, logl); + } else if (compclass == SNDCP_XID_DATA_COMPRESSION) { + dump_dcomp_params(comp_field, logl); + } + + LOGP(DSNDCP, logl, "}\n"); + } + +} diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index ba5ca28..1debb2d 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 74af159..45d1780 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -31,6 +31,7 @@ $(top_builddir)/src/gprs/oap.o \ $(top_builddir)/src/gprs/oap_messages.o \ $(top_builddir)/src/gprs/gprs_llc_xid.o \ + $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ @@ -38,5 +39,5 @@ $(LIBOSMOGB_LIBS) \ $(LIBCARES_LIBS) \ $(LIBCRYPTO_LIBS) \ - -lgtp -lrt + -lgtp -lrt -lm diff --git a/openbsc/tests/sndcp_xid/Makefile.am b/openbsc/tests/sndcp_xid/Makefile.am new file mode 100644 index 0000000..99b9d1a --- /dev/null +++ b/openbsc/tests/sndcp_xid/Makefile.am @@ -0,0 +1,20 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) + +EXTRA_DIST = sndcp_xid_test.ok + +noinst_PROGRAMS = sndcp_xid_test + +sndcp_xid_test_SOURCES = sndcp_xid_test.c + +sndcp_xid_test_LDADD = \ + $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOGB_LIBS) \ + $(LIBCARES_LIBS) \ + $(LIBCRYPTO_LIBS) \ + -lgtp -lrt -lm + + diff --git a/openbsc/tests/sndcp_xid/sndcp_xid_test.c b/openbsc/tests/sndcp_xid/sndcp_xid_test.c new file mode 100644 index 0000000..59ff968 --- /dev/null +++ b/openbsc/tests/sndcp_xid/sndcp_xid_test.c @@ -0,0 +1,283 @@ +/* Test SNDCP-XID Encoding/Decoding */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include + +#include +#include + +#include + +#include +#include + +/* Test SNDCP-XID decoding with a real world sample */ +static void test_xid_decode_realworld(const void *ctx) +{ + struct llist_head *comp_fields; + int rc; + printf("Testing SNDCP XID-Decoder/Encoder (real world data)\n"); + + /* Example of a real world SNDCP-XID message */ + uint8_t xid[] = + { 0x00, 0x01, 0x00, 0x02, 0x31, 0x82, 0x02, 0x27, 0x89, 0xff, 0xe0, + 0x00, 0x0f, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, + 0x01, 0x02, 0x00, 0x03, 0x01, 0x03, 0x00, 0x04, 0x01, 0x04, 0x00, 0x05, + 0x01, 0x05, 0x00, 0x06, 0x00, 0x07, 0x01, 0x07, 0x00, 0x08, 0x01, 0x08, + 0x80, 0x00, 0x04, 0x12, 0x00, 0x40, 0x07 }; + uint8_t xid_r[512]; + + /* Parse and show contained comp fields */ + comp_fields = gprs_sndcp_parse_xid(ctx, xid, sizeof(xid), NULL); + OSMO_ASSERT(comp_fields); + printf("Decoded:\n"); + gprs_sndcp_dump_comp_fields(comp_fields, DSNDCP); + + /* Encode comp-fields again */ + rc = gprs_sndcp_compile_xid(xid_r,sizeof(xid_r), comp_fields); + printf("Result length=%i\n",rc); + printf("Encoded: %s\n", osmo_hexdump_nospc(xid, sizeof(xid))); + printf("Rencoded: %s\n", osmo_hexdump_nospc(xid_r, rc)); + + OSMO_ASSERT(rc == 54); + OSMO_ASSERT(memcmp(xid, xid_r, sizeof(xid)) == 0); + + /* Free comp fields */ + gprs_sndcp_free_comp_fields(comp_fields); + + printf("\n"); +} + +/* Encode and decode test with artificial test data */ +static void test_xid_encode_decode(const void *ctx) +{ + printf("Testing SNDCP XID-Encoder/Decoder\n"); + + LLIST_HEAD(comp_fields); + struct gprs_sndcp_pcomp_rfc1144_params rfc1144_params; + struct gprs_sndcp_comp_field rfc1144_comp_field; + struct gprs_sndcp_pcomp_rfc2507_params rfc2507_params; + struct gprs_sndcp_comp_field rfc2507_comp_field; + struct gprs_sndcp_pcomp_rohc_params rohc_params; + struct gprs_sndcp_comp_field rohc_comp_field; + struct gprs_sndcp_dcomp_v42bis_params v42bis_params; + struct gprs_sndcp_comp_field v42bis_comp_field; + struct gprs_sndcp_dcomp_v44_params v44_params; + struct gprs_sndcp_comp_field v44_comp_field; + struct llist_head *comp_fields_dec; + + uint8_t xid[512]; + unsigned int xid_len = sizeof(xid); + int rc; + + memset(&rfc1144_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + memset(&rfc2507_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + memset(&rohc_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + memset(&v42bis_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + memset(&v44_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + + /* Setup which NSAPIs shall make use of rfc1144 */ + rfc1144_params.nsapi[0] = 5; + rfc1144_params.nsapi_len = 1; + + /* Setup rfc1144 operating parameters */ + rfc1144_params.s01 = 7; + + /* Setup rfc1144 compression field */ + rfc1144_comp_field.p = 1; + rfc1144_comp_field.entity = 0; + rfc1144_comp_field.algo = RFC_1144; + rfc1144_comp_field.comp[RFC1144_PCOMP1] = 1; + rfc1144_comp_field.comp[RFC1144_PCOMP2] = 2; + rfc1144_comp_field.comp_len = RFC1144_PCOMP_NUM; + rfc1144_comp_field.rfc1144_params = &rfc1144_params; + + /* Setup which NSAPIs shall make use of rfc1144 */ + rfc2507_params.nsapi[0] = 6; + rfc2507_params.nsapi_len = 1; + + /* Setup rfc2507 operating parameters */ + rfc2507_params.f_max_period = 256; + rfc2507_params.f_max_time = 5; + rfc2507_params.max_header = 168; + rfc2507_params.tcp_space = 15; + rfc2507_params.non_tcp_space = 15; + + /* Setup rfc2507 compression field */ + rfc2507_comp_field.p = 1; + rfc2507_comp_field.entity = 1; + rfc2507_comp_field.algo = RFC_2507; + rfc2507_comp_field.comp[RFC2507_PCOMP1] = 3; + rfc2507_comp_field.comp[RFC2507_PCOMP2] = 4; + rfc2507_comp_field.comp[RFC2507_PCOMP3] = 5; + rfc2507_comp_field.comp[RFC2507_PCOMP4] = 6; + rfc2507_comp_field.comp[RFC2507_PCOMP5] = 7; + rfc2507_comp_field.comp_len = RFC2507_PCOMP_NUM; + rfc2507_comp_field.rfc2507_params = &rfc2507_params; + + /* Setup which NSAPIs shall make use of ROHC */ + rohc_params.nsapi[0] = 5; + rohc_params.nsapi[1] = 6; + rohc_params.nsapi[2] = 7; + rohc_params.nsapi[3] = 8; + rohc_params.nsapi[4] = 9; + rohc_params.nsapi[5] = 10; + rohc_params.nsapi[6] = 11; + rohc_params.nsapi[7] = 12; + rohc_params.nsapi[8] = 13; + rohc_params.nsapi[9] = 14; + rohc_params.nsapi[10] = 15; + rohc_params.nsapi_len = 11; + + /* Setup ROHC operating parameters */ + rohc_params.max_cid = 15; /* default */ + rohc_params.max_header = 168; /* default */ + rohc_params.profile[0] = ROHC_UNCOMPRESSED; + rohc_params.profile[1] = ROHC_RTP; + rohc_params.profile[2] = ROHCV2_RTP; + rohc_params.profile[3] = ROHC_UDP; + rohc_params.profile[4] = ROHCv2_UDP; + rohc_params.profile[5] = ROHC_ESP; + rohc_params.profile[6] = ROHCV2_ESP; + rohc_params.profile[7] = ROHC_IP; + rohc_params.profile[8] = ROHCV2_IP; + rohc_params.profile[9] = ROHC_LLA; + rohc_params.profile[10] = ROHC_LLA_WITH_R_MODE; + rohc_params.profile[11] = ROHC_TCP; + rohc_params.profile[12] = ROHC_RTP_UDP_LITE; + rohc_params.profile[13] = ROHCV2_RTP_UDP_LITE; + rohc_params.profile[14] = ROHC_UDP_LITE; + rohc_params.profile[15] = ROHCV2_UDP_LITE; + rohc_params.profile_len = 16; + + /* Setup ROHC compression field */ + rohc_comp_field.p = 1; + rohc_comp_field.entity = 2; + rohc_comp_field.algo = ROHC; + rohc_comp_field.comp[ROHC_PCOMP1] = 8; + rohc_comp_field.comp[ROHC_PCOMP2] = 9; + rohc_comp_field.comp_len = ROHC_PCOMP_NUM; + rohc_comp_field.rohc_params = &rohc_params; + + /* Setup which NSAPIs shall make use of v42bis */ + v42bis_params.nsapi[0] = 5; + v42bis_params.nsapi_len = 1; + + /* Setup v42bis operating parameters */ + v42bis_params.p0 = 3; + v42bis_params.p1 = 2048; + v42bis_params.p2 = 20; + + /* Setup v42bis compression field */ + v42bis_comp_field.p = 1; + v42bis_comp_field.entity = 3; + v42bis_comp_field.algo = V42BIS; + v42bis_comp_field.comp[V42BIS_DCOMP1] = 10; + v42bis_comp_field.comp_len = V42BIS_DCOMP_NUM; + v42bis_comp_field.v42bis_params = &v42bis_params; + + /* Setup which NSAPIs shall make use of v44 */ + v44_params.nsapi[0] = 5; + v44_params.nsapi_len = 1; + + /* Setup v44 operating parameters */ + v44_params.c0 = 0x80; + v44_params.p0 = 3; + v44_params.p1t = 300; + v44_params.p1r = 300; + v44_params.p3t = 600; + v44_params.p3r = 600; + + /* Setup v44 compression field */ + v44_comp_field.p = 1; + v44_comp_field.entity = 3; + v44_comp_field.algo = V44; + v44_comp_field.comp[V44_DCOMP1] = 10; + v44_comp_field.comp[V44_DCOMP2] = 11; + v44_comp_field.comp_len = V44_DCOMP_NUM; + v44_comp_field.v44_params = &v44_params; + + /* Add compression field(s) to list */ + llist_add(&v44_comp_field.list, &comp_fields); + llist_add(&v42bis_comp_field.list, &comp_fields); + llist_add(&rfc1144_comp_field.list, &comp_fields); + llist_add(&rfc2507_comp_field.list, &comp_fields); + llist_add(&rohc_comp_field.list, &comp_fields); + printf("Test input data:\n"); + gprs_sndcp_dump_comp_fields(&comp_fields, DSNDCP); + + /* Encode SNDCP-XID fields */ + rc = gprs_sndcp_compile_xid(xid, xid_len, &comp_fields); + OSMO_ASSERT(rc > 0); + + printf("Encoded: %s (%i bytes)\n", osmo_hexdump_nospc(xid, rc), rc); + + /* Parse and show contained comp fields */ + comp_fields_dec = gprs_sndcp_parse_xid(ctx, xid, rc, NULL); + OSMO_ASSERT(comp_fields_dec); + + printf("Decoded:\n"); + gprs_sndcp_dump_comp_fields(comp_fields_dec, DSNDCP); + + /* Free comp fields */ + gprs_sndcp_free_comp_fields(comp_fields_dec); +} + +static struct log_info_cat gprs_categories[] = { + [DSNDCP] = { + .name = "DSNDCP", + .description = + "GPRS Sub-Network Dependent Control Protocol (SNDCP)", + .enabled = 1,.loglevel = LOGL_DEBUG, + } +}; + +static struct log_info info = { + .cat = gprs_categories, + .num_cat = ARRAY_SIZE(gprs_categories), +}; + +int main(int argc, char **argv) +{ + void *xid_ctx; + + osmo_init_logging(&info); + + xid_ctx = talloc_named_const(NULL, 0, "xid_ctx"); + + test_xid_decode_realworld(xid_ctx); + test_xid_encode_decode(xid_ctx); + + printf("Done\n"); + + talloc_report_full(xid_ctx, stderr); + OSMO_ASSERT(talloc_total_blocks(xid_ctx) == 1); + return 0; +} + +/* stubs */ +struct osmo_prim_hdr; +int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) +{ + abort(); +} diff --git a/openbsc/tests/sndcp_xid/sndcp_xid_test.ok b/openbsc/tests/sndcp_xid/sndcp_xid_test.ok new file mode 100644 index 0000000..f357282 --- /dev/null +++ b/openbsc/tests/sndcp_xid/sndcp_xid_test.ok @@ -0,0 +1,11 @@ +Testing SNDCP XID-Decoder/Encoder (real world data) +Decoded: +Result length=54 +Encoded: 000100023182022789ffe0000f00a8000000010101000201020003010300040104000501050006000701070008010880000412004007 +Rencoded: 000100023182022789ffe0000f00a8000000010101000201020003010300040104000501050006000701070008010880000412004007 + +Testing SNDCP XID-Encoder/Decoder +Test input data: +Encoded: 000100011a83010dab00208003012c012c02580258830007a000200308001402408000041200200781010c3456700040010005a80f000f82022789ffe0000f00a80000000101010002010200030103000401040005010500060007010700080108 (97 bytes) +Decoded: +Done diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index 6470ab9..85a81d6 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -129,3 +129,10 @@ cat $abs_srcdir/xid/xid_test.ok > expout AT_CHECK([$abs_top_builddir/tests/xid/xid_test], [], [expout], [ignore]) AT_CLEANUP + +AT_SETUP([sndcp_xid]) +AT_KEYWORDS([sndcp_xid]) +cat $abs_srcdir/sndcp_xid/sndcp_xid_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/sndcp_xid/sndcp_xid_test], [], [expout], [ignore]) +AT_CLEANUP + -- To view, visit https://gerrit.osmocom.org/641 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e Gerrit-PatchSet: 10 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Tue Aug 16 15:37:37 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Tue, 16 Aug 2016 15:37:37 +0000 Subject: [PATCH] openbsc[master]: Adding compression control In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/642 to look at the new patch set (#13). Adding compression control In this commit two modules were added: gprs_sndcp_comp.h/c: This part handles the creation and destruction of conpression entites. It handles the allocation and freeing of the memory and offers functions to query compression parameters (i.e. which compression entity should be used if a packet from NSAPI x has to be compressed?) gprs_sndcp_pcomp.c/h: This is the code that performs the actual header compression. It takes care that the packets are compressed/decompressed with the right modes etc. It works, but is not yet ready for merging. Both files depend on each other so that they only can be merged both at the same time. Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 --- M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_sndcp_comp.h A openbsc/include/openbsc/gprs_sndcp_pcomp.h M openbsc/include/openbsc/sgsn.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_sndcp_comp.c A openbsc/src/gprs/gprs_sndcp_pcomp.c M openbsc/src/gprs/sgsn_vty.c M openbsc/tests/sgsn/Makefile.am 9 files changed, 827 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/42/642/13 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index f402fea..88a7e2c 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,7 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ - slhc.h + slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_sndcp_comp.h b/openbsc/include/openbsc/gprs_sndcp_comp.h new file mode 100644 index 0000000..e2d79ab --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_comp.h @@ -0,0 +1,85 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_SNDCP_COMP_H +#define _GPRS_SNDCP_COMP_H + +#include +#include +#include + +/* Header / Data compression entity */ +struct gprs_sndcp_comp { + struct llist_head list; + + /* Serves as an ID in case we want to delete this entity later */ + int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + + /* Specifies to which NSAPIs the compression entity is assigned */ + int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + int nsapi[11]; /* Applicable NSAPIs (default 0) */ + + /* Assigned pcomp values */ + int comp_len; /* Number of contained PCOMP / DCOMP values */ + int comp[16]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */ + + /* Algorithm parameters */ + int algo; /* Algorithm type (see gprs_sndcp_xid.h) */ + int compclass; /* See gprs_sndcp_xid.h/c */ + void *state; /* Algorithm status and parameters */ +}; + +/* Free a list with compression entities */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities); + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, int entity); + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_entities_add(const void *ctx, struct + llist_head + *comp_entities, const struct + gprs_sndcp_comp_field + *comp_field); + +/* Find compression entity by its entity number */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_entity(const struct llist_head + *comp_entities, int entity); + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head + *comp_entities, int comp); + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head + *comp_entities, int nsapi); + +/* Find a comp_index for a given pcomp/dcomp value */ +int gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp + *comp_entity, int comp); + +/* Find a pcomp/dcomp value for a given comp_index */ +int gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp + *comp_entity, int comp_index); + +#endif diff --git a/openbsc/include/openbsc/gprs_sndcp_pcomp.h b/openbsc/include/openbsc/gprs_sndcp_pcomp.h new file mode 100644 index 0000000..2444260 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_pcomp.h @@ -0,0 +1,47 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_SNDCP_pcomp_H +#define _GPRS_SNDCP_pcomp_H + +#include +#include +#include + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field); + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity); + +/* Expand packet header */ +int gprs_sndcp_pcomp_expand(uint8_t *data_o, uint8_t *data_i, int len, + int pcomp, const struct llist_head *comp_entities); + +/* Compress packet header */ +int gprs_sndcp_pcomp_compress(uint8_t *data_o, uint8_t *data_i, int len, + int *pcomp, + const struct llist_head *comp_entities, + int nsapi); + +#endif diff --git a/openbsc/include/openbsc/sgsn.h b/openbsc/include/openbsc/sgsn.h index 59126fe..2366d7a 100644 --- a/openbsc/include/openbsc/sgsn.h +++ b/openbsc/include/openbsc/sgsn.h @@ -88,6 +88,12 @@ int dynamic_lookup; + /* RFC1144 TCP/IP Header compression */ + struct { + int enabled; + int s01; + } pcomp_rfc1144; + struct oap_config oap; }; diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 245636b..2910c02 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -27,7 +27,7 @@ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ - slhc.c + slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/gprs_sndcp_comp.c b/openbsc/src/gprs/gprs_sndcp_comp.c new file mode 100644 index 0000000..8153fd2 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_comp.c @@ -0,0 +1,320 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +/* Create a new compression entity from a XID-Field */ +static struct gprs_sndcp_comp *gprs_sndcp_comp_create(const void + *ctx, const struct + gprs_sndcp_comp_field + *comp_field) +{ + OSMO_ASSERT(comp_field); + + struct gprs_sndcp_comp *comp_entity; + comp_entity = talloc_zero(ctx, struct gprs_sndcp_comp); + + /* Copy relevant information from the SNDCP-XID field */ + comp_entity->entity = comp_field->entity; + comp_entity->comp_len = comp_field->comp_len; + memcpy(comp_entity->comp, comp_field->comp, + comp_field->comp_len * sizeof(int)); + + if (comp_field->rfc1144_params) { + comp_entity->nsapi_len = comp_field->rfc1144_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc1144_params->nsapi, + comp_entity->nsapi_len * sizeof(int)); + } else if (comp_field->rfc2507_params) { + comp_entity->nsapi_len = comp_field->rfc2507_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc2507_params->nsapi, + comp_entity->nsapi_len * sizeof(int)); + } else if (comp_field->rohc_params) { + comp_entity->nsapi_len = comp_field->rohc_params->nsapi_len; + memcpy(comp_entity->nsapi, comp_field->rohc_params->nsapi, + comp_entity->nsapi_len * sizeof(int)); + } else if (comp_field->v42bis_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + comp_entity->nsapi_len * sizeof(int)); + } else if (comp_field->v44_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + comp_entity->nsapi_len * sizeof(int)); + } else { + talloc_free(comp_entity); + LOGP(DSNDCP, LOGL_ERROR, + "Comp field contained invalid parameters, compression entity not created!\n"); + return NULL; + } + + comp_entity->algo = comp_field->algo; + comp_entity->state = NULL; + + /* Determine of which class our compression entity will be + * (Protocol or Data compresson ?) */ + comp_entity->compclass = gprs_sndcp_get_compression_class(comp_field); + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + if (gprs_sndcp_pcomp_init(ctx, comp_entity, comp_field) == 0) + LOGP(DSNDCP, LOGL_INFO, + "New header compression entity (%i) created.\n", + comp_entity->entity); + else { + talloc_free(comp_entity); + LOGP(DSNDCP, LOGL_ERROR, + "Header compression entity (%i) creation failed!\n", + comp_entity->entity); + return NULL; + } + } else { + LOGP(DSNDCP, LOGL_INFO, + "New data compression entity (%i) created.\n", + comp_entity->entity); + } + + return comp_entity; +} + +/* Free a list with compression entities */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities) +{ + struct llist_head *ce, *ce2; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + /* Free compression entity */ + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %i ...\n", + comp_entity->entity); + gprs_sndcp_pcomp_term(comp_entity); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %i ...\n", + comp_entity->entity); + } + } + + llist_for_each_safe(ce, ce2, comp_entities) { + llist_del(ce); + talloc_free(ce); + } + +} + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, int entity) +{ + struct gprs_sndcp_comp *comp_entity; + struct gprs_sndcp_comp *comp_entity_to_delete = NULL; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) + comp_entity_to_delete = comp_entity; + } + + if (comp_entity_to_delete) { + if (comp_entity_to_delete->compclass == + SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %i ...\n", + comp_entity_to_delete->entity); + gprs_sndcp_pcomp_term(comp_entity_to_delete); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %i ...\n", + comp_entity_to_delete->entity); + } + + /* Delete compression entity */ + llist_del(&comp_entity_to_delete->list); + talloc_free(comp_entity_to_delete); + } + +} + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_entities_add(const void *ctx, struct + llist_head + *comp_entities, const struct + gprs_sndcp_comp_field + *comp_field) +{ + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(comp_entities); + OSMO_ASSERT(comp_field); + + /* Just to be sure, if the entity is already in + * the list it will be deleted now */ + gprs_sndcp_comp_delete(comp_entities, comp_field->entity); + + /* Create and add a new entity to the list */ + comp_entity = gprs_sndcp_comp_create(ctx, comp_field); + + if (comp_entity) { + llist_add(&comp_entity->list, comp_entities); + return comp_entity; + } + + return NULL; +} + +/* Find compression entity by its entity number */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_entity(const struct + llist_head + *comp_entities, int entity) +{ + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) + return comp_entity; + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given entity number %i.\n", + entity); + return NULL; +} + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct + llist_head + *comp_entities, int comp) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return comp_entity; + } + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given pcomp/dcomp value %i.\n", + comp); + return NULL; +} + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct + llist_head + *comp_entities, int nsapi) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->nsapi_len; i++) { + if (comp_entity->nsapi[i] == nsapi) + return comp_entity; + } + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given nsapi value %i\n", + nsapi); + return NULL; + +} + +/* Find a comp_index for a given pcomp/dcomp value */ +int gprs_sndcp_comp_get_idx(const struct + gprs_sndcp_comp + *comp_entity, int comp) +{ + int i; + + OSMO_ASSERT(comp_entity); + + /* A pcomp/dcomp field set to zero always disables + * all sort of compression and is assigned fix. So we + * just return zero in this case */ + if (comp == 0) + return 0; + + /* Look in the pcomp/dcomp list for the index */ + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return i + 1; + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching comp_index for given pcomp/dcomp value %i\n", + comp); + return 0; + +} + +/* Find a pcomp/dcomp value for a given comp_index */ +int gprs_sndcp_comp_get_comp(const struct + gprs_sndcp_comp + *comp_entity, int comp_index) +{ + OSMO_ASSERT(comp_entity); + + /* A comp_index of zero translates to zero right away. */ + if (comp_index == 0) + return 0; + + if (comp_index > comp_entity->comp_len) { + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching pcomp/dcomp value for given comp_index value %i.\n", + comp_index); + return 0; + } + + /* Look in the pcomp/dcomp list for the comp_index */ + return comp_entity->comp[comp_index - 1]; + +} diff --git a/openbsc/src/gprs/gprs_sndcp_pcomp.c b/openbsc/src/gprs/gprs_sndcp_pcomp.c new file mode 100644 index 0000000..41f6c6a --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_pcomp.c @@ -0,0 +1,334 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG_RFC1144 1 + +/* Show details of the RFC1144 compressed packet header */ +static void debug_rfc1144_header(uint8_t *header) +{ +#if DEBUG_RFC1144 == 1 + + int t,c,i,p,s,a,w,u = 0; + t = (header[0] >> 7) & 1; + c = (header[0] >> 6) & 1; + i = (header[0] >> 5) & 1; + p = (header[0] >> 4) & 1; + s = (header[0] >> 3) & 1; + a = (header[0] >> 2) & 1; + w = (header[0] >> 1) & 1; + u = header[0] & 1; + + DEBUGP(DSNDCP,"rfc1144 header:\n"); + DEBUGP(DSNDCP," Tag bit = %d\n",t); + DEBUGP(DSNDCP," C = %d\n",c); + DEBUGP(DSNDCP," I = %d\n",i); + DEBUGP(DSNDCP," P = %d\n",p); + DEBUGP(DSNDCP," S = %d\n",s); + DEBUGP(DSNDCP," A = %d\n",a); + DEBUGP(DSNDCP," W = %d\n",w); + DEBUGP(DSNDCP," U = %d\n",u); + + header++; + if(c) { + DEBUGP(DSNDCP," Connection number (C) = %d\n",*header); + header++; + } + + DEBUGP(DSNDCP," TCP Checksum = %02x%02x\n",header[0],header[1]); + header+=2; + + if(s && w && u) { + DEBUGP(DSNDCP," Special case I (SPECIAL_I) => short header\n"); + return; + } else if(s && a && w && u) { + DEBUGP(DSNDCP," Special case D (SPECIAL_D) => short header\n"); + return; + } + + if(u) { + DEBUGP(DSNDCP," Urgent Pointer (U) = %02x\n",*header); + header++; + } + if(w) { + DEBUGP(DSNDCP," Delta Window (W) = %02x\n",*header); + header++; + } + if(a) { + DEBUGP(DSNDCP," Delta Ack (A) = %02x\n",*header); + header++; + } + if(s) { + DEBUGP(DSNDCP," Delta Sequence (S) = %02x\n",*header); + header++; + } + if(i) { + DEBUGP(DSNDCP," Delta IP ID (I) = %02x\n",*header); + header++; + } + + /* FIXME: Header values will be usually fit in 8 bits, implement + * implement variable length decoding for values larger then 8 bit */ +#endif +} + + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a new header compression + * entity is created by gprs_sndcp.c */ + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + comp_entity->state = + slhc_init(ctx, comp_field->rfc1144_params->s01 + 1, + comp_field->rfc1144_params->s01 + 1); + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression initalized.\n"); + return 0; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a header compression + * entity is deleted by gprs_sndcp.c */ + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + if (comp_entity->state) { + slhc_free((struct slcompress *)comp_entity->state); + comp_entity->state = NULL; + } + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression terminated.\n"); + return; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Compress a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_compress(int *pcomp_index, uint8_t *data_o, + uint8_t *data_i, int len, + struct slcompress *comp) +{ + uint8_t *comp_ptr; /* Not used */ + int compr_len; + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Run compressor */ + compr_len = slhc_compress(comp, data_i, len, data_o, &comp_ptr, 0); + + /* Generate pcomp_index */ + if (data_o[0] & SL_TYPE_COMPRESSED_TCP) { + *pcomp_index = 2; + data_o[0] &= ~SL_TYPE_COMPRESSED_TCP; + debug_rfc1144_header(data_o); + } else if ((data_o[0] & SL_TYPE_UNCOMPRESSED_TCP) == + SL_TYPE_UNCOMPRESSED_TCP) { + *pcomp_index = 1; + data_o[0] &= 0x4F; + } else + *pcomp_index = 0; + + return compr_len; +} + +/* Expand a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_expand(uint8_t *data_o, uint8_t *data_i, + int len, int pcomp_index, + struct slcompress *comp) +{ + int data_decompressed_len; + int type = -1; + + /* Note: this function should never be called with pcomp_index=0, + * since this condition is already filtered + * out by gprs_sndcp_pcomp_expand() */ + + /* Determine the data type by the PCOMP index */ + switch (pcomp_index) { + case 1: + type = SL_TYPE_UNCOMPRESSED_TCP; + break; + case 2: + type = SL_TYPE_COMPRESSED_TCP; + break; + } + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Restore the original version nibble on + * marked uncompressed packets */ + if (type == SL_TYPE_UNCOMPRESSED_TCP) { + + /* Just in case the phone tags uncompressed tcp-datas + * (normally this is handled by pcomp so there is + * no need for tagging the datas) */ + data_o[0] &= 0x4F; + data_decompressed_len = slhc_remember(comp, data_o, len); + return data_decompressed_len; + } + + /* Uncompress compressed packets */ + else if (type == SL_TYPE_COMPRESSED_TCP) { + data_decompressed_len = slhc_uncompress(comp, data_o, len); + return data_decompressed_len; + } + + /* Regular or unknown packets will not be touched */ + return len; +} + +/* Expand packet header */ +int gprs_sndcp_pcomp_expand(uint8_t *data_o, uint8_t *data_i, int len, + int pcomp, const struct llist_head *comp_entities) +{ + int rc; + int pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data_o); + OSMO_ASSERT(data_i); + OSMO_ASSERT(comp_entities); + + /* Skip on pcomp=0 */ + if (pcomp == 0) { + memcpy(data_o,data_i,len); + return len; + } + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_comp(comp_entities, pcomp); + + /* Skip compression if no suitable compression entity can be found */ + if (comp_entity == NULL) { + memcpy(data_o,data_i,len); + return len; + } + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION); + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144); + + /* Find pcomp_index */ + pcomp_index = gprs_sndcp_comp_get_idx(comp_entity, pcomp); + + /* Run decompression algo */ + rc = gprs_sndcp_pcomp_rfc1144_expand(data_o, data_i, len, pcomp_index, + comp_entity->state); + slhc_i_status(comp_entity->state); + slhc_o_status(comp_entity->state); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header expansion done, old length=%i, new length=%i\n", + len, rc); + + return rc; +} + +/* Compress packet header */ +int gprs_sndcp_pcomp_compress(uint8_t *data_o, uint8_t *data_i, int len, + int *pcomp, + const struct llist_head *comp_entities, int nsapi) +{ + int rc; + int pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data_o); + OSMO_ASSERT(data_i); + OSMO_ASSERT(pcomp); + OSMO_ASSERT(comp_entities); + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_nsapi(comp_entities, nsapi); + + /* Skip compression if no suitable compression entity can be found */ + if (!comp_entity) { + *pcomp = 0; + memcpy(data_o,data_i,len); + return len; + } + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION); + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144); + + /* Run compression algo */ + rc = gprs_sndcp_pcomp_rfc1144_compress(&pcomp_index, data_o, data_i, + len, comp_entity->state); + slhc_i_status(comp_entity->state); + slhc_o_status(comp_entity->state); + + /* Find pcomp value */ + *pcomp = gprs_sndcp_comp_get_comp(comp_entity, pcomp_index); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header compression done, old length=%i, new length=%i\n", + len, rc); + return rc; +} diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c index e6dc68d..aae1acb 100644 --- a/openbsc/src/gprs/sgsn_vty.c +++ b/openbsc/src/gprs/sgsn_vty.c @@ -269,6 +269,13 @@ vty_out(vty, " timer t3395 %d%s", g_cfg->timers.T3395, VTY_NEWLINE); vty_out(vty, " timer t3397 %d%s", g_cfg->timers.T3397, VTY_NEWLINE); + if (g_cfg->pcomp_rfc1144.enabled) { + vty_out(vty, " compression rfc1144 slots %d%s", + g_cfg->pcomp_rfc1144.s01+1, VTY_NEWLINE); + } else { + vty_out(vty, " no compression rfc1144%s", VTY_NEWLINE); + } + return CMD_SUCCESS; } @@ -1074,6 +1081,27 @@ return CMD_SUCCESS; } +DEFUN(cfg_no_comp_rfc1144, cfg_no_comp_rfc1144_cmd, + "no compression rfc1144", + NO_STR "compression\n" + "disable rfc1144 TCP/IP header compression\n") +{ + g_cfg->pcomp_rfc1144.enabled = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_comp_rfc1144, cfg_comp_rfc1144_cmd, + "compression rfc1144 slots <1-256>", + "Configure compression\n" + "RFC1144 Header compresion scheme\n" + "Number of compression state slots\n" + "number\n") +{ + g_cfg->pcomp_rfc1144.enabled = 0; + g_cfg->pcomp_rfc1144.s01 = atoi(argv[0]) - 1; + return CMD_SUCCESS; +} + int sgsn_vty_init(void) { install_element_ve(&show_sgsn_cmd); @@ -1128,6 +1156,9 @@ install_element(SGSN_NODE, &cfg_sgsn_T3395_cmd); install_element(SGSN_NODE, &cfg_sgsn_T3397_cmd); + install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd); + install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd); + return 0; } diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 3e66978..1804280 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -33,6 +33,8 @@ $(top_builddir)/src/gprs/gprs_llc_xid.o \ $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ $(top_builddir)/src/gprs/slhc.o \ + $(top_builddir)/src/gprs/gprs_sndcp_comp.o \ + $(top_builddir)/src/gprs/gprs_sndcp_pcomp.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ -- To view, visit https://gerrit.osmocom.org/642 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 Gerrit-PatchSet: 13 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Tue Aug 16 15:37:37 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Tue, 16 Aug 2016 15:37:37 +0000 Subject: [PATCH] openbsc[master]: Adding SLHC (RFC1144 header compression) code from linux kernel In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/634 to look at the new patch set (#8). Adding SLHC (RFC1144 header compression) code from linux kernel Slhc is an Implementation of RFC1144 TCP/IP header compression. We will need RFC1144 compression to compress GPRS TCP/IP traffic. The implementation pushed with this commit was taken from git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git git://git.kernel.org/pub/scm/linux/kernel/git/wtarreau/linux-2.4.git commit 29b4817d4018df78086157ea3a55c1d9424a7cfc Change-Id: Ied69c143678dc4a64cecc671f5c4dfebe19d8519 --- A openbsc/include/openbsc/slhc_vj.h A openbsc/src/gprs/slhc.c 2 files changed, 927 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/34/634/8 diff --git a/openbsc/include/openbsc/slhc_vj.h b/openbsc/include/openbsc/slhc_vj.h new file mode 100644 index 0000000..8716d59 --- /dev/null +++ b/openbsc/include/openbsc/slhc_vj.h @@ -0,0 +1,183 @@ +#ifndef _SLHC_H +#define _SLHC_H +/* + * Definitions for tcp compression routines. + * + * $Header: slcompress.h,v 1.10 89/12/31 08:53:02 van Exp $ + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van at helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + * + * + * modified for KA9Q Internet Software Package by + * Katie Stevens (dkstevens at ucdavis.edu) + * University of California, Davis + * Computing Services + * - 01-31-90 initial adaptation + * + * - Feb 1991 Bill_Simpson at um.cc.umich.edu + * variable number of conversation slots + * allow zero or one slots + * separate routines + * status display + */ + +/* + * Compressed packet format: + * + * The first octet contains the packet type (top 3 bits), TCP + * 'push' bit, and flags that indicate which of the 4 TCP sequence + * numbers have changed (bottom 5 bits). The next octet is a + * conversation number that associates a saved IP/TCP header with + * the compressed packet. The next two octets are the TCP checksum + * from the original datagram. The next 0 to 15 octets are + * sequence number changes, one change per bit set in the header + * (there may be no changes and there are two special cases where + * the receiver implicitly knows what changed -- see below). + * + * There are 5 numbers which can change (they are always inserted + * in the following order): TCP urgent pointer, window, + * acknowledgment, sequence number and IP ID. (The urgent pointer + * is different from the others in that its value is sent, not the + * change in value.) Since typical use of SLIP links is biased + * toward small packets (see comments on MTU/MSS below), changes + * use a variable length coding with one octet for numbers in the + * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the + * range 256 - 65535 or 0. (If the change in sequence number or + * ack is more than 65535, an uncompressed packet is sent.) + */ + +/* + * Packet types (must not conflict with IP protocol version) + * + * The top nibble of the first octet is the packet type. There are + * three possible types: IP (not proto TCP or tcp with one of the + * control flags set); uncompressed TCP (a normal IP/TCP packet but + * with the 8-bit protocol field replaced by an 8-bit connection id -- + * this type of packet syncs the sender & receiver); and compressed + * TCP (described above). + * + * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and + * is logically part of the 4-bit "changes" field that follows. Top + * three bits are actual packet type. For backward compatibility + * and in the interest of conserving bits, numbers are chosen so the + * IP protocol version number (4) which normally appears in this nibble + * means "IP packet". + */ + + +#include +#include + +/* SLIP compression masks for len/vers byte */ +#define SL_TYPE_IP 0x40 +#define SL_TYPE_UNCOMPRESSED_TCP 0x70 +#define SL_TYPE_COMPRESSED_TCP 0x80 +#define SL_TYPE_ERROR 0x00 + +/* Bits in first octet of compressed packet */ +#define NEW_C 0x40 /* flag bits for what changed in a packet */ +#define NEW_I 0x20 +#define NEW_S 0x08 +#define NEW_A 0x04 +#define NEW_W 0x02 +#define NEW_U 0x01 + +/* reserved, special-case values of above */ +#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */ +#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */ +#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U) + +#define TCP_PUSH_BIT 0x10 + +/* + * data type and sizes conversion assumptions: + * + * VJ code KA9Q style generic + * u_char byte_t unsigned char 8 bits + * u_short int16 unsigned short 16 bits + * u_int int16 unsigned short 16 bits + * u_long unsigned long unsigned long 32 bits + * int int32 long 32 bits + */ + +typedef __u8 byte_t; +typedef __u32 int32; + +/* + * "state" data for each active tcp conversation on the wire. This is + * basically a copy of the entire IP/TCP header from the last packet + * we saw from the conversation together with a small identifier + * the transmit & receive ends of the line use to locate saved header. + */ +struct cstate { + byte_t cs_this; /* connection id number (xmit) */ + struct cstate *next; /* next in ring (xmit) */ + struct iphdr cs_ip; /* ip/tcp hdr from most recent packet */ + struct tcphdr cs_tcp; + unsigned char cs_ipopt[64]; + unsigned char cs_tcpopt[64]; + int cs_hsize; +}; +#define NULLSLSTATE (struct cstate *)0 + +/* + * all the state data for one serial line (we need one of these per line). + */ +struct slcompress { + struct cstate *tstate; /* transmit connection states (array)*/ + struct cstate *rstate; /* receive connection states (array)*/ + + byte_t tslot_limit; /* highest transmit slot id (0-l)*/ + byte_t rslot_limit; /* highest receive slot id (0-l)*/ + + byte_t xmit_oldest; /* oldest xmit in ring */ + byte_t xmit_current; /* most recent xmit id */ + byte_t recv_current; /* most recent rcvd id */ + + byte_t flags; +#define SLF_TOSS 0x01 /* tossing rcvd frames until id received */ + + int32 sls_o_nontcp; /* outbound non-TCP packets */ + int32 sls_o_tcp; /* outbound TCP packets */ + int32 sls_o_uncompressed; /* outbound uncompressed packets */ + int32 sls_o_compressed; /* outbound compressed packets */ + int32 sls_o_searches; /* searches for connection state */ + int32 sls_o_misses; /* times couldn't find conn. state */ + + int32 sls_i_uncompressed; /* inbound uncompressed packets */ + int32 sls_i_compressed; /* inbound compressed packets */ + int32 sls_i_error; /* inbound error packets */ + int32 sls_i_tossed; /* inbound packets tossed because of error */ + + int32 sls_i_runt; + int32 sls_i_badcheck; +}; +#define NULLSLCOMPR (struct slcompress *)0 + +/* In slhc.c: */ +struct slcompress *slhc_init(int rslots, int tslots); +void slhc_free(struct slcompress *comp); + +int slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, + unsigned char *ocp, unsigned char **cpp, int compress_cid); +int slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize); +int slhc_remember(struct slcompress *comp, unsigned char *icp, int isize); +int slhc_toss(struct slcompress *comp); + +#endif /* _SLHC_H */ diff --git a/openbsc/src/gprs/slhc.c b/openbsc/src/gprs/slhc.c new file mode 100644 index 0000000..27ed252 --- /dev/null +++ b/openbsc/src/gprs/slhc.c @@ -0,0 +1,744 @@ +/* + * Routines to compress and uncompress tcp packets (for transmission + * over low speed serial lines). + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van at helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + * + * + * modified for KA9Q Internet Software Package by + * Katie Stevens (dkstevens at ucdavis.edu) + * University of California, Davis + * Computing Services + * - 01-31-90 initial adaptation (from 1.19) + * PPP.05 02-15-90 [ks] + * PPP.08 05-02-90 [ks] use PPP protocol field to signal compression + * PPP.15 09-90 [ks] improve mbuf handling + * PPP.16 11-02 [karn] substantially rewritten to use NOS facilities + * + * - Feb 1991 Bill_Simpson at um.cc.umich.edu + * variable number of conversation slots + * allow zero or one slots + * separate routines + * status display + * - Jul 1994 Dmitry Gorodchanin + * Fixes for memory leaks. + * - Oct 1994 Dmitry Gorodchanin + * Modularization. + * - Jan 1995 Bjorn Ekwall + * Use ip_fast_csum from ip.h + * - July 1995 Christos A. Polyzols + * Spotted bug in tcp option checking + * + * + * This module is a difficult issue. It's clearly inet code but it's also clearly + * driver code belonging close to PPP and SLIP + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_INET +/* Entire module is for IP only */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned char *encode(unsigned char *cp, unsigned short n); +static long decode(unsigned char **cpp); +static unsigned char * put16(unsigned char *cp, unsigned short x); +static unsigned short pull16(unsigned char **cpp); + +/* Allocate compression data structure + * slots must be in range 0 to 255 (zero meaning no compression) + * Returns pointer to structure or ERR_PTR() on error. + */ +struct slcompress * +slhc_init(int rslots, int tslots) +{ + register short i; + register struct cstate *ts; + struct slcompress *comp; + + if (rslots < 0 || rslots > 255 || tslots < 0 || tslots > 255) + return ERR_PTR(-EINVAL); + + comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL); + if (! comp) + goto out_fail; + + if (rslots > 0) { + size_t rsize = rslots * sizeof(struct cstate); + comp->rstate = kzalloc(rsize, GFP_KERNEL); + if (! comp->rstate) + goto out_free; + comp->rslot_limit = rslots - 1; + } + + if (tslots > 0) { + size_t tsize = tslots * sizeof(struct cstate); + comp->tstate = kzalloc(tsize, GFP_KERNEL); + if (! comp->tstate) + goto out_free2; + comp->tslot_limit = tslots - 1; + } + + comp->xmit_oldest = 0; + comp->xmit_current = 255; + comp->recv_current = 255; + /* + * don't accept any packets with implicit index until we get + * one with an explicit index. Otherwise the uncompress code + * will try to use connection 255, which is almost certainly + * out of range + */ + comp->flags |= SLF_TOSS; + + if ( tslots > 0 ) { + ts = comp->tstate; + for(i = comp->tslot_limit; i > 0; --i){ + ts[i].cs_this = i; + ts[i].next = &(ts[i - 1]); + } + ts[0].next = &(ts[comp->tslot_limit]); + ts[0].cs_this = 0; + } + return comp; + +out_free2: + kfree(comp->rstate); +out_free: + kfree(comp); +out_fail: + return ERR_PTR(-ENOMEM); +} + + +/* Free a compression data structure */ +void +slhc_free(struct slcompress *comp) +{ + if ( comp == NULLSLCOMPR ) + return; + + if ( comp->tstate != NULLSLSTATE ) + kfree( comp->tstate ); + + if ( comp->rstate != NULLSLSTATE ) + kfree( comp->rstate ); + + kfree( comp ); +} + + +/* Put a short in host order into a char array in network order */ +static inline unsigned char * +put16(unsigned char *cp, unsigned short x) +{ + *cp++ = x >> 8; + *cp++ = x; + + return cp; +} + + +/* Encode a number */ +static unsigned char * +encode(unsigned char *cp, unsigned short n) +{ + if(n >= 256 || n == 0){ + *cp++ = 0; + cp = put16(cp,n); + } else { + *cp++ = n; + } + return cp; +} + +/* Pull a 16-bit integer in host order from buffer in network byte order */ +static unsigned short +pull16(unsigned char **cpp) +{ + short rval; + + rval = *(*cpp)++; + rval <<= 8; + rval |= *(*cpp)++; + return rval; +} + +/* Decode a number */ +static long +decode(unsigned char **cpp) +{ + register int x; + + x = *(*cpp)++; + if(x == 0){ + return pull16(cpp) & 0xffff; /* pull16 returns -1 on error */ + } else { + return x & 0xff; /* -1 if PULLCHAR returned error */ + } +} + +/* + * icp and isize are the original packet. + * ocp is a place to put a copy if necessary. + * cpp is initially a pointer to icp. If the copy is used, + * change it to ocp. + */ + +int +slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, + unsigned char *ocp, unsigned char **cpp, int compress_cid) +{ + register struct cstate *ocs = &(comp->tstate[comp->xmit_oldest]); + register struct cstate *lcs = ocs; + register struct cstate *cs = lcs->next; + register unsigned long deltaS, deltaA; + register short changes = 0; + int hlen; + unsigned char new_seq[16]; + register unsigned char *cp = new_seq; + struct iphdr *ip; + struct tcphdr *th, *oth; + __sum16 csum; + + + /* + * Don't play with runt packets. + */ + + if(isizeprotocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x3fff)) { + /* Send as regular IP */ + if(ip->protocol != IPPROTO_TCP) + comp->sls_o_nontcp++; + else + comp->sls_o_tcp++; + return isize; + } + /* Extract TCP header */ + + th = (struct tcphdr *)(((unsigned char *)ip) + ip->ihl*4); + hlen = ip->ihl*4 + th->doff*4; + + /* Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or + * some other control bit is set). Also uncompressible if + * it's a runt. + */ + if(hlen > isize || th->syn || th->fin || th->rst || + ! (th->ack)){ + /* TCP connection stuff; send as regular IP */ + comp->sls_o_tcp++; + return isize; + } + /* + * Packet is compressible -- we're going to send either a + * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way, + * we need to locate (or create) the connection state. + * + * States are kept in a circularly linked list with + * xmit_oldest pointing to the end of the list. The + * list is kept in lru order by moving a state to the + * head of the list whenever it is referenced. Since + * the list is short and, empirically, the connection + * we want is almost always near the front, we locate + * states via linear search. If we don't find a state + * for the datagram, the oldest state is (re-)used. + */ + for ( ; ; ) { + if( ip->saddr == cs->cs_ip.saddr + && ip->daddr == cs->cs_ip.daddr + && th->source == cs->cs_tcp.source + && th->dest == cs->cs_tcp.dest) + goto found; + + /* if current equal oldest, at end of list */ + if ( cs == ocs ) + break; + lcs = cs; + cs = cs->next; + comp->sls_o_searches++; + } + /* + * Didn't find it -- re-use oldest cstate. Send an + * uncompressed packet that tells the other side what + * connection number we're using for this conversation. + * + * Note that since the state list is circular, the oldest + * state points to the newest and we only need to set + * xmit_oldest to update the lru linkage. + */ + comp->sls_o_misses++; + comp->xmit_oldest = lcs->cs_this; + goto uncompressed; + +found: + /* + * Found it -- move to the front on the connection list. + */ + if(lcs == ocs) { + /* found at most recently used */ + } else if (cs == ocs) { + /* found at least recently used */ + comp->xmit_oldest = lcs->cs_this; + } else { + /* more than 2 elements */ + lcs->next = cs->next; + cs->next = ocs->next; + ocs->next = cs; + } + + /* + * Make sure that only what we expect to change changed. + * Check the following: + * IP protocol version, header length & type of service. + * The "Don't fragment" bit. + * The time-to-live field. + * The TCP header length. + * IP options, if any. + * TCP options, if any. + * If any of these things are different between the previous & + * current datagram, we send the current datagram `uncompressed'. + */ + oth = &cs->cs_tcp; + + if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl + || ip->tos != cs->cs_ip.tos + || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000)) + || ip->ttl != cs->cs_ip.ttl + || th->doff != cs->cs_tcp.doff + || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) + || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){ + goto uncompressed; + } + + /* + * Figure out which of the changing fields changed. The + * receiver expects changes in the order: urgent, window, + * ack, seq (the order minimizes the number of temporaries + * needed in this section of code). + */ + if(th->urg){ + deltaS = ntohs(th->urg_ptr); + cp = encode(cp,deltaS); + changes |= NEW_U; + } else if(th->urg_ptr != oth->urg_ptr){ + /* argh! URG not set but urp changed -- a sensible + * implementation should never do this but RFC793 + * doesn't prohibit the change so we have to deal + * with it. */ + goto uncompressed; + } + if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){ + cp = encode(cp,deltaS); + changes |= NEW_W; + } + if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){ + if(deltaA > 0x0000ffff) + goto uncompressed; + cp = encode(cp,deltaA); + changes |= NEW_A; + } + if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){ + if(deltaS > 0x0000ffff) + goto uncompressed; + cp = encode(cp,deltaS); + changes |= NEW_S; + } + + switch(changes){ + case 0: /* Nothing changed. If this packet contains data and the + * last one didn't, this is probably a data packet following + * an ack (normal on an interactive connection) and we send + * it compressed. Otherwise it's probably a retransmit, + * retransmitted ack or window probe. Send it uncompressed + * in case the other side missed the compressed version. + */ + if(ip->tot_len != cs->cs_ip.tot_len && + ntohs(cs->cs_ip.tot_len) == hlen) + break; + goto uncompressed; + case SPECIAL_I: + case SPECIAL_D: + /* actual changes match one of our special case encodings -- + * send packet uncompressed. + */ + goto uncompressed; + case NEW_S|NEW_A: + if(deltaS == deltaA && + deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ + /* special case for echoed terminal traffic */ + changes = SPECIAL_I; + cp = new_seq; + } + break; + case NEW_S: + if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ + /* special case for data xfer */ + changes = SPECIAL_D; + cp = new_seq; + } + break; + } + deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id); + if(deltaS != 1){ + cp = encode(cp,deltaS); + changes |= NEW_I; + } + if(th->psh) + changes |= TCP_PUSH_BIT; + /* Grab the cksum before we overwrite it below. Then update our + * state with this packet's header. + */ + csum = th->check; + memcpy(&cs->cs_ip,ip,20); + memcpy(&cs->cs_tcp,th,20); + /* We want to use the original packet as our compressed packet. + * (cp - new_seq) is the number of bytes we need for compressed + * sequence numbers. In addition we need one byte for the change + * mask, one for the connection id and two for the tcp checksum. + * So, (cp - new_seq) + 4 bytes of header are needed. + */ + deltaS = cp - new_seq; + if(compress_cid == 0 || comp->xmit_current != cs->cs_this){ + cp = ocp; + *cpp = ocp; + *cp++ = changes | NEW_C; + *cp++ = cs->cs_this; + comp->xmit_current = cs->cs_this; + } else { + cp = ocp; + *cpp = ocp; + *cp++ = changes; + } + *(__sum16 *)cp = csum; + cp += 2; +/* deltaS is now the size of the change section of the compressed header */ + memcpy(cp,new_seq,deltaS); /* Write list of deltas */ + memcpy(cp+deltaS,icp+hlen,isize-hlen); + comp->sls_o_compressed++; + ocp[0] |= SL_TYPE_COMPRESSED_TCP; + return isize - hlen + deltaS + (cp - ocp); + + /* Update connection state cs & send uncompressed packet (i.e., + * a regular ip/tcp packet but with the 'conversation id' we hope + * to use on future compressed packets in the protocol field). + */ +uncompressed: + memcpy(&cs->cs_ip,ip,20); + memcpy(&cs->cs_tcp,th,20); + if (ip->ihl > 5) + memcpy(cs->cs_ipopt, ip+1, ((ip->ihl) - 5) * 4); + if (th->doff > 5) + memcpy(cs->cs_tcpopt, th+1, ((th->doff) - 5) * 4); + comp->xmit_current = cs->cs_this; + comp->sls_o_uncompressed++; + memcpy(ocp, icp, isize); + *cpp = ocp; + ocp[9] = cs->cs_this; + ocp[0] |= SL_TYPE_UNCOMPRESSED_TCP; + return isize; +} + + +int +slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) +{ + register int changes; + long x; + register struct tcphdr *thp; + register struct iphdr *ip; + register struct cstate *cs; + int len, hdrlen; + unsigned char *cp = icp; + + /* We've got a compressed packet; read the change byte */ + comp->sls_i_compressed++; + if(isize < 3){ + comp->sls_i_error++; + return 0; + } + changes = *cp++; + if(changes & NEW_C){ + /* Make sure the state index is in range, then grab the state. + * If we have a good state index, clear the 'discard' flag. + */ + x = *cp++; /* Read conn index */ + if(x < 0 || x > comp->rslot_limit) + goto bad; + + comp->flags &=~ SLF_TOSS; + comp->recv_current = x; + } else { + /* this packet has an implicit state index. If we've + * had a line error since the last time we got an + * explicit state index, we have to toss the packet. */ + if(comp->flags & SLF_TOSS){ + comp->sls_i_tossed++; + return 0; + } + } + cs = &comp->rstate[comp->recv_current]; + thp = &cs->cs_tcp; + ip = &cs->cs_ip; + + thp->check = *(__sum16 *)cp; + cp += 2; + + thp->psh = (changes & TCP_PUSH_BIT) ? 1 : 0; +/* + * we can use the same number for the length of the saved header and + * the current one, because the packet wouldn't have been sent + * as compressed unless the options were the same as the previous one + */ + + hdrlen = ip->ihl * 4 + thp->doff * 4; + + switch(changes & SPECIALS_MASK){ + case SPECIAL_I: /* Echoed terminal traffic */ + { + register short i; + i = ntohs(ip->tot_len) - hdrlen; + thp->ack_seq = htonl( ntohl(thp->ack_seq) + i); + thp->seq = htonl( ntohl(thp->seq) + i); + } + break; + + case SPECIAL_D: /* Unidirectional data */ + thp->seq = htonl( ntohl(thp->seq) + + ntohs(ip->tot_len) - hdrlen); + break; + + default: + if(changes & NEW_U){ + thp->urg = 1; + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->urg_ptr = htons(x); + } else + thp->urg = 0; + if(changes & NEW_W){ + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->window = htons( ntohs(thp->window) + x); + } + if(changes & NEW_A){ + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->ack_seq = htonl( ntohl(thp->ack_seq) + x); + } + if(changes & NEW_S){ + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->seq = htonl( ntohl(thp->seq) + x); + } + break; + } + if(changes & NEW_I){ + if((x = decode(&cp)) == -1) { + goto bad; + } + ip->id = htons (ntohs (ip->id) + x); + } else + ip->id = htons (ntohs (ip->id) + 1); + + /* + * At this point, cp points to the first byte of data in the + * packet. Put the reconstructed TCP and IP headers back on the + * packet. Recalculate IP checksum (but not TCP checksum). + */ + + len = isize - (cp - icp); + if (len < 0) + goto bad; + len += hdrlen; + ip->tot_len = htons(len); + ip->check = 0; + + memmove(icp + hdrlen, cp, len - hdrlen); + + cp = icp; + memcpy(cp, ip, 20); + cp += 20; + + if (ip->ihl > 5) { + memcpy(cp, cs->cs_ipopt, (ip->ihl - 5) * 4); + cp += (ip->ihl - 5) * 4; + } + + put_unaligned(ip_fast_csum(icp, ip->ihl), + &((struct iphdr *)icp)->check); + + memcpy(cp, thp, 20); + cp += 20; + + if (thp->doff > 5) { + memcpy(cp, cs->cs_tcpopt, ((thp->doff) - 5) * 4); + cp += ((thp->doff) - 5) * 4; + } + + return len; +bad: + comp->sls_i_error++; + return slhc_toss( comp ); +} + + +int +slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +{ + register struct cstate *cs; + unsigned ihl; + + unsigned char index; + + if(isize < 20) { + /* The packet is shorter than a legal IP header */ + comp->sls_i_runt++; + return slhc_toss( comp ); + } + /* Peek at the IP header's IHL field to find its length */ + ihl = icp[0] & 0xf; + if(ihl < 20 / 4){ + /* The IP header length field is too small */ + comp->sls_i_runt++; + return slhc_toss( comp ); + } + index = icp[9]; + icp[9] = IPPROTO_TCP; + + if (ip_fast_csum(icp, ihl)) { + /* Bad IP header checksum; discard */ + comp->sls_i_badcheck++; + return slhc_toss( comp ); + } + if(index > comp->rslot_limit) { + comp->sls_i_error++; + return slhc_toss(comp); + } + + /* Update local state */ + cs = &comp->rstate[comp->recv_current = index]; + comp->flags &=~ SLF_TOSS; + memcpy(&cs->cs_ip,icp,20); + memcpy(&cs->cs_tcp,icp + ihl*4,20); + if (ihl > 5) + memcpy(cs->cs_ipopt, icp + sizeof(struct iphdr), (ihl - 5) * 4); + if (cs->cs_tcp.doff > 5) + memcpy(cs->cs_tcpopt, icp + ihl*4 + sizeof(struct tcphdr), (cs->cs_tcp.doff - 5) * 4); + cs->cs_hsize = ihl*2 + cs->cs_tcp.doff*2; + /* Put headers back on packet + * Neither header checksum is recalculated + */ + comp->sls_i_uncompressed++; + return isize; +} + +int +slhc_toss(struct slcompress *comp) +{ + if ( comp == NULLSLCOMPR ) + return 0; + + comp->flags |= SLF_TOSS; + return 0; +} + +#else /* CONFIG_INET */ + +int +slhc_toss(struct slcompress *comp) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss"); + return -EINVAL; +} +int +slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress"); + return -EINVAL; +} +int +slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, + unsigned char *ocp, unsigned char **cpp, int compress_cid) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress"); + return -EINVAL; +} + +int +slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember"); + return -EINVAL; +} + +void +slhc_free(struct slcompress *comp) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free"); +} +struct slcompress * +slhc_init(int rslots, int tslots) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init"); + return NULL; +} + +#endif /* CONFIG_INET */ + +/* VJ header compression */ +EXPORT_SYMBOL(slhc_init); +EXPORT_SYMBOL(slhc_free); +EXPORT_SYMBOL(slhc_remember); +EXPORT_SYMBOL(slhc_compress); +EXPORT_SYMBOL(slhc_uncompress); +EXPORT_SYMBOL(slhc_toss); + +MODULE_LICENSE("Dual BSD/GPL"); -- To view, visit https://gerrit.osmocom.org/634 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ied69c143678dc4a64cecc671f5c4dfebe19d8519 Gerrit-PatchSet: 8 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Tue Aug 16 15:37:37 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Tue, 16 Aug 2016 15:37:37 +0000 Subject: [PATCH] openbsc[master]: SLHC (RFC1144 header compression) integration In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/635 to look at the new patch set (#8). SLHC (RFC1144 header compression) integration The previously pushed slhc implementation has been modified to compile and function outside of the kernel. Also debug log messages were added and datatypes ware matched. The implementation is now ready to be used Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 --- M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/debug.h R openbsc/include/openbsc/slhc.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/slhc.c M openbsc/tests/sgsn/Makefile.am 6 files changed, 115 insertions(+), 89 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/35/635/8 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index e200b05..f402fea 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,8 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h + gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ + slhc.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 43ebb19..90ddca5 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -29,6 +29,7 @@ DBSSGP, DLLC, DSNDCP, + DSLHC, DNAT, DCTRL, DSMPP, diff --git a/openbsc/include/openbsc/slhc_vj.h b/openbsc/include/openbsc/slhc.h similarity index 97% rename from openbsc/include/openbsc/slhc_vj.h rename to openbsc/include/openbsc/slhc.h index 8716d59..cd5a47c 100644 --- a/openbsc/include/openbsc/slhc_vj.h +++ b/openbsc/include/openbsc/slhc.h @@ -171,7 +171,8 @@ #define NULLSLCOMPR (struct slcompress *)0 /* In slhc.c: */ -struct slcompress *slhc_init(int rslots, int tslots); +struct slcompress *slhc_init(const void *ctx, int rslots, int tslots); + void slhc_free(struct slcompress *comp); int slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, @@ -180,4 +181,7 @@ int slhc_remember(struct slcompress *comp, unsigned char *icp, int isize); int slhc_toss(struct slcompress *comp); +void slhc_i_status(struct slcompress *comp); +void slhc_o_status(struct slcompress *comp); + #endif /* _SLHC_H */ diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index fa4a3dd..245636b 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -26,7 +26,8 @@ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ - oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c + oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ + slhc.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/slhc.c b/openbsc/src/gprs/slhc.c index 27ed252..ed095f9 100644 --- a/openbsc/src/gprs/slhc.c +++ b/openbsc/src/gprs/slhc.c @@ -50,61 +50,77 @@ * driver code belonging close to PPP and SLIP */ -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#ifdef CONFIG_INET -/* Entire module is for IP only */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#define ERR_PTR(x) x + static unsigned char *encode(unsigned char *cp, unsigned short n); static long decode(unsigned char **cpp); static unsigned char * put16(unsigned char *cp, unsigned short x); static unsigned short pull16(unsigned char **cpp); +/* Replacement for kernel space function ip_fast_csum() */ +static uint16_t ip_fast_csum(uint8_t *iph, int ihl) +{ + int i; + uint16_t temp; + uint32_t accumulator = 0xFFFF; + + for(i=0;i0xFFFF) + { + accumulator++; + accumulator&=0xFFFF; + } + } + + return (uint16_t)(htons(~accumulator)&0xFFFF); +} + +/* Replacement for kernel space function put_unaligned() */ +static void put_unaligned(uint16_t val, void *ptr) +{ + memcpy(ptr,&val,sizeof(val)); +} + + /* Allocate compression data structure * slots must be in range 0 to 255 (zero meaning no compression) * Returns pointer to structure or ERR_PTR() on error. */ struct slcompress * -slhc_init(int rslots, int tslots) +slhc_init(const void *ctx, int rslots, int tslots) { register short i; register struct cstate *ts; struct slcompress *comp; if (rslots < 0 || rslots > 255 || tslots < 0 || tslots > 255) - return ERR_PTR(-EINVAL); + return NULL; - comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL); + comp = (struct slcompress *)talloc_zero_size(ctx,sizeof(struct slcompress)); if (! comp) goto out_fail; if (rslots > 0) { size_t rsize = rslots * sizeof(struct cstate); - comp->rstate = kzalloc(rsize, GFP_KERNEL); + comp->rstate = (struct cstate *) talloc_zero_size(ctx, rsize); if (! comp->rstate) goto out_free; comp->rslot_limit = rslots - 1; @@ -112,7 +128,7 @@ if (tslots > 0) { size_t tsize = tslots * sizeof(struct cstate); - comp->tstate = kzalloc(tsize, GFP_KERNEL); + comp->tstate = (struct cstate *) talloc_zero_size(ctx, tsize); if (! comp->tstate) goto out_free2; comp->tslot_limit = tslots - 1; @@ -141,11 +157,11 @@ return comp; out_free2: - kfree(comp->rstate); + talloc_free(comp->rstate); out_free: - kfree(comp); + talloc_free(comp); out_fail: - return ERR_PTR(-ENOMEM); + return NULL; } @@ -153,16 +169,18 @@ void slhc_free(struct slcompress *comp) { + LOGP(DSLHC, LOGL_DEBUG, "slhc_free(): Freeing compression states...\n"); + if ( comp == NULLSLCOMPR ) return; if ( comp->tstate != NULLSLSTATE ) - kfree( comp->tstate ); + talloc_free(comp->tstate ); if ( comp->rstate != NULLSLSTATE ) - kfree( comp->rstate ); + talloc_free( comp->rstate ); - kfree( comp ); + talloc_free( comp ); } @@ -256,6 +274,7 @@ comp->sls_o_nontcp++; else comp->sls_o_tcp++; + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Not a TCP packat, will not touch...\n"); return isize; } /* Extract TCP header */ @@ -271,6 +290,7 @@ ! (th->ack)){ /* TCP connection stuff; send as regular IP */ comp->sls_o_tcp++; + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Packet is part of a TCP connection, will not touch...\n"); return isize; } /* @@ -287,6 +307,9 @@ * states via linear search. If we don't find a state * for the datagram, the oldest state is (re-)used. */ + + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Compressible packet detected!\n"); + for ( ; ; ) { if( ip->saddr == cs->cs_ip.saddr && ip->daddr == cs->cs_ip.daddr @@ -310,11 +333,14 @@ * state points to the newest and we only need to set * xmit_oldest to update the lru linkage. */ + + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Header not yet seen, will memorize header for the next turn...\n"); comp->sls_o_misses++; comp->xmit_oldest = lcs->cs_this; goto uncompressed; found: + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Header already seen, trying to compress...\n"); /* * Found it -- move to the front on the connection list. */ @@ -351,6 +377,7 @@ || th->doff != cs->cs_tcp.doff || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){ + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): The header contains unexpected changes, can't compress...\n"); goto uncompressed; } @@ -369,6 +396,7 @@ * implementation should never do this but RFC793 * doesn't prohibit the change so we have to deal * with it. */ + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): URG not set but urp changed, can't compress...\n"); goto uncompressed; } if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){ @@ -376,14 +404,18 @@ changes |= NEW_W; } if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){ - if(deltaA > 0x0000ffff) + if(deltaA > 0x0000ffff) { + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): (deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L, can't compress...\n"); goto uncompressed; + } cp = encode(cp,deltaA); changes |= NEW_A; } if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){ - if(deltaS > 0x0000ffff) + if(deltaS > 0x0000ffff) { + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): (deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L, can't compress...\n"); goto uncompressed; + } cp = encode(cp,deltaS); changes |= NEW_S; } @@ -399,12 +431,14 @@ if(ip->tot_len != cs->cs_ip.tot_len && ntohs(cs->cs_ip.tot_len) == hlen) break; + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Retransmitted packet detected, can't compress...\n"); goto uncompressed; case SPECIAL_I: case SPECIAL_D: /* actual changes match one of our special case encodings -- * send packet uncompressed. */ + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Special case detected, can't compress...\n"); goto uncompressed; case NEW_S|NEW_A: if(deltaS == deltaA && @@ -467,6 +501,7 @@ * to use on future compressed packets in the protocol field). */ uncompressed: + LOGP(DSLHC, LOGL_DEBUG, "slhc_compress(): Packet will be sent uncompressed...\n"); memcpy(&cs->cs_ip,ip,20); memcpy(&cs->cs_tcp,th,20); if (ip->ihl > 5) @@ -538,6 +573,8 @@ switch(changes & SPECIALS_MASK){ case SPECIAL_I: /* Echoed terminal traffic */ + LOGP(DSLHC, LOGL_DEBUG, "slhc_uncompress(): Echoed terminal traffic detected\n"); + { register short i; i = ntohs(ip->tot_len) - hdrlen; @@ -547,11 +584,13 @@ break; case SPECIAL_D: /* Unidirectional data */ + LOGP(DSLHC, LOGL_DEBUG, "slhc_uncompress(): Unidirectional data detected\n"); thp->seq = htonl( ntohl(thp->seq) + ntohs(ip->tot_len) - hdrlen); break; default: + LOGP(DSLHC, LOGL_DEBUG, "slhc_uncompress(): default packet type detected\n"); if(changes & NEW_U){ thp->urg = 1; if((x = decode(&cp)) == -1) { @@ -601,6 +640,7 @@ ip->tot_len = htons(len); ip->check = 0; + LOGP(DSLHC, LOGL_DEBUG, "slhc_uncompress(): making space for the reconstructed header...\n"); memmove(icp + hdrlen, cp, len - hdrlen); cp = icp; @@ -625,6 +665,7 @@ return len; bad: + LOGP(DSLHC, LOGL_DEBUG, "slhc_uncompress(): bad packet detected!\n"); comp->sls_i_error++; return slhc_toss( comp ); } @@ -641,6 +682,7 @@ if(isize < 20) { /* The packet is shorter than a legal IP header */ comp->sls_i_runt++; + LOGP(DSLHC, LOGL_DEBUG, "slhc_remember(): The packet is shorter than a legal IP header ==> slhc_toss()\n"); return slhc_toss( comp ); } /* Peek at the IP header's IHL field to find its length */ @@ -648,6 +690,7 @@ if(ihl < 20 / 4){ /* The IP header length field is too small */ comp->sls_i_runt++; + LOGP(DSLHC, LOGL_DEBUG, "slhc_remember(): The IP header length field is too small ==> slhc_toss()\n"); return slhc_toss( comp ); } index = icp[9]; @@ -656,10 +699,12 @@ if (ip_fast_csum(icp, ihl)) { /* Bad IP header checksum; discard */ comp->sls_i_badcheck++; + LOGP(DSLHC, LOGL_DEBUG, "slhc_remember(): Bad IP header checksum; discard ==> slhc_toss()\n"); return slhc_toss( comp ); } if(index > comp->rslot_limit) { comp->sls_i_error++; + LOGP(DSLHC, LOGL_DEBUG, "slhc_remember(): index > comp->rslot_limit ==> slhc_toss()\n"); return slhc_toss(comp); } @@ -683,6 +728,7 @@ int slhc_toss(struct slcompress *comp) { + LOGP(DSLHC, LOGL_DEBUG, "slhc_toss(): Reset compression state...\n"); if ( comp == NULLSLCOMPR ) return 0; @@ -690,55 +736,27 @@ return 0; } -#else /* CONFIG_INET */ - -int -slhc_toss(struct slcompress *comp) +void slhc_i_status(struct slcompress *comp) { - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss"); - return -EINVAL; -} -int -slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress"); - return -EINVAL; -} -int -slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, - unsigned char *ocp, unsigned char **cpp, int compress_cid) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress"); - return -EINVAL; + if (comp != NULLSLCOMPR) { + LOGP(DSLHC, LOGL_DEBUG, "slhc_i_status(): %d Cmp, %d Uncmp, %d Bad, %d Tossed\n", + comp->sls_i_compressed, + comp->sls_i_uncompressed, + comp->sls_i_error, + comp->sls_i_tossed); + } } -int -slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +void slhc_o_status(struct slcompress *comp) { - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember"); - return -EINVAL; + if (comp != NULLSLCOMPR) { + LOGP(DSLHC, LOGL_DEBUG, "slhc_o_status(): %d Cmp, %d Uncmp, %d AsIs, %d NotTCP %d Searches, %d Misses\n", + comp->sls_o_compressed, + comp->sls_o_uncompressed, + comp->sls_o_tcp, + comp->sls_o_nontcp, + comp->sls_o_searches, + comp->sls_o_misses); + } } -void -slhc_free(struct slcompress *comp) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free"); -} -struct slcompress * -slhc_init(int rslots, int tslots) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init"); - return NULL; -} - -#endif /* CONFIG_INET */ - -/* VJ header compression */ -EXPORT_SYMBOL(slhc_init); -EXPORT_SYMBOL(slhc_free); -EXPORT_SYMBOL(slhc_remember); -EXPORT_SYMBOL(slhc_compress); -EXPORT_SYMBOL(slhc_uncompress); -EXPORT_SYMBOL(slhc_toss); - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 45d1780..3e66978 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -32,6 +32,7 @@ $(top_builddir)/src/gprs/oap_messages.o \ $(top_builddir)/src/gprs/gprs_llc_xid.o \ $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ + $(top_builddir)/src/gprs/slhc.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ -- To view, visit https://gerrit.osmocom.org/635 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 Gerrit-PatchSet: 8 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Tue Aug 16 16:10:24 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Tue, 16 Aug 2016 16:10:24 +0000 Subject: [PATCH] openbsc[master]: SLHC (RFC1144 header compression) integration In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/635 to look at the new patch set (#9). SLHC (RFC1144 header compression) integration The previously pushed slhc implementation has been modified to compile and function outside of the kernel. Also debug log messages were added and datatypes ware matched. The implementation is now ready to be used Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 --- M openbsc/.gitignore M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/debug.h R openbsc/include/openbsc/slhc.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/slhc.c M openbsc/tests/Makefile.am M openbsc/tests/sgsn/Makefile.am A openbsc/tests/slhc/Makefile.am A openbsc/tests/slhc/packets.txt A openbsc/tests/slhc/slhc_test.c A openbsc/tests/slhc/slhc_test.ok M openbsc/tests/testsuite.at 14 files changed, 576 insertions(+), 91 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/35/635/9 diff --git a/openbsc/.gitignore b/openbsc/.gitignore index 8ce3b70..e75b9eb 100644 --- a/openbsc/.gitignore +++ b/openbsc/.gitignore @@ -83,6 +83,7 @@ tests/mm_auth/mm_auth_test tests/xid/xid_test tests/sndcp_xid/sndcp_xid_test +tests/slhc/slhc_test tests/atconfig tests/atlocal diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 53072bd..18980b0 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -231,6 +231,7 @@ tests/mm_auth/Makefile tests/xid/Makefile tests/sndcp_xid/Makefile + tests/slhc/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index e200b05..f402fea 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,8 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h + gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ + slhc.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 43ebb19..90ddca5 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -29,6 +29,7 @@ DBSSGP, DLLC, DSNDCP, + DSLHC, DNAT, DCTRL, DSMPP, diff --git a/openbsc/include/openbsc/slhc_vj.h b/openbsc/include/openbsc/slhc.h similarity index 97% rename from openbsc/include/openbsc/slhc_vj.h rename to openbsc/include/openbsc/slhc.h index 8716d59..cd5a47c 100644 --- a/openbsc/include/openbsc/slhc_vj.h +++ b/openbsc/include/openbsc/slhc.h @@ -171,7 +171,8 @@ #define NULLSLCOMPR (struct slcompress *)0 /* In slhc.c: */ -struct slcompress *slhc_init(int rslots, int tslots); +struct slcompress *slhc_init(const void *ctx, int rslots, int tslots); + void slhc_free(struct slcompress *comp); int slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, @@ -180,4 +181,7 @@ int slhc_remember(struct slcompress *comp, unsigned char *icp, int isize); int slhc_toss(struct slcompress *comp); +void slhc_i_status(struct slcompress *comp); +void slhc_o_status(struct slcompress *comp); + #endif /* _SLHC_H */ diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index fa4a3dd..245636b 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -26,7 +26,8 @@ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ - oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c + oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ + slhc.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/slhc.c b/openbsc/src/gprs/slhc.c index 27ed252..cbdf8db 100644 --- a/openbsc/src/gprs/slhc.c +++ b/openbsc/src/gprs/slhc.c @@ -50,61 +50,77 @@ * driver code belonging close to PPP and SLIP */ -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#ifdef CONFIG_INET -/* Entire module is for IP only */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#define ERR_PTR(x) x + static unsigned char *encode(unsigned char *cp, unsigned short n); static long decode(unsigned char **cpp); static unsigned char * put16(unsigned char *cp, unsigned short x); static unsigned short pull16(unsigned char **cpp); +/* Replacement for kernel space function ip_fast_csum() */ +static uint16_t ip_fast_csum(uint8_t *iph, int ihl) +{ + int i; + uint16_t temp; + uint32_t accumulator = 0xFFFF; + + for(i=0;i0xFFFF) + { + accumulator++; + accumulator&=0xFFFF; + } + } + + return (uint16_t)(htons(~accumulator)&0xFFFF); +} + +/* Replacement for kernel space function put_unaligned() */ +static void put_unaligned(uint16_t val, void *ptr) +{ + memcpy(ptr,&val,sizeof(val)); +} + + /* Allocate compression data structure * slots must be in range 0 to 255 (zero meaning no compression) * Returns pointer to structure or ERR_PTR() on error. */ struct slcompress * -slhc_init(int rslots, int tslots) +slhc_init(const void *ctx, int rslots, int tslots) { register short i; register struct cstate *ts; struct slcompress *comp; if (rslots < 0 || rslots > 255 || tslots < 0 || tslots > 255) - return ERR_PTR(-EINVAL); + return NULL; - comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL); + comp = (struct slcompress *)talloc_zero_size(ctx,sizeof(struct slcompress)); if (! comp) goto out_fail; if (rslots > 0) { size_t rsize = rslots * sizeof(struct cstate); - comp->rstate = kzalloc(rsize, GFP_KERNEL); + comp->rstate = (struct cstate *) talloc_zero_size(ctx, rsize); if (! comp->rstate) goto out_free; comp->rslot_limit = rslots - 1; @@ -112,7 +128,7 @@ if (tslots > 0) { size_t tsize = tslots * sizeof(struct cstate); - comp->tstate = kzalloc(tsize, GFP_KERNEL); + comp->tstate = (struct cstate *) talloc_zero_size(ctx, tsize); if (! comp->tstate) goto out_free2; comp->tslot_limit = tslots - 1; @@ -141,11 +157,11 @@ return comp; out_free2: - kfree(comp->rstate); + talloc_free(comp->rstate); out_free: - kfree(comp); + talloc_free(comp); out_fail: - return ERR_PTR(-ENOMEM); + return NULL; } @@ -153,16 +169,18 @@ void slhc_free(struct slcompress *comp) { + DEBUGP(DSLHC, "slhc_free(): Freeing compression states...\n"); + if ( comp == NULLSLCOMPR ) return; if ( comp->tstate != NULLSLSTATE ) - kfree( comp->tstate ); + talloc_free(comp->tstate ); if ( comp->rstate != NULLSLSTATE ) - kfree( comp->rstate ); + talloc_free( comp->rstate ); - kfree( comp ); + talloc_free( comp ); } @@ -187,6 +205,8 @@ } else { *cp++ = n; } + + DEBUGP(DSLHC, "encode(): n=%04x\n",n); return cp; } @@ -256,6 +276,7 @@ comp->sls_o_nontcp++; else comp->sls_o_tcp++; + DEBUGP(DSLHC, "slhc_compress(): Not a TCP packat, will not touch...\n"); return isize; } /* Extract TCP header */ @@ -271,6 +292,7 @@ ! (th->ack)){ /* TCP connection stuff; send as regular IP */ comp->sls_o_tcp++; + DEBUGP(DSLHC, "slhc_compress(): Packet is part of a TCP connection, will not touch...\n"); return isize; } /* @@ -287,6 +309,9 @@ * states via linear search. If we don't find a state * for the datagram, the oldest state is (re-)used. */ + + DEBUGP(DSLHC, "slhc_compress(): Compressible packet detected!\n"); + for ( ; ; ) { if( ip->saddr == cs->cs_ip.saddr && ip->daddr == cs->cs_ip.daddr @@ -310,11 +335,14 @@ * state points to the newest and we only need to set * xmit_oldest to update the lru linkage. */ + + DEBUGP(DSLHC, "slhc_compress(): Header not yet seen, will memorize header for the next turn...\n"); comp->sls_o_misses++; comp->xmit_oldest = lcs->cs_this; goto uncompressed; found: + DEBUGP(DSLHC, "slhc_compress(): Header already seen, trying to compress...\n"); /* * Found it -- move to the front on the connection list. */ @@ -344,6 +372,39 @@ */ oth = &cs->cs_tcp; + /* Display a little more debug information about which of the + * header fields changed unexpectedly */ + if(ip->version != cs->cs_ip.version) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->version != cs->cs_ip.version\n"); + if(ip->ihl != cs->cs_ip.ihl) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->ihl != cs->cs_ip.ihl\n"); + if(ip->tos != cs->cs_ip.tos) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->tos != cs->cs_ip.tos\n"); + if((ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))\n"); + if(ip->ttl != cs->cs_ip.ttl) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->ttl != cs->cs_ip.ttl\n"); + if(th->doff != cs->cs_tcp.doff) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: th->doff != cs->cs_tcp.doff\n"); + if(ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) { + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0)\n"); + DEBUGP(DSLHC, "slhc_compress(): ip->ihl = %i\n", ip->ihl); + DEBUGP(DSLHC, "slhc_compress(): ip+1 = %s\n", + osmo_hexdump_nospc((uint8_t*)(ip+1),((ip->ihl)-5)*4)); + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: cs->cs_ipopt = %s\n", + osmo_hexdump_nospc((uint8_t*)(cs->cs_ipopt),((ip->ihl)-5)*4)); + } + if(th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0) { + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)\n"); + DEBUGP(DSLHC, "slhc_compress(): th->doff = %i\n", th->doff); + DEBUGP(DSLHC, "slhc_compress(): th+1 = %s\n", + osmo_hexdump_nospc((uint8_t*)(th+1),((th->doff)-5)*4)); + DEBUGP(DSLHC, "slhc_compress(): cs->cs_tcpopt = %s\n", + osmo_hexdump_nospc((uint8_t*)cs->cs_tcpopt, + ((th->doff)-5)*4)); + } + + if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl || ip->tos != cs->cs_ip.tos || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000)) @@ -351,6 +412,7 @@ || th->doff != cs->cs_tcp.doff || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){ + DEBUGP(DSLHC, "slhc_compress(): The header contains unexpected changes, can't compress...\n"); goto uncompressed; } @@ -362,6 +424,7 @@ */ if(th->urg){ deltaS = ntohs(th->urg_ptr); + DEBUGP(DSLHC, "slhc_compress(): flag: Urgent Pointer (U) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_U; } else if(th->urg_ptr != oth->urg_ptr){ @@ -369,21 +432,29 @@ * implementation should never do this but RFC793 * doesn't prohibit the change so we have to deal * with it. */ + DEBUGP(DSLHC, "slhc_compress(): URG not set but urp changed, can't compress...\n"); goto uncompressed; } if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){ + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Window (W) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_W; } if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){ - if(deltaA > 0x0000ffff) + if(deltaA > 0x0000ffff) { + DEBUGP(DSLHC, "slhc_compress(): (deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L, can't compress...\n"); goto uncompressed; + } + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Ack (A) = 1\n"); cp = encode(cp,deltaA); changes |= NEW_A; } if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){ - if(deltaS > 0x0000ffff) + if(deltaS > 0x0000ffff) { + DEBUGP(DSLHC, "slhc_compress(): (deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L, can't compress...\n"); goto uncompressed; + } + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_S; } @@ -399,17 +470,21 @@ if(ip->tot_len != cs->cs_ip.tot_len && ntohs(cs->cs_ip.tot_len) == hlen) break; + DEBUGP(DSLHC, "slhc_compress(): Retransmitted packet detected, can't compress...\n"); goto uncompressed; case SPECIAL_I: case SPECIAL_D: /* actual changes match one of our special case encodings -- * send packet uncompressed. */ + DEBUGP(DSLHC, "slhc_compress(): Special case detected, can't compress...\n"); goto uncompressed; case NEW_S|NEW_A: if(deltaS == deltaA && deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ /* special case for echoed terminal traffic */ + DEBUGP(DSLHC, "slhc_compress(): Special case for echoed terminal traffic detected...\n"); + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1, Delta Window (W) = 1, Urgent Pointer (U) = 1\n"); changes = SPECIAL_I; cp = new_seq; } @@ -417,6 +492,8 @@ case NEW_S: if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ /* special case for data xfer */ + DEBUGP(DSLHC, "slhc_compress(): Special case for data xfer detected...\n"); + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1, Delta Ack (A) = 1, Delta Window (W) = 1, Urgent Pointer (U) = 1\n"); changes = SPECIAL_D; cp = new_seq; } @@ -424,11 +501,14 @@ } deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id); if(deltaS != 1){ + DEBUGP(DSLHC, "slhc_compress(): flag: Delta IP ID (I) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_I; } - if(th->psh) + if(th->psh) { + DEBUGP(DSLHC, "slhc_compress(): flag: Push (P) = 1\n"); changes |= TCP_PUSH_BIT; + } /* Grab the cksum before we overwrite it below. Then update our * state with this packet's header. */ @@ -445,6 +525,7 @@ if(compress_cid == 0 || comp->xmit_current != cs->cs_this){ cp = ocp; *cpp = ocp; + DEBUGP(DSLHC, "slhc_compress(): flag: Connection number (C) = 1\n"); *cp++ = changes | NEW_C; *cp++ = cs->cs_this; comp->xmit_current = cs->cs_this; @@ -456,6 +537,10 @@ *(__sum16 *)cp = csum; cp += 2; /* deltaS is now the size of the change section of the compressed header */ + + DEBUGP(DSLHC, "slhc_compress(): Delta-list length (deltaS) = %li\n",deltaS); + DEBUGP(DSLHC, "slhc_compress(): Original header len (hlen) = %i\n",hlen); + memcpy(cp,new_seq,deltaS); /* Write list of deltas */ memcpy(cp+deltaS,icp+hlen,isize-hlen); comp->sls_o_compressed++; @@ -467,6 +552,7 @@ * to use on future compressed packets in the protocol field). */ uncompressed: + DEBUGP(DSLHC, "slhc_compress(): Packet will be sent uncompressed...\n"); memcpy(&cs->cs_ip,ip,20); memcpy(&cs->cs_tcp,th,20); if (ip->ihl > 5) @@ -538,6 +624,8 @@ switch(changes & SPECIALS_MASK){ case SPECIAL_I: /* Echoed terminal traffic */ + DEBUGP(DSLHC, "slhc_uncompress(): Echoed terminal traffic detected\n"); + { register short i; i = ntohs(ip->tot_len) - hdrlen; @@ -547,11 +635,13 @@ break; case SPECIAL_D: /* Unidirectional data */ + DEBUGP(DSLHC, "slhc_uncompress(): Unidirectional data detected\n"); thp->seq = htonl( ntohl(thp->seq) + ntohs(ip->tot_len) - hdrlen); break; default: + DEBUGP(DSLHC, "slhc_uncompress(): default packet type detected\n"); if(changes & NEW_U){ thp->urg = 1; if((x = decode(&cp)) == -1) { @@ -601,6 +691,7 @@ ip->tot_len = htons(len); ip->check = 0; + DEBUGP(DSLHC, "slhc_uncompress(): making space for the reconstructed header...\n"); memmove(icp + hdrlen, cp, len - hdrlen); cp = icp; @@ -625,6 +716,7 @@ return len; bad: + DEBUGP(DSLHC, "slhc_uncompress(): bad packet detected!\n"); comp->sls_i_error++; return slhc_toss( comp ); } @@ -641,6 +733,7 @@ if(isize < 20) { /* The packet is shorter than a legal IP header */ comp->sls_i_runt++; + DEBUGP(DSLHC, "slhc_remember(): The packet is shorter than a legal IP header ==> slhc_toss()\n"); return slhc_toss( comp ); } /* Peek at the IP header's IHL field to find its length */ @@ -648,6 +741,7 @@ if(ihl < 20 / 4){ /* The IP header length field is too small */ comp->sls_i_runt++; + DEBUGP(DSLHC, "slhc_remember(): The IP header length field is too small ==> slhc_toss()\n"); return slhc_toss( comp ); } index = icp[9]; @@ -656,10 +750,12 @@ if (ip_fast_csum(icp, ihl)) { /* Bad IP header checksum; discard */ comp->sls_i_badcheck++; + DEBUGP(DSLHC, "slhc_remember(): Bad IP header checksum; discard ==> slhc_toss()\n"); return slhc_toss( comp ); } if(index > comp->rslot_limit) { comp->sls_i_error++; + DEBUGP(DSLHC, "slhc_remember(): index > comp->rslot_limit ==> slhc_toss()\n"); return slhc_toss(comp); } @@ -683,6 +779,7 @@ int slhc_toss(struct slcompress *comp) { + DEBUGP(DSLHC, "slhc_toss(): Reset compression state...\n"); if ( comp == NULLSLCOMPR ) return 0; @@ -690,55 +787,27 @@ return 0; } -#else /* CONFIG_INET */ - -int -slhc_toss(struct slcompress *comp) +void slhc_i_status(struct slcompress *comp) { - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss"); - return -EINVAL; -} -int -slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress"); - return -EINVAL; -} -int -slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, - unsigned char *ocp, unsigned char **cpp, int compress_cid) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress"); - return -EINVAL; + if (comp != NULLSLCOMPR) { + DEBUGP(DSLHC, "slhc_i_status(): %d Cmp, %d Uncmp, %d Bad, %d Tossed\n", + comp->sls_i_compressed, + comp->sls_i_uncompressed, + comp->sls_i_error, + comp->sls_i_tossed); + } } -int -slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +void slhc_o_status(struct slcompress *comp) { - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember"); - return -EINVAL; + if (comp != NULLSLCOMPR) { + DEBUGP(DSLHC, "slhc_o_status(): %d Cmp, %d Uncmp, %d AsIs, %d NotTCP %d Searches, %d Misses\n", + comp->sls_o_compressed, + comp->sls_o_uncompressed, + comp->sls_o_tcp, + comp->sls_o_nontcp, + comp->sls_o_searches, + comp->sls_o_misses); + } } -void -slhc_free(struct slcompress *comp) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free"); -} -struct slcompress * -slhc_init(int rslots, int tslots) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init"); - return NULL; -} - -#endif /* CONFIG_INET */ - -/* VJ header compression */ -EXPORT_SYMBOL(slhc_init); -EXPORT_SYMBOL(slhc_free); -EXPORT_SYMBOL(slhc_remember); -EXPORT_SYMBOL(slhc_compress); -EXPORT_SYMBOL(slhc_uncompress); -EXPORT_SYMBOL(slhc_toss); - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index 1debb2d..d5aa356 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid slhc if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 45d1780..3e66978 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -32,6 +32,7 @@ $(top_builddir)/src/gprs/oap_messages.o \ $(top_builddir)/src/gprs/gprs_llc_xid.o \ $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ + $(top_builddir)/src/gprs/slhc.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ diff --git a/openbsc/tests/slhc/Makefile.am b/openbsc/tests/slhc/Makefile.am new file mode 100644 index 0000000..d21990f --- /dev/null +++ b/openbsc/tests/slhc/Makefile.am @@ -0,0 +1,21 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) + +EXTRA_DIST = slhc_test.ok + +noinst_PROGRAMS = slhc_test + +slhc_test_SOURCES = slhc_test.c + +slhc_test_LDADD = \ + $(top_builddir)/src/gprs/slhc.o \ + $(top_builddir)/src/libcommon/libcommon.a \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOGB_LIBS) \ + $(LIBCARES_LIBS) \ + $(LIBCRYPTO_LIBS) \ + -lgtp -lrt -lm + + diff --git a/openbsc/tests/slhc/packets.txt b/openbsc/tests/slhc/packets.txt new file mode 100644 index 0000000..9f7adeb --- /dev/null +++ b/openbsc/tests/slhc/packets.txt @@ -0,0 +1,6 @@ +4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 +4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 +4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 +4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 +4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a +4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20 diff --git a/openbsc/tests/slhc/slhc_test.c b/openbsc/tests/slhc/slhc_test.c new file mode 100644 index 0000000..41babae --- /dev/null +++ b/openbsc/tests/slhc/slhc_test.c @@ -0,0 +1,311 @@ +/* Test SLHC/RFC1144 TCP/IP Header compression/decompression */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include + +#include +#include + +#include + +#include +#include +#include + +/* Number of compression slots (S0-1) */ +#define SLOTS 8 + +/* Maximum packet bytes to display */ +#define DISP_MAX_BYTES 100 + +/* Compress a packet using Van Jacobson RFC1144 header compression */ +static int compress(uint8_t *data_o, uint8_t *data_i, int len, + struct slcompress *comp) +{ + uint8_t *comp_ptr; /* Not used */ + int compr_len; + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Run compressor */ + compr_len = slhc_compress(comp, data_i, len, data_o, &comp_ptr, 0); + return compr_len; +} + +/* Expand a packet using Van Jacobson RFC1144 header compression */ +static int expand(uint8_t *data_o, uint8_t *data_i, int len, + struct slcompress *comp) +{ + int data_decompressed_len; + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Handle an uncompressed packet (learn header information */ + if ((data_i[0] & SL_TYPE_UNCOMPRESSED_TCP) == SL_TYPE_UNCOMPRESSED_TCP) { + data_o[0] &= 0x4F; + data_decompressed_len = slhc_remember(comp, data_o, len); + return data_decompressed_len; + } + + /* Uncompress compressed packets */ + else if (data_o[0] & SL_TYPE_COMPRESSED_TCP) { + data_decompressed_len = slhc_uncompress(comp, data_o, len); + return data_decompressed_len; + } + + /* Regular or unknown packets will not be touched */ + return len; +} + +/* Calculate TCP/IP checksum */ +static uint16_t calc_ip_csum(uint8_t *data, int len) +{ + int i; + uint32_t accumulator = 0; + uint16_t *pointer = (uint16_t *) data; + + for (i = len; i > 1; i -= 2) { + accumulator += *pointer; + pointer++; + } + + if (len % 2) + accumulator += *pointer; + + accumulator = (accumulator & 0xffff) + ((accumulator >> 16) & 0xffff); + accumulator += (accumulator >> 16) & 0xffff; + return (~accumulator); +} + +/* Calculate TCP/IP checksum */ +static uint16_t calc_tcpip_csum(const void *ctx, uint8_t *packet, int len) +{ + uint8_t *buf; + uint16_t csum; + + buf = talloc_zero_size(ctx, len); + memset(buf, 0, len); + memcpy(buf, packet + 12, 8); + buf[9] = packet[9]; + buf[11] = (len - 20) & 0xFF; + buf[10] = (len - 20) >> 8 & 0xFF; + memcpy(buf + 12, packet + 20, len - 20); + csum = calc_ip_csum(buf, len - 20 + 12); + talloc_free(buf); + return csum; +} + +/* Check TCP/IP packet */ +static void check_packet(const void *ctx, uint8_t *packet, int len) +{ + /* Check IP header */ + OSMO_ASSERT(len > 20); + OSMO_ASSERT(calc_ip_csum(packet, 20) == 0); + + /* Check TCP packet */ + if (packet[9] != 0x06) + return; + OSMO_ASSERT(len > 40); + OSMO_ASSERT(calc_tcpip_csum(ctx, packet, len) == 0); +} + +/* Strip TCP options from TCP/IP packet */ +static int strip_tcp_options(const void *ctx, uint8_t *packet, int len) +{ + uint8_t doff; + uint16_t csum; + + /* Check if the packet can be handled here */ + if (len < 37) + return len; + if (packet[9] != 0x06) + return len; + + /* Strip TCP/IP options from packet */ + doff = ((packet[32] >> 4) & 0x0F) * 4; + memmove(packet + 40, packet + doff + 20, len - 40 - (doff - 20)); + len = len - (doff - 20); + + /* Repair data offset (TCP header length) */ + packet[32] &= 0x0F; + packet[32] |= 0x50; + + /* Repair checksum */ + packet[36] = 0; + packet[37] = 0; + csum = calc_tcpip_csum(ctx, packet, len); + packet[36] = csum & 0xFF; + packet[37] = csum >> 8 & 0xFF; + + /* Repair total length */ + packet[3] = len & 0xFF; + packet[2] = len >> 8 & 0xFF; + + /* Repair IP header checksum */ + packet[10] = 0; + packet[11] = 0; + csum = calc_ip_csum(packet, 20); + packet[10] = csum & 0xFF; + packet[11] = csum >> 8 & 0xFF; + printf("csum=%04x\n", csum); + + return len; +} + +/* osmo_hexparse() does not like line breaks, this fixes that */ +static void fixup_hexstring(char *str) +{ + int i; + for (i = 0; i < strlen(str); i++) { + if (str[i] == '\n') + str[i] = 0; + } +} + +/* Compress / Decompress packets */ +static void test_slhc(const void *ctx) +{ + char packet_ascii[2048]; + FILE *fd = NULL; + char *rc_fgets; + + struct slcompress *comp; + uint8_t packet[1024]; + int packet_len; + uint8_t packet_compr[1024]; + int packet_compr_len; + uint8_t packet_decompr[1024]; + int packet_decompr_len; + + + printf("Allocating compression state...\n"); + comp = slhc_init(ctx, SLOTS, SLOTS); + OSMO_ASSERT(comp); + + printf("Opening file with sample packets...\n"); + fd = fopen("packets.txt", "r"); + OSMO_ASSERT(fd) + printf("\n"); + + while (1) { + /* Read input file */ + memset(packet_ascii, 0, sizeof(packet_ascii)); + memset(packet, 0, sizeof(packet)); + memset(packet_compr, 0, sizeof(packet_compr)); + memset(packet_decompr, 0, sizeof(packet_decompr)); + printf("Reading packet from file...\n"); + rc_fgets = fgets(packet_ascii, sizeof(packet_ascii), fd); + if (rc_fgets == NULL || strlen(packet_ascii) < 20) { + printf("=> End of file detected, test done!\n\n"); + break; + } + fixup_hexstring(packet_ascii); + packet_len = + osmo_hexparse(packet_ascii, packet, sizeof(packet)); + check_packet(ctx, packet, packet_len); + packet_len = strip_tcp_options(ctx, packet, packet_len); + check_packet(ctx, packet, packet_len); + + /* Run compression/decompression algorithm */ + printf("Compressing...\n"); + packet_compr_len = + compress(packet_compr, packet, packet_len, comp); + printf("Decompressing...\n"); + packet_decompr_len = + expand(packet_decompr, packet_compr, packet_compr_len, + comp); + OSMO_ASSERT(packet_decompr_len == packet_len); + check_packet(ctx,packet_decompr,packet_decompr_len); + + /* Display results */ + printf("Results:\n"); + if (packet_compr_len > DISP_MAX_BYTES) + packet_compr_len = DISP_MAX_BYTES; + if (packet_len > DISP_MAX_BYTES) + packet_len = DISP_MAX_BYTES; + if (packet_decompr_len > DISP_MAX_BYTES) + packet_decompr_len = DISP_MAX_BYTES; + printf("Original Packet: (%i bytes) %s\n", packet_len, + osmo_hexdump_nospc(packet, packet_len)); + printf("DecompressedPacket: (%i bytes) %s\n", + packet_decompr_len, osmo_hexdump_nospc(packet_decompr, + packet_decompr_len)); + printf("CompressedPacket: (%i bytes) %s\n", packet_compr_len, + osmo_hexdump_nospc(packet_compr, packet_compr_len)); + slhc_o_status(comp); + slhc_o_status(comp); + + printf("\n"); + } + + printf("Freeing compression state...\n"); + slhc_free(comp); + printf("\n"); + fclose(fd); +} + +static struct log_info_cat gprs_categories[] = { + [DSNDCP] = { + .name = "DSNDCP", + .description = + "GPRS Sub-Network Dependent Control Protocol (SNDCP)", + .enabled = 1,.loglevel = LOGL_DEBUG, + }, + [DSLHC] = { + .name = "DSLHC", + .description = + "Van Jacobson RFC1144 TCP/IP header compression (SLHC)", + .enabled = 1,.loglevel = LOGL_DEBUG, + } +}; + +static struct log_info info = { + .cat = gprs_categories, + .num_cat = ARRAY_SIZE(gprs_categories), +}; + +int main(int argc, char **argv) +{ + void *ctx; + + osmo_init_logging(&info); + + ctx = talloc_named_const(NULL, 0, "slhc_ctx"); + + test_slhc(ctx); + + printf("Done\n"); + + talloc_report_full(ctx, stderr); + OSMO_ASSERT(talloc_total_blocks(ctx) == 1); + return 0; +} + +/* stubs */ +struct osmo_prim_hdr; +int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) +{ + abort(); +} diff --git a/openbsc/tests/slhc/slhc_test.ok b/openbsc/tests/slhc/slhc_test.ok new file mode 100644 index 0000000..3f802ea --- /dev/null +++ b/openbsc/tests/slhc/slhc_test.ok @@ -0,0 +1,63 @@ +Allocating compression state... +Opening file with sample packets... + +Reading packet from file... +csum=b3a9 +Compressing... +Decompressing... +Results: +Original Packet: (52 bytes) 4510003446dd40004006a9b3c0a8646ec0a864640017ad8b81980100f3ac984d501800e371410000fffd18fffd20fffd23fffd27 +DecompressedPacket: (52 bytes) 4510003446dd40004006a9b3c0a8646ec0a864640017ad8b81980100f3ac984d501800e371410000fffd18fffd20fffd23fffd27 +CompressedPacket: (52 bytes) 7510003446dd40004000a9b3c0a8646ec0a864640017ad8b81980100f3ac984d501800e371410000fffd18fffd20fffd23fffd27 + +Reading packet from file... +csum=97a9 +Compressing... +Decompressing... +Results: +Original Packet: (79 bytes) 4510004f46de40004006a997c0a8646ec0a864640017ad8b8198010cf3ac984d501800e3cda40000fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 +DecompressedPacket: (79 bytes) 4510004f46de40004006a997c0a8646ec0a864640017ad8b8198010cf3ac984d501800e3cda40000fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 +CompressedPacket: (43 bytes) df00cda4fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 + +Reading packet from file... +csum=baa9 +Compressing... +Decompressing... +Results: +Original Packet: (43 bytes) 4510002b46df40004006a9bac0a8646ec0a864640017ad8b81980133f3ac989f501800e3a70a0000fffd01 +DecompressedPacket: (43 bytes) 4510002b46df40004006a9bac0a8646ec0a864640017ad8b81980133f3ac989f501800e3a70a0000fffd01 +CompressedPacket: (9 bytes) dc00a70a5227fffd01 + +Reading packet from file... +csum=b9a9 +Compressing... +Decompressing... +Results: +Original Packet: (43 bytes) 4510002b46e040004006a9b9c0a8646ec0a864640017ad8b81980136f3ac98a2501800e3a7060000fffb01 +DecompressedPacket: (43 bytes) 4510002b46e040004006a9b9c0a8646ec0a864640017ad8b81980136f3ac98a2501800e3a7060000fffb01 +CompressedPacket: (7 bytes) db00a706fffb01 + +Reading packet from file... +csum=7ba9 +Compressing... +Decompressing... +Results: +Original Packet: (100 bytes) 4510006846e140004006a97bc0a8646ec0a864640017ad8b81980139f3ac98a5501800e3c2d000000d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d +DecompressedPacket: (100 bytes) 4510006846e140004006a97bc0a8646ec0a864640017ad8b81980139f3ac98a5501800e3c2d000000d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d +CompressedPacket: (68 bytes) db00c2d00d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a + +Reading packet from file... +csum=aca9 +Compressing... +Decompressing... +Results: +Original Packet: (54 bytes) 4510003646e240004006a9acc0a8646ec0a864640017ad8b81980179f3ac98a5501800e321fb0000706f6c6c7578206c6f67696e3a20 +DecompressedPacket: (54 bytes) 4510003646e240004006a9acc0a8646ec0a864640017ad8b81980179f3ac98a5501800e321fb0000706f6c6c7578206c6f67696e3a20 +CompressedPacket: (18 bytes) df0021fb706f6c6c7578206c6f67696e3a20 + +Reading packet from file... +=> End of file detected, test done! + +Freeing compression state... + +Done diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index 85a81d6..5f37b8e 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -136,3 +136,8 @@ AT_CHECK([$abs_top_builddir/tests/sndcp_xid/sndcp_xid_test], [], [expout], [ignore]) AT_CLEANUP +AT_SETUP([slhc]) +AT_KEYWORDS([slhc]) +cat $abs_srcdir/slhc/slhc_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/slhc/slhc_test], [], [expout], [ignore]) +AT_CLEANUP -- To view, visit https://gerrit.osmocom.org/635 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 Gerrit-PatchSet: 9 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Wed Aug 17 07:22:17 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Wed, 17 Aug 2016 07:22:17 +0000 Subject: [PATCH] osmo-pcu[master]: Describe the issue with EGPRS PUAN encoding Message-ID: Review at https://gerrit.osmocom.org/702 Describe the issue with EGPRS PUAN encoding Currently pcu doesn?t encode EGPRS PUAN message for VQ not equal to VR case. This patch describe the issue with initially sending the BSN 1 which generated the PUAN message as below 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b. Later Unit test frame work sends BSN 4 and PUAN generated is below 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b which is same as previous PUAN message. Please see the Generated test file. This is considerable issue with OTA. The assert in the test file needs to be corrected. Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 --- M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 3 files changed, 298 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/02/702/1 diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..54ff9af 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -618,6 +618,143 @@ &ulreq, tbf->poll_fn); } +static gprs_rlcmac_ul_tbf *puan_issue(BTS *the_bts, + uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, + uint8_t ms_class, uint8_t egprs_ms_class) +{ + GprsMs *ms; + uint32_t rach_fn = *fn - 51; + uint32_t sba_fn = *fn + 52; + uint8_t trx_no = 0; + int tfi = 0, i = 0; + gprs_rlcmac_ul_tbf *ul_tbf; + struct gprs_rlcmac_pdch *pdch; + gprs_rlcmac_bts *bts; + RlcMacUplink_t ulreq = {0}; + struct pcu_l1_meas meas; + struct gprs_rlc_ul_header_egprs_3 *egprs3 = NULL; + GprsCodingScheme cs; + + meas.set_rssi(31); + bts = the_bts->bts_data(); + + /* needed to set last_rts_fn in the PDCH object */ + request_dl_rlc_block(bts, trx_no, ts_no, fn); + + /* + * simulate RACH, this sends an Immediate + * Assignment Uplink on the AGCH + */ + the_bts->rcv_rach(0x73, rach_fn, qta); + + /* get next free TFI */ + tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1); + + /* fake a resource request */ + ulreq.u.MESSAGE_TYPE = MT_PACKET_RESOURCE_REQUEST; + ulreq.u.Packet_Resource_Request.PayloadType = GPRS_RLCMAC_CONTROL_BLOCK; + ulreq.u.Packet_Resource_Request.ID.UnionType = 1; /* != 0 */ + ulreq.u.Packet_Resource_Request.ID.u.TLLI = tlli; + ulreq.u.Packet_Resource_Request.Exist_MS_Radio_Access_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + Count_MS_RA_capability_value = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Exist_Multislot_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + Exist_GPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + GPRS_multislot_class = ms_class; + if (egprs_ms_class) { + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Multislot_capability.Exist_EGPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Multislot_capability.EGPRS_multislot_class = ms_class; + } + + send_ul_mac_block(the_bts, trx_no, ts_no, &ulreq, sba_fn); + + /* check the TBF */ + ul_tbf = the_bts->ul_tbf_by_tfi(tfi, trx_no, ts_no); + OSMO_ASSERT(ul_tbf != NULL); + OSMO_ASSERT(ul_tbf->ta() == qta / 4); + + /* send packet uplink assignment */ + *fn = sba_fn; + request_dl_rlc_block(ul_tbf, fn); + + /* send real acknowledgement */ + send_control_ack(ul_tbf); + + check_tbf(ul_tbf); + /* send fake data */ + uint8_t data_msg[42] = { + 0x00 | 0xf << 2, /* GPRS_RLCMAC_DATA_BLOCK << 6, CV = 15 */ + uint8_t(0 | (tfi << 1)), + uint8_t(1), /* BSN:7, E:1 */ + }; + + pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no]; + pdch->rcv_block(&data_msg[0], 23, *fn, &meas); + + ms = the_bts->ms_by_tlli(tlli); + OSMO_ASSERT(ms != NULL); + OSMO_ASSERT(ms->ta() == qta/4); + OSMO_ASSERT(ms->ul_tbf() == ul_tbf); + + /* + * TS 44.060, B.8.1 + * first seg received first, later second seg + */ + cs = GprsCodingScheme::MCS3; + egprs3 = (struct gprs_rlc_ul_header_egprs_3 *) data_msg; + egprs3->si = 0; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 1; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 0; + egprs3->pi = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + struct msgb *msg1 = ul_tbf->create_ul_ack(*fn, ts_no); + + egprs3->si = 0; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 4; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + struct msgb *msg2 = ul_tbf->create_ul_ack(*fn, ts_no); + + /* TODO: Need to modify the assert */ + OSMO_ASSERT(!memcmp(msg2->data, msg1->data, msg1->data_len)); + + return ul_tbf; +} + static gprs_rlcmac_ul_tbf *establish_ul_tbf_two_phase_spb(BTS *the_bts, uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, uint8_t ms_class, uint8_t egprs_ms_class) @@ -1631,6 +1768,41 @@ gprs_bssgp_destroy(); } +static void test_tbf_puan_issue(void) +{ + BTS the_bts; + int ts_no = 7; + uint32_t fn = 2654218; + uint16_t qta = 31; + uint32_t tlli = 0xf1223344; + const char *imsi = "0011223344"; + uint8_t ms_class = 1; + uint8_t egprs_ms_class = 1; + gprs_rlcmac_ul_tbf *ul_tbf; + GprsMs *ms; + uint8_t test_data[256]; + + printf("=== start %s ===\n", __func__); + + memset(test_data, 1, sizeof(test_data)); + + setup_bts(&the_bts, ts_no, 4); + the_bts.bts_data()->initial_mcs_dl = 9; + the_bts.bts_data()->egprs_enabled = 1; + + ul_tbf = puan_issue(&the_bts, ts_no, tlli, &fn, qta, + ms_class, egprs_ms_class); + + ms = ul_tbf->ms(); + fprintf(stderr, "Got '%s', TA=%d\n", ul_tbf->name(), ul_tbf->ta()); + fprintf(stderr, + "Got MS: TLLI = 0x%08x, TA = %d\n", ms->tlli(), ms->ta()); + + send_dl_data(&the_bts, tlli, imsi, test_data, sizeof(test_data)); + + printf("=== end %s ===\n", __func__); +} + static void test_tbf_egprs_two_phase_spb(void) { BTS the_bts; @@ -2071,6 +2243,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_puan_issue(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..aa8a087 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -5780,3 +5780,126 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654218 block=8 data=47 94 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +MS requests UL TBF on RACH, so we provide one: +MS requests single block allocation +RX: [PCU <- BTS] RACH qbit-ta=31 ra=0x73, Fn=2654167 (17,25,9), SBFn=2654270 +TX: Immediate Assignment Uplink (AGCH) + - TRX=0 (0) TS=7 TA=7 TSC=0 TFI=-1 USF=7 +Sending data request: trx=0 ts=0 sapi=2 arfcn=0 fn=0 block=0 data=2d 06 3f 10 0f 00 00 73 8b 29 07 00 c0 0c 5a 43 2b 2b 2b 2b 2b 2b 2b +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +MS requests UL TBF in packet resource request of single block, so we provide one: +MS supports EGPRS multislot class 1. +********** TBF starts here ********** +Allocating UL TBF: MS_CLASS=1/1 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 1 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 1 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign uplink TS=7 TFI=0 USF=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 00 +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=ASSIGN EGPRS) starting timer 3169. +Modifying MS object, UL TLLI: 0x00000000 -> 0xf1223344, not yet confirmed +Modifying MS object, TLLI = 0xf1223344, TA 0 -> 7 +Change control TS to 7 until assinment is complete. +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS)s start Packet Uplink Assignment (PACCH) ++++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++ +------------------------- TX : Packet Uplink Assignment ------------------------- +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS): Scheduling polling at FN 2654283 TS 7 +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS) changes state from ASSIGN to WAIT ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Scheduled UL Assignment polling on FN=2654283, TS=7 +Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) (TRX=0, TS=7) +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654270 block=8 data=4f 28 5e 24 46 68 90 f8 0a 39 00 00 88 00 08 2b 2b 2b 2b 2b 2b 2b 2b +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Packet Control Ack +TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) changes state from WAIT ASSIGN to FLOW +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=0 .. V(R)=0) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got CS-1 RLC data block: CV=15, BSN=0, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 0 storing in window (0..63) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 1 +- Taking block 0 out, raising V(Q) to 1 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=0 CV=15 +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1d 08 40 c1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=0, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=1) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=1, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 1 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 2 +- Taking block 1 out, raising V(Q) to 2 +- Assembling frames: (len=37) +-- Frame 1 starts at offset 0, length=37, is_complete=0 +- No gaps in received block, last block: BSN=1 CV=7 +Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) + - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 2, BOW, EOW +Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1d 20 40 c1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=0, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=2 .. V(R)=2) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=4, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 4 storing in window (2..65) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 5 +Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) + - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 5, BOW, EOW +Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got 'TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS)', TA=7 +Got MS: TLLI = 0xf1223344, TA = 7 +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=1/1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign downlink TS=7 TFI=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0xf1223344, TBF = TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 80 +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +Modifying MS object, TLLI: 0xf1223344 confirmed +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) [DOWNLINK] START +Modifying MS object, TLLI = 0xf1223344, IMSI '' -> '0011223344' +Send dowlink assignment on PACCH, because TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) exists +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) starting timer 0. +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) append diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..6b99857 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,5 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_puan_issue === +=== end test_tbf_puan_issue === -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Wed Aug 17 07:22:17 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Wed, 17 Aug 2016 07:22:17 +0000 Subject: [PATCH] osmo-pcu[master]: Fix the issue with PUAN encoding for EGPRS Message-ID: Review at https://gerrit.osmocom.org/703 Fix the issue with PUAN encoding for EGPRS Earlier there was an incorrect encoding of PUAN when VQ is not equal VR case for EGPRS UL RLC window. The PCU was encoding the same PUAN message always irrespective of radio condition. This was a bottle neck for performance testing. Which has been fixed in this patch. Change-Id: Iba7b1995028bd81749ffb080616b2ad5f2540d57 --- M src/encoding.cpp M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err 3 files changed, 5 insertions(+), 5 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/03/703/1 diff --git a/src/encoding.cpp b/src/encoding.cpp index 63049ac..41e0d10 100644 --- a/src/encoding.cpp +++ b/src/encoding.cpp @@ -575,7 +575,8 @@ eow = false; urbb_len = rest_bits - 9; /* TODO: use compression (see above) */ - } + } else + urbb_len = num_blocks; if (urbb_len + crbb_len == rest_bits) len = -1; diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 54ff9af..bfac72e 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -749,8 +749,7 @@ struct msgb *msg2 = ul_tbf->create_ul_ack(*fn, ts_no); - /* TODO: Need to modify the assert */ - OSMO_ASSERT(!memcmp(msg2->data, msg1->data, msg1->data_len)); + OSMO_ASSERT(memcmp(msg2->data, msg1->data, msg1->data_len)); return ul_tbf; } diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index aa8a087..fa0927c 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -5875,8 +5875,8 @@ TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - Raising V(R) to 5 Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) - - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 5, BOW, EOW -Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b + - EGPRS URBB, len = 2, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 5, BOW, EOW +Uplink Ack/Nack bit count 100, max 184, message = 40 24 01 3f 3e 24 46 68 90 88 b0 06 8b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b Got 'TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS)', TA=7 Got MS: TLLI = 0xf1223344, TA = 7 ********** TBF starts here ********** -- To view, visit https://gerrit.osmocom.org/703 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Iba7b1995028bd81749ffb080616b2ad5f2540d57 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Wed Aug 17 07:30:25 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Wed, 17 Aug 2016 07:30:25 +0000 Subject: [PATCH] osmo-pcu[master]: Remove warning while using 'egprs only' command in VTY Message-ID: Review at https://gerrit.osmocom.org/704 Remove warning while using 'egprs only' command in VTY This warning is not valid since the PCU is not failing when EGPRS is activated. So removing this trace Change-Id: I62278f998adc691b9a3563ac2a46d756e7bfb66c --- M src/pcu_vty.c 1 file changed, 0 insertions(+), 6 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/04/704/1 diff --git a/src/pcu_vty.c b/src/pcu_vty.c index 58fea99..ef48027 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -187,12 +187,6 @@ bts->egprs_enabled = 1; - vty_out(vty, "%%Note that EGPRS support is in an experimental state " - "and the PCU will currently fail to use a TBF if the MS is capable " - "to do EGPRS. You may want to disable this feature by entering " - "the \"no egprs\" command. " - "Do not use this in production!%s", VTY_NEWLINE); - return CMD_SUCCESS; } -- To view, visit https://gerrit.osmocom.org/704 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I62278f998adc691b9a3563ac2a46d756e7bfb66c Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Wed Aug 17 11:00:35 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 17 Aug 2016 11:00:35 +0000 Subject: osmo-pcu[master]: Add data structure to handle SPB for EGPRS DL In-Reply-To: References: Message-ID: Patch Set 6: Code-Review+1 I could still nitpick on punctuation in the comments but I'd rather be done. -- To view, visit https://gerrit.osmocom.org/654 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I57673e53a9da2affa7e8aaa6551ac4b271c3d525 Gerrit-PatchSet: 6 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 17 11:25:26 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 17 Aug 2016 11:25:26 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 15: Code-Review-1 (5 comments) Thank you for your patience ... I still found some issues. https://gerrit.osmocom.org/#/c/655/15/src/pcu_vty.c File src/pcu_vty.c: Line 489: "dl arq-type (0|1)", I notice that 0 is for EGPRS_ARQ1 and 1 is for EGPRS_ARQ2. This is confusing; as holger likes to say: the vty is for humans. So IMHO you should have (1|2) and explicitly translate those to EGPRS_ARQ1 and EGPRS_ARQ2 in the arg parsing, preferably even with a switch() or if() statement, to decouple. Even better could be to use string arguments like (spb|arq2) instead of the numbers. Make it most convenient for humans ;) Line 490: EGPRS_STR "DL ARQ options\n" ah, missed this one before: EGPRS_STR is only for "egprs", not for "dl". i.e. EGPRS_STR should be dropped, and the doc string for "arq-type" is missing. Line 491: "enable DL SPB support\n" is SPB == ARQ1? I'm not familiar with the topic, but if it is, the doc string could mention both? https://gerrit.osmocom.org/#/c/655/15/src/tbf_dl.cpp File src/tbf_dl.cpp: Line 632: unsigned int spb_status = get_egprs_dl_spb_status(index); nice. Line 1215: uint8_t **block_data) this now fits on one line. -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 15 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Wed Aug 17 11:42:56 2016 From: gerrit-no-reply at lists.osmocom.org (bhargava_abhyankar) Date: Wed, 17 Aug 2016 11:42:56 +0000 Subject: [PATCH] osmo-pcu[master]: Change interface in osmo-pcu for 11 bit RACH In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/429 to look at the new patch set (#4). Change interface in osmo-pcu for 11 bit RACH Interface structure between osmo-bts and osmo-pcu is updated with the parameters to differentiate the type of RACH and further support 11 bit RACH. The function prototype and definitions are changed accordingly. Interface version number is increased. Change-Id: I265c2d92d36d6cbcbeee60cdd8407dafe1da06a4 --- M src/bts.cpp M src/bts.h M src/pcu_l1_if.cpp M src/pcuif_proto.h M tests/tbf/TbfTest.cpp 5 files changed, 18 insertions(+), 9 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/29/429/4 diff --git a/src/bts.cpp b/src/bts.cpp index c53c92c..e65d608 100644 --- a/src/bts.cpp +++ b/src/bts.cpp @@ -467,7 +467,8 @@ return 0; } -int BTS::rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta) +int BTS::rcv_rach(uint16_t ra, uint32_t Fn, int16_t qta, uint8_t is_11bit, + enum ph_burst_type burst_type) { struct gprs_rlcmac_ul_tbf *tbf = NULL; uint8_t trx_no, ts_no = 0; diff --git a/src/bts.h b/src/bts.h index 807ce08..d68e5d8 100644 --- a/src/bts.h +++ b/src/bts.h @@ -28,6 +28,7 @@ #include #include #include +#include } #include "poll_controller.h" @@ -285,7 +286,8 @@ int tfi_find_free(enum gprs_rlcmac_tbf_direction dir, uint8_t *_trx, int8_t use_trx); int rcv_imm_ass_cnf(const uint8_t *data, uint32_t fn); - int rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta); + int rcv_rach(uint16_t ra, uint32_t Fn, int16_t qta, uint8_t is_11bit, + enum ph_burst_type burst_type); void trigger_dl_ass(gprs_rlcmac_dl_tbf *tbf, gprs_rlcmac_tbf *old_tbf); void snd_dl_ass(gprs_rlcmac_tbf *tbf, uint8_t poll, const char *imsi); diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp index 1434213..f1c73c9 100644 --- a/src/pcu_l1_if.cpp +++ b/src/pcu_l1_if.cpp @@ -322,7 +322,8 @@ case PCU_IF_SAPI_RACH: rc = BTS::main_bts()->rcv_rach( rach_ind->ra, rach_ind->fn, - rach_ind->qta); + rach_ind->qta, rach_ind->is_11bit, + (ph_burst_type)rach_ind->burst_type); break; default: LOGP(DL1IF, LOGL_ERROR, "Received PCU rach request with " diff --git a/src/pcuif_proto.h b/src/pcuif_proto.h index d320380..268f59a 100644 --- a/src/pcuif_proto.h +++ b/src/pcuif_proto.h @@ -1,7 +1,9 @@ #ifndef _PCUIF_PROTO_H #define _PCUIF_PROTO_H -#define PCU_IF_VERSION 0x06 +#include + +#define PCU_IF_VERSION 0x07 /* msg_type */ #define PCU_IF_MSG_DATA_REQ 0x00 /* send data to given channel */ @@ -67,10 +69,12 @@ struct gsm_pcu_if_rach_ind { uint8_t sapi; - uint8_t ra; + uint16_t ra; int16_t qta; uint32_t fn; uint16_t arfcn; + uint8_t is_11bit; + uint8_t burst_type; } __attribute__ ((packed)); struct gsm_pcu_if_info_trx { diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..2569f8c 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -36,6 +36,7 @@ #include #include #include +#include } #include @@ -553,7 +554,7 @@ tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1); - the_bts->rcv_rach(0x03, *fn, qta); + the_bts->rcv_rach(0x03, *fn, qta, 0, GSM_L1_BURST_TYPE_ACCESS_0); ul_tbf = the_bts->ul_tbf_by_tfi(tfi, trx_no, ts_no); OSMO_ASSERT(ul_tbf != NULL); @@ -645,7 +646,7 @@ * simulate RACH, this sends an Immediate * Assignment Uplink on the AGCH */ - the_bts->rcv_rach(0x73, rach_fn, qta); + the_bts->rcv_rach(0x73, rach_fn, qta, 0, GSM_L1_BURST_TYPE_ACCESS_0); /* get next free TFI */ tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1); @@ -1090,8 +1091,8 @@ /* needed to set last_rts_fn in the PDCH object */ request_dl_rlc_block(bts, trx_no, ts_no, fn); - /* simulate RACH, this sends an Immediate Assignment Uplink on the AGCH */ - the_bts->rcv_rach(0x73, rach_fn, qta); + /* simulate RACH, sends an Immediate Assignment Uplink on the AGCH */ + the_bts->rcv_rach(0x73, rach_fn, qta, 0, GSM_L1_BURST_TYPE_ACCESS_0); /* get next free TFI */ tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1); -- To view, visit https://gerrit.osmocom.org/429 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I265c2d92d36d6cbcbeee60cdd8407dafe1da06a4 Gerrit-PatchSet: 4 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: bhargava_abhyankar From gerrit-no-reply at lists.osmocom.org Wed Aug 17 11:43:35 2016 From: gerrit-no-reply at lists.osmocom.org (bhargava_abhyankar) Date: Wed, 17 Aug 2016 11:43:35 +0000 Subject: [PATCH] osmo-bts[master]: Change interface in osmo-bts for 11 bit RACH In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/433 to look at the new patch set (#5). Change interface in osmo-bts for 11 bit RACH Interface structure between osmo-bts and osmo-pcu is updated with the parameters to differentiate the type of RACH and further support 11 bit RACH. The function prototype and definitions are changed accordingly. Interface version number is increased. Change-Id: I4f4c501b2d86d77c78de32a84b1804172ffb6f4d --- M include/osmo-bts/pcu_if.h M include/osmo-bts/pcuif_proto.h M src/common/l1sap.c M src/common/pcu_sock.c M src/osmo-bts-sysmo/l1_if.c 5 files changed, 22 insertions(+), 7 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/33/433/5 diff --git a/include/osmo-bts/pcu_if.h b/include/osmo-bts/pcu_if.h index efad0c5..a020c05 100644 --- a/include/osmo-bts/pcu_if.h +++ b/include/osmo-bts/pcu_if.h @@ -11,7 +11,8 @@ int pcu_tx_data_ind(struct gsm_bts_trx_ts *ts, uint8_t is_ptcch, uint32_t fn, uint16_t arfcn, uint8_t block_nr, uint8_t *data, uint8_t len, int8_t rssi, uint16_t ber10k, int16_t bto, int16_t lqual); -int pcu_tx_rach_ind(struct gsm_bts *bts, int16_t qta, uint8_t ra, uint32_t fn); +int pcu_tx_rach_ind(struct gsm_bts *bts, int16_t qta, uint16_t ra, uint32_t fn, + uint8_t is_11bit, enum ph_burst_type burst_type); int pcu_tx_time_ind(uint32_t fn); int pcu_tx_pag_req(const uint8_t *identity_lv, uint8_t chan_needed); int pcu_tx_pch_data_cnf(uint32_t fn, uint8_t *data, uint8_t len); diff --git a/include/osmo-bts/pcuif_proto.h b/include/osmo-bts/pcuif_proto.h index 07d35f8..5527238 100644 --- a/include/osmo-bts/pcuif_proto.h +++ b/include/osmo-bts/pcuif_proto.h @@ -1,7 +1,7 @@ #ifndef _PCUIF_PROTO_H #define _PCUIF_PROTO_H -#define PCU_IF_VERSION 0x06 +#define PCU_IF_VERSION 0x07 /* msg_type */ #define PCU_IF_MSG_DATA_REQ 0x00 /* send data to given channel */ @@ -67,10 +67,12 @@ struct gsm_pcu_if_rach_ind { uint8_t sapi; - uint8_t ra; + uint16_t ra; int16_t qta; uint32_t fn; uint16_t arfcn; + uint8_t is_11bit; + uint8_t burst_type; } __attribute__ ((packed)); struct gsm_pcu_if_info_trx { diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 6498103..2ab4055 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -288,7 +288,7 @@ *ss = L1SAP_CHAN2SS_SDCCH4(chan_nr); else if (L1SAP_IS_CHAN_SDCCH8(chan_nr)) *ss = L1SAP_CHAN2SS_SDCCH8(chan_nr); - *data = &l1sap->u.rach_ind.ra; + *data = (uint8_t *)&l1sap->u.rach_ind.ra; *len = 1; return 0; @@ -965,10 +965,13 @@ return l1sap_handover_rach(trx, l1sap, rach_ind); /* check for packet access */ - if (trx == bts->c0 && L1SAP_IS_PACKET_RACH(rach_ind->ra)) { + if ((trx == bts->c0 && L1SAP_IS_PACKET_RACH(rach_ind->ra)) || + (trx == bts->c0 && rach_ind->is_11bit)) { + LOGP(DL1P, LOGL_INFO, "RACH for packet access\n"); pcu_tx_rach_ind(bts, rach_ind->acc_delay << 2, - rach_ind->ra, rach_ind->fn); + rach_ind->ra, rach_ind->fn, + rach_ind->is_11bit, rach_ind->burst_type); return 0; } diff --git a/src/common/pcu_sock.c b/src/common/pcu_sock.c index fed464f..62f18a7 100644 --- a/src/common/pcu_sock.c +++ b/src/common/pcu_sock.c @@ -371,7 +371,8 @@ return pcu_sock_send(&bts_gsmnet, msg); } -int pcu_tx_rach_ind(struct gsm_bts *bts, int16_t qta, uint8_t ra, uint32_t fn) +int pcu_tx_rach_ind(struct gsm_bts *bts, int16_t qta, uint16_t ra, uint32_t fn, + uint8_t is_11bit, enum ph_burst_type burst_type) { struct msgb *msg; struct gsm_pcu_if *pcu_prim; @@ -390,6 +391,8 @@ rach_ind->ra = ra; rach_ind->qta = qta; rach_ind->fn = fn; + rach_ind->is_11bit = is_11bit; + rach_ind->burst_type = burst_type; return pcu_sock_send(&bts_gsmnet, msg); } diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index f70ccf5..fcd3a3e 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -970,6 +970,12 @@ l1sap->u.rach_ind.ra = ra; l1sap->u.rach_ind.acc_delay = acc_delay; l1sap->u.rach_ind.fn = fn; + + /* Initialising the parameters needs to be handled when 11 bit RACH */ + + l1sap->u.rach_ind.is_11bit = 0; + l1sap->u.rach_ind.burst_type = GSM_L1_BURST_TYPE_ACCESS_0; + if (!lchan || lchan->ts->pchan == GSM_PCHAN_CCCH || lchan->ts->pchan == GSM_PCHAN_CCCH_SDCCH4) l1sap->u.rach_ind.chan_nr = 0x88; -- To view, visit https://gerrit.osmocom.org/433 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I4f4c501b2d86d77c78de32a84b1804172ffb6f4d Gerrit-PatchSet: 5 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: bhargava_abhyankar From gerrit-no-reply at lists.osmocom.org Wed Aug 17 11:43:35 2016 From: gerrit-no-reply at lists.osmocom.org (bhargava_abhyankar) Date: Wed, 17 Aug 2016 11:43:35 +0000 Subject: [PATCH] osmo-bts[master]: Update parameters in osmo-bts-sysmo for 11bit RACH In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/434 to look at the new patch set (#6). Update parameters in osmo-bts-sysmo for 11bit RACH Based on the indication from L1, number of bits in RACH and burst type is determined. Appropriate parameters are filled in osmo-bts-sysmo These parameters are sent to osmo-pcu for processing of the RACH. Change-Id: I93831ddfb3f31b637e6a576f23a9bb4557758582 --- M src/osmo-bts-sysmo/l1_if.c 1 file changed, 36 insertions(+), 6 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/34/434/6 diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index fcd3a3e..4fcee2f 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -929,7 +929,8 @@ struct gsm_lchan *lchan; struct osmo_phsap_prim *l1sap; uint32_t fn; - uint8_t ra, acc_delay = 0; + uint8_t acc_delay = 0; + uint16_t ra = 0, is_11bit = 0, burst_type = 0, temp = 0; int rc; /* increment number of busy RACH slots, if required */ @@ -951,16 +952,28 @@ btsb->load.rach.access++; dump_meas_res(LOGL_DEBUG, &ra_ind->measParam); + burst_type = ra_ind->burstType; - if (ra_ind->msgUnitParam.u8Size != 1) { + if ((ra_ind->msgUnitParam.u8Size != 1) && + (ra_ind->msgUnitParam.u8Size != 2)) { LOGP(DL1C, LOGL_ERROR, "PH-RACH-INDICATION has %d bits\n", ra_ind->sapi); msgb_free(l1p_msg); return 0; } + if (ra_ind->msgUnitParam.u8Size == 2) { + is_11bit = 1; + ra = ra_ind->msgUnitParam.u8Buffer[0]; + ra = ra << 3; + temp = (ra_ind->msgUnitParam.u8Buffer[1] & 0x7); + ra = ra | temp; + } else { + is_11bit = 0; + ra = ra_ind->msgUnitParam.u8Buffer[0]; + } + fn = ra_ind->u32Fn; - ra = ra_ind->msgUnitParam.u8Buffer[0]; rc = msgb_trim(l1p_msg, sizeof(*l1sap)); if (rc < 0) MSGB_ABORT(l1p_msg, "No room for primitive data\n"); @@ -970,11 +983,28 @@ l1sap->u.rach_ind.ra = ra; l1sap->u.rach_ind.acc_delay = acc_delay; l1sap->u.rach_ind.fn = fn; + l1sap->u.rach_ind.is_11bit = is_11bit; /* no of bits in 11 bit RACH */ - /* Initialising the parameters needs to be handled when 11 bit RACH */ + /*mapping of the burst type, the values are specific to osmo-bts-sysmo*/ - l1sap->u.rach_ind.is_11bit = 0; - l1sap->u.rach_ind.burst_type = GSM_L1_BURST_TYPE_ACCESS_0; + switch (burst_type) { + case GsmL1_BurstType_Access_0: + l1sap->u.rach_ind.burst_type = + GSM_L1_BURST_TYPE_ACCESS_0; + break; + case GsmL1_BurstType_Access_1: + l1sap->u.rach_ind.burst_type = + GSM_L1_BURST_TYPE_ACCESS_1; + break; + case GsmL1_BurstType_Access_2: + l1sap->u.rach_ind.burst_type = + GSM_L1_BURST_TYPE_ACCESS_2; + break; + default: + l1sap->u.rach_ind.burst_type = + GSM_L1_BURST_TYPE_NONE; + break; + } if (!lchan || lchan->ts->pchan == GSM_PCHAN_CCCH || lchan->ts->pchan == GSM_PCHAN_CCCH_SDCCH4) -- To view, visit https://gerrit.osmocom.org/434 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I93831ddfb3f31b637e6a576f23a9bb4557758582 Gerrit-PatchSet: 6 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: bhargava_abhyankar From gerrit-no-reply at lists.osmocom.org Wed Aug 17 13:14:26 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Wed, 17 Aug 2016 13:14:26 +0000 Subject: [PATCH] openbsc[master]: Adding SNDCP-XID encoder / decoder and unit test In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/641 to look at the new patch set (#11). Adding SNDCP-XID encoder / decoder and unit test The SNDCP-XID (or layer-3 xid) is used to exchange layer-3 parameters such as compression. The encoder encodes a bytestream that is then sent as regular XID field from LLC. We will need the SNDCP-XID to negotiate the parameters for our upcomming GPRS data and header compression features Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e --- M openbsc/.gitignore M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_sndcp_xid.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_sndcp_xid.c M openbsc/tests/Makefile.am M openbsc/tests/sgsn/Makefile.am A openbsc/tests/sndcp_xid/Makefile.am A openbsc/tests/sndcp_xid/sndcp_xid_test.c A openbsc/tests/sndcp_xid/sndcp_xid_test.ok M openbsc/tests/testsuite.at 12 files changed, 2,418 insertions(+), 5 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/41/641/11 diff --git a/openbsc/.gitignore b/openbsc/.gitignore index 0a2965d..8ce3b70 100644 --- a/openbsc/.gitignore +++ b/openbsc/.gitignore @@ -81,6 +81,8 @@ tests/oap/oap_test tests/gtphub/gtphub_test tests/mm_auth/mm_auth_test +tests/xid/xid_test +tests/sndcp_xid/sndcp_xid_test tests/atconfig tests/atlocal diff --git a/openbsc/configure.ac b/openbsc/configure.ac index fbf2930..53072bd 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -230,6 +230,7 @@ tests/gtphub/Makefile tests/mm_auth/Makefile tests/xid/Makefile + tests/sndcp_xid/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index ce5f768..e200b05 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,7 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_llc_xid.h gprs_sndcp.h + gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_sndcp_xid.h b/openbsc/include/openbsc/gprs_sndcp_xid.h new file mode 100644 index 0000000..8c5cbf4 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_xid.h @@ -0,0 +1,214 @@ +/* GPRS SNDCP XID field encoding/decoding as per 3GPP TS 44.065 */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_SNDCP_XID_H +#define _GPRS_SNDCP_XID_H + +#include +#include + +#define CURRENT_SNDCP_VERSION 0 /* See 3GPP TS 44.065, clause 8 */ +#define MAX_ENTITIES 32 /* 3GPP TS 44.065 reserves 5 bit + * for compression enitity number */ + +/* According to: 3GPP TS 44.065, 6.5.1.1 Format of the protocol control + * information compression field (Figure 7) + * 3GPP TS 44.065, 6.6.1.1 Format of the data compression + * field (Figure 9) */ +struct gprs_sndcp_comp_field { + struct llist_head list; + + /* Propose bit (P), see also: 6.5.1.1.2 and 6.6.1.1.2 */ + unsigned int p; + + /* Entity number, see also: 6.5.1.1.3 and 6.6.1.1.3 */ + unsigned int entity; + + /* Algorithm identifier, see also: 6.5.1.1.4 and 6.6.1.1.4 */ + int algo; + + /* Number of contained PCOMP / DCOMP values */ + unsigned int comp_len; + + /* PCOMP / DCOMP values, see also: 6.5.1.1.5 and 6.6.1.1.5 */ + unsigned int comp[16]; + + /* Note: Only one of the following struct pointers may, + be used unused pointers must be set to NULL! */ + struct gprs_sndcp_pcomp_rfc1144_params *rfc1144_params; + struct gprs_sndcp_pcomp_rfc2507_params *rfc2507_params; + struct gprs_sndcp_pcomp_rohc_params *rohc_params; + struct gprs_sndcp_dcomp_v42bis_params *v42bis_params; + struct gprs_sndcp_dcomp_v44_params *v44_params; +}; + +/* According to: 3GPP TS 44.065, 6.5.1.1.4 Algorithm identifier */ +enum gprs_sndcp_hdr_comp_algo { + RFC_1144, /* TCP/IP header compression, see also 6.5.2 */ + RFC_2507, /* TCP/UDP/IP header compression, see also: 6.5.3 */ + ROHC /* Robust Header Compression, see also 6.5.4 */ +}; + +/* According to: 3GPP TS 44.065, 6.5.1.1.4 Algorithm identifier */ +enum gprs_sndcp_data_comp_algo { + V42BIS, /* V.42bis data compression, see also 6.6.2 */ + V44 /* V44 data compression, see also: 6.6.3 */ +}; + +/* According to: 3GPP TS 44.065, 8 SNDCP XID parameters */ +enum gprs_sndcp_xid_param_types { + SNDCP_XID_VERSION_NUMBER, + SNDCP_XID_DATA_COMPRESSION, /* See also: subclause 6.6.1 */ + SNDCP_XID_PROTOCOL_COMPRESSION, /* See also: subclause 6.5.1 */ +}; + +/* According to: 3GPP TS 44.065, 6.5.2.1 Parameters (Table 5) */ +struct gprs_sndcp_pcomp_rfc1144_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int s01; /* (default 15) */ +}; + +/* According to: 3GPP TS 44.065, 6.5.2.2 Assignment of PCOMP values */ +enum gprs_sndcp_pcomp_rfc1144_pcomp { + RFC1144_PCOMP1, /* Uncompressed TCP */ + RFC1144_PCOMP2, /* Compressed TCP */ + RFC1144_PCOMP_NUM /* Number of pcomp values */ +}; + +/* According to: 3GPP TS 44.065, 6.5.3.1 Parameters (Table 6) */ +struct gprs_sndcp_pcomp_rfc2507_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int f_max_period; /* (default 256) */ + int f_max_time; /* (default 5) */ + int max_header; /* (default 168) */ + int tcp_space; /* (default 15) */ + int non_tcp_space; /* (default 15) */ +}; + +/* According to: 3GPP TS 44.065, 6.5.3.2 Assignment of PCOMP values for RFC2507 */ +enum gprs_sndcp_pcomp_rfc2507_pcomp { + RFC2507_PCOMP1, /* Full Header */ + RFC2507_PCOMP2, /* Compressed TCP */ + RFC2507_PCOMP3, /* Compressed TCP non delta */ + RFC2507_PCOMP4, /* Compressed non TCP */ + RFC2507_PCOMP5, /* Context state */ + RFC2507_PCOMP_NUM /* Number of pcomp values */ +}; + +/* According to: 3GPP TS 44.065, 6.5.4.1 Parameter (Table 10) */ +struct gprs_sndcp_pcomp_rohc_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int max_cid; /* (default 15) */ + int max_header; /* (default 168) */ + unsigned int profile_len; /* (default 1) */ + uint16_t profile[16]; /* (default 0, ROHC uncompressed) */ +}; + +/* According to: 3GPP TS 44.065, 6.5.4.2 Assignment of PCOMP values for ROHC */ +enum gprs_sndcp_pcomp_rohc_pcomp { + ROHC_PCOMP1, /* ROHC small CIDs */ + ROHC_PCOMP2, /* ROHC large CIDs */ + ROHC_PCOMP_NUM /* Number of pcomp values */ +}; + +/* ROHC compression profiles, see also: + http://www.iana.org/assignments/rohc-pro-ids/rohc-pro-ids.xhtml */ +enum gprs_sndcp_xid_rohc_profiles { + ROHC_UNCOMPRESSED = 0x0000, /* ROHC uncompressed [RFC5795] */ + ROHC_RTP = 0x0001, /* ROHC RTP [RFC3095] */ + ROHCV2_RTP = 0x0101, /* ROHCv2 RTP [RFC5225] */ + ROHC_UDP = 0x0002, /* ROHC UDP [RFC3095] */ + ROHCv2_UDP = 0x0102, /* ROHCv2 UDP [RFC5225] */ + ROHC_ESP = 0x0003, /* ROHC ESP [RFC3095] */ + ROHCV2_ESP = 0x0103, /* ROHCv2 ESP [RFC5225] */ + ROHC_IP = 0x0004, /* ROHC IP [RFC3843] */ + ROHCV2_IP = 0x0104, /* ROHCv2 IP [RFC5225] */ + ROHC_LLA = 0x0005, /* ROHC LLA [RFC4362] */ + ROHC_LLA_WITH_R_MODE = 0x0105, /* ROHC LLA with R-mode [RFC3408] */ + ROHC_TCP = 0x0006, /* ROHC TCP [RFC6846] */ + ROHC_RTP_UDP_LITE = 0x0007, /* ROHC RTP/UDP-Lite [RFC4019] */ + ROHCV2_RTP_UDP_LITE = 0x0107, /* ROHCv2 RTP/UDP-Lite [RFC5225] */ + ROHC_UDP_LITE = 0x0008, /* ROHC UDP-Lite [RFC4019] */ + ROHCV2_UDP_LITE = 0x0108, /* ROHCv2 UDP-Lite [RFC5225] */ +}; + +/* According to: 3GPP TS 44.065, 6.6.2.1 Parameters (Table 7a) */ +struct gprs_sndcp_dcomp_v42bis_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int p0; /* (default 3) */ + int p1; /* (default 2048) */ + int p2; /* (default 20) */ + +}; + +/* According to: 3GPP TS 44.065, 6.6.2.2 Assignment of DCOMP values */ +enum gprs_sndcp_dcomp_v42bis_dcomp { + V42BIS_DCOMP1, /* V.42bis enabled */ + V42BIS_DCOMP_NUM /* Number of dcomp values */ +}; + +/* According to: 3GPP TS 44.065, 6.6.3.1 Parameters (Table 7c) */ +struct gprs_sndcp_dcomp_v44_params { + unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */ + int c0; /* (default 10000000) */ + int p0; /* (default 3) */ + int p1t; /* Refer to subclause 6.6.3.1.4 */ + int p1r; /* Refer to subclause 6.6.3.1.5 */ + int p3t; /* (default 3 x p1t) */ + int p3r; /* (default 3 x p1r) */ +}; + +/* According to: 3GPP TS 44.065, 6.6.3.2 Assignment of DCOMP values */ +enum gprs_sndcp_dcomp_v44_dcomp { + V44_DCOMP1, /* Packet method compressed */ + V44_DCOMP2, /* Multi packet method compressed */ + V44_DCOMP_NUM /* Number of dcomp values */ +}; + +/* Transform a list with compression fields into an SNDCP-XID message (dst) */ +int gprs_sndcp_compile_xid(uint8_t *dst, unsigned int dst_maxlen, + const struct llist_head *comp_fields); + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +struct llist_head *gprs_sndcp_parse_xid(const void *ctx, + const uint8_t * src, + unsigned int src_len, + const struct llist_head *comp_fields_req); + +/* Free a list with SNDCP-XID fields */ +struct llist_head *gprs_sndcp_free_comp_fields(struct llist_head *comp_fields); + +/* Find out to which compression class the specified comp-field belongs + * (header compression or data compression?) */ +int gprs_sndcp_get_compression_class( + const struct gprs_sndcp_comp_field *comp_field); + +/* Dump a list with SNDCP-XID fields (Debug) */ +void gprs_sndcp_dump_comp_fields(const struct llist_head *comp_fields, + unsigned int logl); + +#endif diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 1b6de46..fa4a3dd 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -26,11 +26,11 @@ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ - oap.c oap_messages.c gprs_llc_xid.c + oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ - $(LIBCRYPTO_LIBS) -lrt + $(LIBCRYPTO_LIBS) -lrt -lm osmo_gtphub_SOURCES = gtphub_main.c gtphub.c gtphub_sock.c gtphub_ares.c \ gtphub_vty.c sgsn_ares.c gprs_utils.c diff --git a/openbsc/src/gprs/gprs_sndcp_xid.c b/openbsc/src/gprs/gprs_sndcp_xid.c new file mode 100644 index 0000000..704f47c --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_xid.c @@ -0,0 +1,1874 @@ +/* GPRS SNDCP XID field encoding/decoding as per 3GPP TS 44.065 */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* When the propose bit in an SNDCP-XID compression field is set to zero, + * the algorithm identifier is stripped. The algoritm parameters are specific + * for each algorithms. The following struct is used to pass the information + * about the referenced algorithm to the parser. */ +struct entity_algo_table { + unsigned int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + unsigned int algo; /* see also: 6.5.1.1.4 and 6.6.1.1.4 */ + unsigned int compclass; /* Can be either SNDCP_XID_DATA_COMPRESSION or + SNDCP_XID_PROTOCOL_COMPRESSION */ +}; + +/* FUNCTIONS RELATED TO SNDCP-XID ENCODING */ + +/* Encode applicable sapis (works the same in all three compression schemes) */ +static int encode_pcomp_applicable_sapis(uint8_t *dst, + const unsigned int *nsapis, + unsigned int nsapis_len) +{ + /* NOTE: Buffer *dst needs offer at 2 bytes + * of space to store the generation results */ + + uint16_t blob; + unsigned int nsapi; + int i; + + OSMO_ASSERT(dst); + OSMO_ASSERT(nsapis); + + /* Bail if number of possible nsapis exceeds valid range + * (Only 11 nsapis possible for PDP-Contexts) */ + OSMO_ASSERT(nsapis_len <= 11); + + /* Encode applicable SAPIs */ + blob = 0; + for (i = 0; i < nsapis_len; i++) { + nsapi = nsapis[i]; + /* Only NSAPI 5 to 15 are applicable for user traffic (PDP- + * contexts). Only for these NSAPIs SNDCP-XID parameters + * can apply. See also 3GPP TS 44.065, 5.1 Service primitives */ + OSMO_ASSERT(nsapi >= 5 && nsapi <= 15); + blob |= (1 << nsapi); + } + + /* Store result */ + *dst = (blob >> 8) & 0xFF; + dst++; + *dst = blob & 0xFF; + + return 2; +} + +/* Encode rfc1144 parameter field + * (see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */ +static int encode_pcomp_rfc1144_params(uint8_t *dst, unsigned int dst_maxlen, const struct + gprs_sndcp_pcomp_rfc1144_params *params) +{ + /* NOTE: Buffer *dst should offer at least 3 bytes + * of space to store the generation results */ + + int dst_counter = 0; + int rc; + + OSMO_ASSERT(params); + OSMO_ASSERT(dst); + OSMO_ASSERT(dst_maxlen >= 3); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode s01 (see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */ + OSMO_ASSERT(params->s01 >= 0); + OSMO_ASSERT(params->s01 <= 255); + *dst = params->s01; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + +/* + * Encode rfc2507 parameter field + * (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) + */ +static int encode_pcomp_rfc2507_params(uint8_t *dst, unsigned int dst_maxlen, + const struct + gprs_sndcp_pcomp_rfc2507_params *params) +{ + /* NOTE: Buffer *dst should offer at least 3 bytes + * of space to store the generation results */ + + int dst_counter = 0; + int rc; + + OSMO_ASSERT(params); + OSMO_ASSERT(dst); + OSMO_ASSERT(dst_maxlen >= 9); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode F_MAX_PERIOD (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->f_max_period >= 1); + OSMO_ASSERT(params->f_max_period <= 65535); + *dst = (params->f_max_period >> 8) & 0xFF; + dst++; + dst_counter++; + *dst = (params->f_max_period) & 0xFF; + dst++; + dst_counter++; + + /* Encode F_MAX_TIME (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->f_max_time >= 1); + OSMO_ASSERT(params->f_max_time <= 255); + *dst = params->f_max_time; + dst++; + dst_counter++; + + /* Encode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->max_header >= 60); + OSMO_ASSERT(params->max_header <= 255); + *dst = params->max_header; + dst++; + dst_counter++; + + /* Encode TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->tcp_space >= 3); + OSMO_ASSERT(params->tcp_space <= 255); + *dst = params->tcp_space; + dst++; + dst_counter++; + + /* Encode NON_TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->non_tcp_space >= 3); + OSMO_ASSERT(params->non_tcp_space <= 65535); + *dst = (params->non_tcp_space >> 8) & 0xFF; + dst++; + dst_counter++; + *dst = (params->non_tcp_space) & 0xFF; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + +/* Encode ROHC parameter field + * (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ +static int encode_pcomp_rohc_params(uint8_t *dst, unsigned int dst_maxlen, + const struct gprs_sndcp_pcomp_rohc_params + *params) +{ + /* NOTE: Buffer *dst should offer at least 36 + * (2 * 16 Profiles + 2 * 3 Parameter) bytes + * of memory space to store generation results */ + + int i; + int dst_counter = 0; + int rc; + + OSMO_ASSERT(params); + OSMO_ASSERT(dst); + OSMO_ASSERT(dst_maxlen >= 38); + + /* Bail if number of ROHC profiles exceeds limit + * (ROHC supports only a maximum of 16 different profiles) */ + OSMO_ASSERT(params->profile_len >= 0); + OSMO_ASSERT(params->profile_len <= 16); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode MAX_CID (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + OSMO_ASSERT(params->max_cid >= 0); + OSMO_ASSERT(params->max_cid <= 16383); + *dst = (params->max_cid >> 8) & 0xFF; + dst++; + *dst = params->max_cid & 0xFF; + dst++; + dst_counter += 2; + + /* Encode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + OSMO_ASSERT(params->max_header >= 60); + OSMO_ASSERT(params->max_header <= 255); + *dst = (params->max_header >> 8) & 0xFF; + dst++; + *dst = params->max_header & 0xFF; + dst++; + dst_counter += 2; + + /* Encode ROHC Profiles (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + for (i = 0; i < params->profile_len; i++) { + *dst = (params->profile[i] >> 8) & 0xFF; + dst++; + *dst = params->profile[i] & 0xFF; + dst++; + dst_counter += 2; + } + + /* Return generated length */ + return dst_counter; +} + +/* Encode V.42bis parameter field + * (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ +static int encode_dcomp_v42bis_params(uint8_t *dst, unsigned int dst_maxlen, + const struct + gprs_sndcp_dcomp_v42bis_params *params) +{ + /* NOTE: Buffer *dst should offer at least 6 bytes + * of space to store the generation results */ + + int dst_counter = 0; + int rc; + + OSMO_ASSERT(params); + OSMO_ASSERT(dst); + OSMO_ASSERT(dst_maxlen >= 6); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode P0 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + OSMO_ASSERT(params->p0 >= 0); + OSMO_ASSERT(params->p0 <= 3); + *dst = params->p0 & 0x03; + dst++; + dst_counter++; + + /* Encode P1 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + OSMO_ASSERT(params->p1 >= 512); + OSMO_ASSERT(params->p1 <= 65535); + *dst = (params->p1 >> 8) & 0xFF; + dst++; + *dst = params->p1 & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P2 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + OSMO_ASSERT(params->p2 >= 6); + OSMO_ASSERT(params->p2 <= 250); + *dst = params->p2; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + +/* Encode V44 parameter field + * (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ +static int encode_dcomp_v44_params(uint8_t *dst, unsigned int dst_maxlen, + const struct gprs_sndcp_dcomp_v44_params + *params) +{ + /* NOTE: Buffer *dst should offer at least 12 bytes + * of space to store the generation results */ + + int dst_counter = 0; + int rc; + + OSMO_ASSERT(params); + OSMO_ASSERT(dst); + OSMO_ASSERT(dst_maxlen >= 12); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode C0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->c0 == 0x80 || params->c0 == 0xC0); + *dst = params->c0 & 0xC0; + dst++; + dst_counter++; + + /* Encode P0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p0 >= 0); + OSMO_ASSERT(params->p0 <= 3); + *dst = params->p0 & 0x03; + dst++; + dst_counter++; + + /* Encode P1T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p1t >= 256); + OSMO_ASSERT(params->p1t <= 65535); + *dst = (params->p1t >> 8) & 0xFF; + dst++; + *dst = params->p1t & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P1R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p1r >= 256); + OSMO_ASSERT(params->p1r <= 65535); + *dst = (params->p1r >> 8) & 0xFF; + dst++; + *dst = params->p1r & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P3T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p3t >= 0); + OSMO_ASSERT(params->p3t <= 65535); + OSMO_ASSERT(params->p3t >= 2 * params->p1t); + *dst = (params->p3t >> 8) & 0xFF; + dst++; + *dst = params->p3t & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P3R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p3r >= 0); + OSMO_ASSERT(params->p3r <= 65535); + OSMO_ASSERT(params->p3r >= 2 * params->p1r); + *dst = (params->p3r >> 8) & 0xFF; + dst++; + *dst = params->p3r & 0xFF; + dst++; + dst_counter += 2; + + /* Return generated length */ + return dst_counter; +} + +/* Encode data or protocol control information compression field + * (see also: 3GPP TS 44.065, 6.6.1.1, Figure 9 and + * 3GPP TS 44.065, 6.5.1.1, Figure 7) */ +static int encode_comp_field(uint8_t *dst, unsigned int dst_maxlen, + const struct gprs_sndcp_comp_field *comp_field) +{ + int dst_counter = 0; + int len; + int expected_length; + int i; + + OSMO_ASSERT(dst); + OSMO_ASSERT(comp_field); + + uint8_t payload_bytes[256]; + int payload_bytes_len = -1; + + /* If possible, try do encode payload bytes first */ + if (comp_field->rfc1144_params) { + payload_bytes_len = + encode_pcomp_rfc1144_params(payload_bytes, + sizeof(payload_bytes), + comp_field->rfc1144_params); + } else if (comp_field->rfc2507_params) { + payload_bytes_len = + encode_pcomp_rfc2507_params(payload_bytes, + sizeof(payload_bytes), + comp_field->rfc2507_params); + } else if (comp_field->rohc_params) { + payload_bytes_len = + encode_pcomp_rohc_params(payload_bytes, + sizeof(payload_bytes), + comp_field->rohc_params); + } else if (comp_field->v42bis_params) { + payload_bytes_len = + encode_dcomp_v42bis_params(payload_bytes, + sizeof(payload_bytes), + comp_field->v42bis_params); + } else if (comp_field->v44_params) { + payload_bytes_len = + encode_dcomp_v44_params(payload_bytes, + sizeof(payload_bytes), + comp_field->v44_params); + } else + OSMO_ASSERT(false); + + /* Bail immediately if payload byte generation failed */ + OSMO_ASSERT(payload_bytes_len >= 0); + + /* Bail if comp_len is out of bounds */ + OSMO_ASSERT(comp_field->comp_len <= sizeof(comp_field->comp)); + + /* Calculate length field of the data block */ + if (comp_field->p) { + len = + payload_bytes_len + + ceil((double)(comp_field->comp_len) / 2.0); + expected_length = len + 3; + } else { + len = payload_bytes_len; + expected_length = len + 2; + } + + /* Bail immediately if no sufficient memory space is supplied */ + OSMO_ASSERT(dst_maxlen >= expected_length); + + /* Check if the entity number is within bounds */ + OSMO_ASSERT(comp_field->entity <= 0x1f); + + /* Check if the algorithm number is within bounds */ + OSMO_ASSERT(comp_field->algo >= 0 || comp_field->algo <= 0x1f); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode Propose bit */ + if (comp_field->p) + *dst |= (1 << 7); + + /* Encode entity number */ + *dst |= comp_field->entity & 0x1F; + dst++; + dst_counter++; + + /* Encode algorithm number */ + if (comp_field->p) { + *dst |= comp_field->algo & 0x1F; + dst++; + dst_counter++; + } + + /* Encode length field */ + *dst |= len & 0xFF; + dst++; + dst_counter++; + + /* Encode PCOMP/DCOMP values */ + if (comp_field->p) { + for (i = 0; i < comp_field->comp_len; i++) { + /* Check if submitted PCOMP/DCOMP + values are within bounds */ + if ((comp_field->comp[i] < 0) + || (comp_field->comp[i] > 0x0F)) + return -EINVAL; + + if (i & 1) { + *dst |= comp_field->comp[i] & 0x0F; + dst++; + dst_counter++; + } else + *dst |= (comp_field->comp[i] << 4) & 0xF0; + } + + if (i & 1) { + dst++; + dst_counter++; + } + } + + /* Append payload bytes */ + memcpy(dst, payload_bytes, payload_bytes_len); + dst_counter += payload_bytes_len; + + /* Return generated length */ + return dst_counter; +} + +/* Find out to which compression class the specified comp-field belongs + * (header compression or data compression?) */ +int gprs_sndcp_get_compression_class(const struct gprs_sndcp_comp_field + *comp_field) +{ + OSMO_ASSERT(comp_field); + + if (comp_field->rfc1144_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->rfc2507_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->rohc_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->v42bis_params) + return SNDCP_XID_DATA_COMPRESSION; + else if (comp_field->v44_params) + return SNDCP_XID_DATA_COMPRESSION; + else + return -EINVAL; +} + +/* Convert all compression fields to bytstreams */ +static int gprs_sndcp_pack_fields(const struct llist_head *comp_fields, + uint8_t *dst, + unsigned int dst_maxlen, int class) +{ + struct gprs_sndcp_comp_field *comp_field; + int byte_counter = 0; + int rc; + + OSMO_ASSERT(comp_fields); + OSMO_ASSERT(dst); + + llist_for_each_entry_reverse(comp_field, comp_fields, list) { + if (class == gprs_sndcp_get_compression_class(comp_field)) { + rc = encode_comp_field(dst + byte_counter, + dst_maxlen - byte_counter, + comp_field); + + /* When input data is correct, there is + * no reason for the encoder to fail! */ + OSMO_ASSERT(rc >= 0); + + byte_counter += rc; + } + } + + /* Return generated length */ + return byte_counter; +} + +/* Transform a list with compression fields into an SNDCP-XID message (dst) */ +int gprs_sndcp_compile_xid(uint8_t *dst, unsigned int dst_maxlen, + const struct llist_head *comp_fields) +{ + int rc; + int byte_counter = 0; + uint8_t comp_bytes[512]; + uint8_t xid_version_number[1] = { CURRENT_SNDCP_VERSION }; + + OSMO_ASSERT(comp_fields); + OSMO_ASSERT(dst); + OSMO_ASSERT(dst_maxlen >= 2 + sizeof(xid_version_number)); + + /* Bail if there is no input */ + if (llist_empty(comp_fields)) + return -EINVAL; + + /* Prepend header */ + dst = + tlv_put(dst, SNDCP_XID_VERSION_NUMBER, + sizeof(xid_version_number), xid_version_number); + byte_counter += (sizeof(xid_version_number) + 2); + + /* Add data compression fields */ + rc = gprs_sndcp_pack_fields(comp_fields, comp_bytes, + sizeof(comp_bytes), + SNDCP_XID_DATA_COMPRESSION); + OSMO_ASSERT(rc >= 0); + + if (rc > 0) { + dst = tlv_put(dst, SNDCP_XID_DATA_COMPRESSION, rc, comp_bytes); + byte_counter += rc + 2; + } + + /* Add header compression fields */ + rc = gprs_sndcp_pack_fields(comp_fields, comp_bytes, + sizeof(comp_bytes), + SNDCP_XID_PROTOCOL_COMPRESSION); + OSMO_ASSERT(rc >= 0); + + if (rc > 0) { + dst = tlv_put(dst, SNDCP_XID_PROTOCOL_COMPRESSION, rc, + comp_bytes); + byte_counter += rc + 2; + } + + /* Return generated length */ + return byte_counter; +} + +/* FUNCTIONS RELATED TO SNDCP-XID DECODING */ + +/* Decode applicable sapis (works the same in all three compression schemes) */ +static int decode_pcomp_applicable_sapis(unsigned int *nsapis, + unsigned int *nsapis_len, + const uint8_t *src, + unsigned int src_len) +{ + uint16_t blob; + int i; + int nsapi_len = 0; + + OSMO_ASSERT(src); + + /* Exit immediately if no result can be stored */ + if (!nsapis) + return -EINVAL; + + /* Exit immediately if not enough input data is available */ + if (src_len < 2) + return -EINVAL; + + /* Read bitmask */ + blob = *src; + blob = (blob << 8) & 0xFF00; + src++; + blob |= (*src) & 0xFF; + blob = (blob >> 5); + + /* Decode applicable SAPIs */ + for (i = 0; i < 15; i++) { + if ((blob >> i) & 1) { + nsapis[nsapi_len] = i + 5; + nsapi_len++; + } + } + + /* Return consumed length */ + *nsapis_len = nsapi_len; + return 2; +} + +/* Decode 16 bit field */ +static int decode_pcomp_16_bit_field(int *value_int, uint16_t * value_uint16, + const uint8_t *src, + unsigned int src_len, + int value_min, int value_max) +{ + uint16_t blob; + + OSMO_ASSERT(src); + + /* Reset values to zero (just to be sure) */ + if (value_int) + *value_int = -1; + if (value_uint16) + *value_uint16 = 0; + + /* Exit if not enough src are available */ + if (src_len < 2) + return -EINVAL; + + /* Decode bit value */ + blob = *src; + blob = (blob << 8) & 0xFF00; + src++; + blob |= *src; + + /* Check if parsed value is within bounds */ + if (blob < value_min) + return -EINVAL; + if (blob > value_max) + return -EINVAL; + + /* Hand back results to the caller */ + if (value_int) + *value_int = blob; + if (value_uint16) + *value_uint16 = blob; + + /* Return consumed length */ + return 2; +} + +/* Decode 8 bit field */ +static int decode_pcomp_8_bit_field(int *value_int, uint8_t *value_uint8, + const uint8_t *src, + unsigned int src_len, + int value_min, int value_max) +{ + uint8_t blob; + + OSMO_ASSERT(src); + + /* Reset values to invalid (just to be sure) */ + if (value_int) + *value_int = -1; + if (value_uint8) + *value_uint8 = 0; + + /* Exit if not enough src are available */ + if (src_len < 1) + return -EINVAL; + + /* Decode bit value */ + blob = *src; + + /* Check if parsed value is within bounds */ + if (blob < value_min) + return -EINVAL; + if (blob > value_max) + return -EINVAL; + + /* Hand back results to the caller */ + if (value_int) + *value_int = blob; + if (value_uint8) + *value_uint8 = blob; + + /* Return consumed length */ + return 1; +} + +/* Decode rfc1144 parameter field see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */ +static int decode_pcomp_rfc1144_params(struct gprs_sndcp_pcomp_rfc1144_params + *params, const uint8_t *src, + unsigned int src_len) +{ + int rc; + int byte_counter = 0; + + OSMO_ASSERT(params); + OSMO_ASSERT(src); + + /* Mark all optional parameters invalid by default */ + params->s01 = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode parameter S0 -1 + * (see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */ + rc = decode_pcomp_8_bit_field(¶ms->s01, NULL, src, + src_len - byte_counter, 0, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Decode rfc2507 parameter field + * (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ +static int decode_pcomp_rfc2507_params(struct gprs_sndcp_pcomp_rfc2507_params + *params, const uint8_t *src, + unsigned int src_len) +{ + int rc; + int byte_counter = 0; + + OSMO_ASSERT(params); + OSMO_ASSERT(src); + + /* Mark all optional parameters invalid by default */ + params->f_max_period = -1; + params->f_max_time = -1; + params->max_header = -1; + params->tcp_space = -1; + params->non_tcp_space = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode F_MAX_PERIOD (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_16_bit_field(¶ms->f_max_period, NULL, src, + src_len - byte_counter, 1, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode F_MAX_TIME (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_8_bit_field(¶ms->f_max_time, NULL, src, + src_len - byte_counter, 1, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_8_bit_field(¶ms->max_header, NULL, src, + src_len - byte_counter, 60, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_8_bit_field(¶ms->tcp_space, NULL, src, + src_len - byte_counter, 3, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode NON_TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_16_bit_field(¶ms->non_tcp_space, NULL, src, + src_len - byte_counter, 3, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Decode ROHC parameter field (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ +static int decode_pcomp_rohc_params(struct gprs_sndcp_pcomp_rohc_params *params, + const uint8_t *src, unsigned int src_len) +{ + int rc; + int byte_counter = 0; + int i; + + OSMO_ASSERT(params); + OSMO_ASSERT(src); + + /* Mark all optional parameters invalid by default */ + params->max_cid = -1; + params->max_header = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_CID (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + rc = decode_pcomp_16_bit_field(¶ms->max_cid, NULL, src, + src_len - byte_counter, 0, 16383); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + rc = decode_pcomp_16_bit_field(¶ms->max_header, NULL, src, + src_len - byte_counter, 60, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode Profiles (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + for (i = 0; i < 16; i++) { + params->profile_len = 0; + rc = decode_pcomp_16_bit_field(NULL, ¶ms->profile[i], src, + src_len - byte_counter, 0, + 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + params->profile_len = i + 1; + } + + /* Return consumed length */ + return byte_counter; +} + +/* Decode V.42bis parameter field + * (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ +static int decode_dcomp_v42bis_params(struct gprs_sndcp_dcomp_v42bis_params + *params, const uint8_t *src, + unsigned int src_len) +{ + int rc; + int byte_counter = 0; + + OSMO_ASSERT(params); + OSMO_ASSERT(src); + + /* Mark all optional parameters invalid by default */ + params->p0 = -1; + params->p1 = -1; + params->p2 = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode P0 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + rc = decode_pcomp_8_bit_field(¶ms->p0, NULL, src, + src_len - byte_counter, 0, 3); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + rc = decode_pcomp_16_bit_field(¶ms->p1, NULL, src, + src_len - byte_counter, 512, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P2 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + rc = decode_pcomp_8_bit_field(¶ms->p2, NULL, src, + src_len - byte_counter, 6, 250); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Decode V44 parameter field (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ +static int decode_dcomp_v44_params(struct gprs_sndcp_dcomp_v44_params *params, + const uint8_t *src, unsigned int src_len) +{ + int rc; + int byte_counter = 0; + + OSMO_ASSERT(params); + OSMO_ASSERT(src); + + /* Mark all optional parameters invalid by default */ + params->c0 = -1; + params->p0 = -1; + params->p1t = -1; + params->p1r = -1; + params->p3t = -1; + params->p3r = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode C0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_8_bit_field(¶ms->c0, NULL, src, + src_len - byte_counter, 0, 255); + if (rc <= 0) + return byte_counter; + if ((params->c0 != 0x80) && (params->c0 != 0xC0)) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Decode P0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_8_bit_field(¶ms->p0, NULL, src, + src_len - byte_counter, 0, 3); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_16_bit_field(¶ms->p1t, NULL, src, + src_len - byte_counter, 265, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_16_bit_field(¶ms->p1r, NULL, src, + src_len - byte_counter, 265, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P3T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_16_bit_field(¶ms->p3t, NULL, src, + src_len - byte_counter, 265, 65535); + if (rc <= 0) + return byte_counter; + if (params->p3t < 2 * params->p1t) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Decode P3R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_16_bit_field(¶ms->p3r, NULL, src, + src_len - byte_counter, 265, 65535); + if (rc <= 0) + return byte_counter; + if (params->p3r < 2 * params->p1r) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Lookup algorithm identfier by entity ID */ +static int lookup_algorithm_identifier(int entity, const struct + entity_algo_table + *lt, unsigned int lt_len, int compclass) +{ + int i; + + if (!lt) + return -1; + + for (i = 0; i < lt_len; i++) { + if ((lt[i].entity == entity) + && (lt[i].compclass == compclass)) + return lt[i].algo; + } + + return -1; +} + +/* Helper function for decode_comp_field(), decodes + * numeric pcomp/dcomp values */ +static int decode_comp_values(struct gprs_sndcp_comp_field *comp_field, + const uint8_t *src, int compclass) +{ + int src_counter = 0; + int i; + + OSMO_ASSERT(comp_field); + OSMO_ASSERT(src); + + if (comp_field->p) { + /* Determine the number of expected PCOMP/DCOMP values */ + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + /* For protocol compression */ + switch (comp_field->algo) { + case RFC_1144: + comp_field->comp_len = RFC1144_PCOMP_NUM; + break; + case RFC_2507: + comp_field->comp_len = RFC2507_PCOMP_NUM; + break; + case ROHC: + comp_field->comp_len = ROHC_PCOMP_NUM; + break; + + /* Exit if the algorithem type encodes + something unknown / unspecified */ + default: + return -EINVAL; + } + } else { + /* For data compression */ + switch (comp_field->algo) { + case V42BIS: + comp_field->comp_len = V42BIS_DCOMP_NUM; + break; + case V44: + comp_field->comp_len = V44_DCOMP_NUM; + break; + + /* Exit if the algorithem type encodes + something unknown / unspecified */ + default: + return -EINVAL; + } + } + + for (i = 0; i < comp_field->comp_len; i++) { + if (i & 1) { + comp_field->comp[i] = (*src) & 0x0F; + src++; + src_counter++; + } else + comp_field->comp[i] = ((*src) >> 4) & 0x0F; + } + + if (i & 1) { + src++; + src_counter++; + } + } + + return src_counter; +} + +/* Helper function for decode_comp_field(), decodes the parameters + * which are protocol compression specific */ +static int decode_pcomp_params(struct gprs_sndcp_comp_field *comp_field, + const uint8_t *src, int src_len) +{ + int rc; + + OSMO_ASSERT(comp_field); + OSMO_ASSERT(src); + + switch (comp_field->algo) { + case RFC_1144: + comp_field->rfc1144_params = talloc_zero(comp_field, struct + gprs_sndcp_pcomp_rfc1144_params); + rc = decode_pcomp_rfc1144_params(comp_field->rfc1144_params, + src, src_len); + if (rc < 0) + talloc_free(comp_field->rfc1144_params); + break; + case RFC_2507: + comp_field->rfc2507_params = talloc_zero(comp_field, struct + gprs_sndcp_pcomp_rfc2507_params); + rc = decode_pcomp_rfc2507_params(comp_field->rfc2507_params, + src, src_len); + if (rc < 0) + talloc_free(comp_field->rfc1144_params); + break; + case ROHC: + comp_field->rohc_params = talloc_zero(comp_field, struct + gprs_sndcp_pcomp_rohc_params); + rc = decode_pcomp_rohc_params(comp_field->rohc_params, src, + src_len); + if (rc < 0) + talloc_free(comp_field->rohc_params); + break; + + /* If no suitable decoder is detected, + leave the remaining bytes undecoded */ + default: + rc = src_len; + } + + if (rc < 0) { + comp_field->rfc1144_params = NULL; + comp_field->rfc2507_params = NULL; + comp_field->rohc_params = NULL; + } + + return rc; +} + +/* Helper function for decode_comp_field(), decodes the parameters + * which are data compression specific */ +static int decode_dcomp_params(struct gprs_sndcp_comp_field *comp_field, + const uint8_t *src, int src_len) +{ + int rc; + + OSMO_ASSERT(comp_field); + OSMO_ASSERT(src); + + switch (comp_field->algo) { + case V42BIS: + comp_field->v42bis_params = talloc_zero(comp_field, struct + gprs_sndcp_dcomp_v42bis_params); + rc = decode_dcomp_v42bis_params(comp_field->v42bis_params, src, + src_len); + if (rc < 0) + talloc_free(comp_field->v42bis_params); + break; + case V44: + comp_field->v44_params = talloc_zero(comp_field, struct + gprs_sndcp_dcomp_v44_params); + rc = decode_dcomp_v44_params(comp_field->v44_params, src, + src_len); + if (rc < 0) + talloc_free(comp_field->v44_params); + break; + + /* If no suitable decoder is detected, + * leave the remaining bytes undecoded */ + default: + rc = src_len; + } + + if (rc < 0) { + comp_field->v42bis_params = NULL; + comp_field->v44_params = NULL; + } + + return rc; +} + +/* Decode data or protocol control information compression field + * (see also: 3GPP TS 44.065, 6.6.1.1, Figure 9 and + * 3GPP TS 44.065, 6.5.1.1, Figure 7) */ +static int decode_comp_field(struct gprs_sndcp_comp_field *comp_field, + const uint8_t *src, unsigned int src_len, + const struct entity_algo_table *lt, + unsigned int lt_len, int compclass) +{ + int src_counter = 0; + unsigned int len; + int rc; + + OSMO_ASSERT(comp_field); + + /* Exit immediately if it is clear that no + parseable data is present */ + if (src_len < 1 || !src) + return -EINVAL; + + /* Zero out target struct */ + memset(comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + + /* Decode Propose bit and Entity number */ + if ((*src) & 0x80) + comp_field->p = 1; + comp_field->entity = (*src) & 0x1F; + src_counter++; + src++; + + /* Decode algorithm number (if present) */ + if (comp_field->p) { + comp_field->algo = (*src) & 0x1F; + src_counter++; + src++; + } + /* Alternatively take the information from the lookup table */ + else + comp_field->algo = + lookup_algorithm_identifier(comp_field->entity, lt, + lt_len, compclass); + + /* Decode length field */ + len = *src; + src_counter++; + src++; + + /* Decode PCOMP/DCOMP values */ + rc = decode_comp_values(comp_field, src, compclass); + if (rc < 0) + return -EINVAL; + src_counter += rc; + src += rc; + len -= rc; + + /* Decode algorithm specific payload data */ + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + rc = decode_pcomp_params(comp_field, src, len); + else if (compclass == SNDCP_XID_DATA_COMPRESSION) + rc = decode_dcomp_params(comp_field, src, len); + else + return -EINVAL; + + if (rc >= 0) + src_counter += rc; + else + return -EINVAL; + + /* Return consumed length */ + return src_counter; +} + +/* Helper function for gprs_sndcp_decode_xid() to decode XID blocks */ +static int decode_xid_block(struct llist_head *comp_fields, uint8_t tag, + uint16_t tag_len, const uint8_t *val, + const struct entity_algo_table *lt, + unsigned int lt_len) +{ + struct gprs_sndcp_comp_field *comp_field; + int byte_counter = 0; + int comp_field_count = 0; + int rc; + + OSMO_ASSERT(comp_fields); + OSMO_ASSERT(val); + + byte_counter = 0; + do { + /* Bail if more than the maximum number of + comp_fields is generated */ + if (comp_field_count > MAX_ENTITIES * 2) { + return -EINVAL; + } + + /* Parse and add comp_field */ + comp_field = + talloc_zero(comp_fields, struct gprs_sndcp_comp_field); + + rc = decode_comp_field(comp_field, val + byte_counter, + tag_len - byte_counter, lt, lt_len, tag); + + if (rc < 0) { + talloc_free(comp_field); + return -EINVAL; + } + + byte_counter += rc; + llist_add(&comp_field->list, comp_fields); + comp_field_count++; + } + while (tag_len - byte_counter > 0); + + return byte_counter; +} + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +static int gprs_sndcp_decode_xid(struct llist_head *comp_fields, + const uint8_t *src, unsigned int src_len, + const struct + entity_algo_table + *lt, unsigned int lt_len) +{ + int src_pos = 0; + uint8_t tag; + uint16_t tag_len; + const uint8_t *val; + int byte_counter = 0; + int rc; + int tlv_count = 0; + + OSMO_ASSERT(comp_fields); + OSMO_ASSERT(src); + + /* Valid TLV-Tag and types */ + static const struct tlv_definition sndcp_xid_def = { + .def = { + [SNDCP_XID_VERSION_NUMBER] = {TLV_TYPE_TLV,}, + [SNDCP_XID_DATA_COMPRESSION] = {TLV_TYPE_TLV,}, + [SNDCP_XID_PROTOCOL_COMPRESSION] = {TLV_TYPE_TLV,}, + }, + }; + + /* Parse TLV-Encoded SNDCP-XID message and defer payload + to the apporpiate sub-parser functions */ + while (1) { + + /* Bail if an the maximum number of TLV fields + * have been parsed */ + if (tlv_count >= 3) { + gprs_sndcp_free_comp_fields(comp_fields); + return -EINVAL; + } + + /* Parse TLV field */ + rc = tlv_parse_one(&tag, &tag_len, &val, &sndcp_xid_def, + src + src_pos, src_len - src_pos); + if (rc > 0) + src_pos += rc; + else { + gprs_sndcp_free_comp_fields(comp_fields); + return -EINVAL; + } + + /* Decode compression parameters */ + if ((tag == SNDCP_XID_PROTOCOL_COMPRESSION) + || (tag == SNDCP_XID_DATA_COMPRESSION)) { + rc = decode_xid_block(comp_fields, tag, tag_len, val, + lt, lt_len); + + if (rc < 0) { + gprs_sndcp_free_comp_fields(comp_fields); + return -EINVAL; + } else + byte_counter += rc; + } + + /* Stop when no further TLV elements can be expected */ + if (src_len - src_pos <= 2) + break; + + tlv_count++; + } + + return 0; +} + +/* Fill up lookutable from a list with comression entitiy fields */ +static int gprs_sndcp_fill_table(struct + entity_algo_table *lt, + unsigned int lt_len, + const struct llist_head *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field; + int i = 0; + + OSMO_ASSERT(lt); + OSMO_ASSERT(comp_fields); + + if (!comp_fields) + return -EINVAL; + if (!lt) + return -EINVAL; + + memset(lt, 0, lt_len * sizeof(lt)); + + llist_for_each_entry(comp_field, comp_fields, list) { + + lt[i].entity = comp_field->entity; + lt[i].algo = comp_field->algo; + lt[i].compclass = gprs_sndcp_get_compression_class(comp_field); + + if (lt[i].compclass < 0) { + memset(lt, 0, lt_len * sizeof(lt)); + return -EINVAL; + } + + i++; + } + + return i; +} + +/* Complete comp field params + * (if a param (dst) is not valid, it will be copied from source (src) */ +static int complete_comp_field_params(struct gprs_sndcp_comp_field + *comp_field_dst, const struct + gprs_sndcp_comp_field *comp_field_src) +{ + OSMO_ASSERT(comp_field_dst); + OSMO_ASSERT(comp_field_src); + + if (comp_field_dst->algo < 0) + return -EINVAL; + + if (comp_field_dst->rfc1144_params && comp_field_src->rfc1144_params) { + if (comp_field_dst->rfc1144_params->s01 < 0) { + comp_field_dst->rfc1144_params->s01 = + comp_field_src->rfc1144_params->s01; + } + return 0; + } + + if (comp_field_dst->rfc2507_params && comp_field_src->rfc2507_params) { + + if (comp_field_dst->rfc2507_params->f_max_period < 0) { + comp_field_dst->rfc2507_params->f_max_period = + comp_field_src->rfc2507_params->f_max_period; + } + if (comp_field_dst->rfc2507_params->f_max_time < 0) { + comp_field_dst->rfc2507_params->f_max_time = + comp_field_src->rfc2507_params->f_max_time; + } + if (comp_field_dst->rfc2507_params->max_header < 0) { + comp_field_dst->rfc2507_params->max_header = + comp_field_src->rfc2507_params->max_header; + } + if (comp_field_dst->rfc2507_params->tcp_space < 0) { + comp_field_dst->rfc2507_params->tcp_space = + comp_field_src->rfc2507_params->tcp_space; + } + if (comp_field_dst->rfc2507_params->non_tcp_space < 0) { + comp_field_dst->rfc2507_params->non_tcp_space = + comp_field_src->rfc2507_params->non_tcp_space; + } + return 0; + } + + if (comp_field_dst->rohc_params && comp_field_src->rohc_params) { + if (comp_field_dst->rohc_params->max_cid < 0) { + comp_field_dst->rohc_params->max_cid = + comp_field_src->rohc_params->max_cid; + } + if (comp_field_dst->rohc_params->max_header < 0) { + comp_field_dst->rohc_params->max_header = + comp_field_src->rohc_params->max_header; + } + if (comp_field_dst->rohc_params->profile_len > 0) { + memcpy(comp_field_dst->rohc_params->profile, + comp_field_src->rohc_params->profile, + sizeof(comp_field_dst->rohc_params->profile)); + comp_field_dst->rohc_params->profile_len = + comp_field_src->rohc_params->profile_len; + } + + return 0; + } + + if (comp_field_dst->v42bis_params && comp_field_src->v42bis_params) { + if (comp_field_dst->v42bis_params->p0 < 0) { + comp_field_dst->v42bis_params->p0 = + comp_field_src->v42bis_params->p0; + } + if (comp_field_dst->v42bis_params->p1 < 0) { + comp_field_dst->v42bis_params->p1 = + comp_field_src->v42bis_params->p1; + } + if (comp_field_dst->v42bis_params->p2 < 0) { + comp_field_dst->v42bis_params->p2 = + comp_field_src->v42bis_params->p2; + } + return 0; + } + + if (comp_field_dst->v44_params && comp_field_src->v44_params) { + if (comp_field_dst->v44_params->c0 < 0) { + comp_field_dst->v44_params->c0 = + comp_field_src->v44_params->c0; + } + if (comp_field_dst->v44_params->p0 < 0) { + comp_field_dst->v44_params->p0 = + comp_field_src->v44_params->p0; + } + if (comp_field_dst->v44_params->p1t < 0) { + comp_field_dst->v44_params->p1t = + comp_field_src->v44_params->p1t; + } + if (comp_field_dst->v44_params->p1r < 0) { + comp_field_dst->v44_params->p1r = + comp_field_src->v44_params->p1r; + } + if (comp_field_dst->v44_params->p3t < 0) { + comp_field_dst->v44_params->p3t = + comp_field_src->v44_params->p3t; + } + if (comp_field_dst->v44_params->p3r < 0) { + comp_field_dst->v44_params->p3r = + comp_field_src->v44_params->p3r; + } + return 0; + } + + /* There should be at least exist one param set + * in the destination struct, otherwise something + * must be wrong! */ + return -EINVAL; +} + +/* Complete missing parameters in a comp_field */ +static int gprs_sndcp_complete_comp_field(struct gprs_sndcp_comp_field + *comp_field, const struct llist_head + *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field_src; + int rc = 0; + + OSMO_ASSERT(comp_field); + OSMO_ASSERT(comp_fields); + + llist_for_each_entry(comp_field_src, comp_fields, list) { + if (comp_field_src->entity == comp_field->entity) { + + /* Complete header fields */ + if (comp_field_src->comp_len > 0) { + memcpy(comp_field->comp, + comp_field_src->comp, + sizeof(comp_field_src->comp)); + comp_field->comp_len = comp_field_src->comp_len; + } + + /* Complete parameter fields */ + rc = complete_comp_field_params(comp_field, + comp_field_src); + } + } + + return rc; +} + +/* Complete missing parameters of all comp_field in a list */ +static int gprs_sndcp_complete_comp_fields(struct llist_head + *comp_fields_incomplete, + const struct llist_head *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field_incomplete; + int rc; + + OSMO_ASSERT(comp_fields_incomplete); + OSMO_ASSERT(comp_fields); + + llist_for_each_entry(comp_field_incomplete, comp_fields_incomplete, + list) { + + rc = gprs_sndcp_complete_comp_field(comp_field_incomplete, + comp_fields); + if (rc < 0) + return -EINVAL; + + } + + return 0; +} + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +struct llist_head *gprs_sndcp_parse_xid(const void *ctx, + const uint8_t *src, + unsigned int src_len, + const struct llist_head + *comp_fields_req) +{ + int rc; + int lt_len; + struct llist_head *comp_fields; + struct entity_algo_table lt[MAX_ENTITIES * 2]; + + OSMO_ASSERT(src); + + comp_fields = talloc_zero(ctx, struct llist_head); + INIT_LLIST_HEAD(comp_fields); + + if (comp_fields_req) { + /* Generate lookup table */ + lt_len = + gprs_sndcp_fill_table(lt, MAX_ENTITIES * 2, + comp_fields_req); + if (lt_len < 0) + return gprs_sndcp_free_comp_fields(comp_fields); + + /* Parse SNDCP-CID XID-Field */ + rc = gprs_sndcp_decode_xid(comp_fields, src, src_len, lt, + lt_len); + if (rc < 0) + return gprs_sndcp_free_comp_fields(comp_fields); + + rc = gprs_sndcp_complete_comp_fields(comp_fields, + comp_fields_req); + if (rc < 0) + return gprs_sndcp_free_comp_fields(comp_fields); + + } else { + /* Parse SNDCP-CID XID-Field */ + rc = gprs_sndcp_decode_xid(comp_fields, src, src_len, NULL, 0); + if (rc < 0) + return gprs_sndcp_free_comp_fields(comp_fields); + } + + return comp_fields; +} + +/* Free a list with SNDCP-XID fields */ +struct llist_head *gprs_sndcp_free_comp_fields(struct llist_head *comp_fields) +{ + if (comp_fields != NULL) + talloc_free(comp_fields); + return NULL; +} + +/* Helper for gprs_sndcp_dump_comp_fields(), + * dumps protocol compression parameters */ +static void dump_pcomp_params(const struct gprs_sndcp_comp_field + *comp_field, unsigned int logl) +{ + int i; + + OSMO_ASSERT(comp_field); + + switch (comp_field->algo) { + case RFC_1144: + if (comp_field->rfc1144_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_pcomp_rfc1144_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_pcomp_rfc1144_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%i;\n", + comp_field->rfc1144_params->nsapi_len); + if (comp_field->rfc1144_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rfc1144_params->nsapi_len; i++) { + LOGP(DSNDCP, logl, + " nsapi[%i]=%i;\n", i, + comp_field->rfc1144_params->nsapi[i]); + } + LOGP(DSNDCP, logl, " s01=%i;\n", + comp_field->rfc1144_params->s01); + LOGP(DSNDCP, logl, " }\n"); + break; + case RFC_2507: + if (comp_field->rfc2507_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_pcomp_rfc2507_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_pcomp_rfc2507_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%i;\n", + comp_field->rfc2507_params->nsapi_len); + if (comp_field->rfc2507_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rfc2507_params->nsapi_len; i++) { + LOGP(DSNDCP, logl, + " nsapi[%i]=%i;\n", i, + comp_field->rfc2507_params->nsapi[i]); + } + LOGP(DSNDCP, logl, + " f_max_period=%i;\n", + comp_field->rfc2507_params->f_max_period); + LOGP(DSNDCP, logl, + " f_max_time=%i;\n", + comp_field->rfc2507_params->f_max_time); + LOGP(DSNDCP, logl, + " max_header=%i;\n", + comp_field->rfc2507_params->max_header); + LOGP(DSNDCP, logl, + " tcp_space=%i;\n", + comp_field->rfc2507_params->tcp_space); + LOGP(DSNDCP, logl, + " non_tcp_space=%i;\n", + comp_field->rfc2507_params->non_tcp_space); + LOGP(DSNDCP, logl, " }\n"); + break; + case ROHC: + if (comp_field->rohc_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_pcomp_rohc_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_pcomp_rohc_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%i;\n", + comp_field->rohc_params->nsapi_len); + if (comp_field->rohc_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rohc_params->nsapi_len; i++) { + LOGP(DSNDCP, logl, + " nsapi[%i]=%i;\n", i, + comp_field->rohc_params->nsapi[i]); + } + LOGP(DSNDCP, logl, + " max_cid=%i;\n", comp_field->rohc_params->max_cid); + LOGP(DSNDCP, logl, + " max_header=%i;\n", + comp_field->rohc_params->max_header); + LOGP(DSNDCP, logl, + " profile_len=%i;\n", + comp_field->rohc_params->profile_len); + if (comp_field->rohc_params->profile_len == 0) + LOGP(DSNDCP, logl, " profile[] = NULL;\n"); + for (i = 0; i < comp_field->rohc_params->profile_len; i++) + LOGP(DSNDCP, logl, + " profile[%i]=%04x;\n", + i, comp_field->rohc_params->profile[i]); + LOGP(DSNDCP, logl, " }\n"); + break; + } + +} + +/* Helper for gprs_sndcp_dump_comp_fields(), + * data protocol compression parameters */ +static void dump_dcomp_params(const struct gprs_sndcp_comp_field + *comp_field, unsigned int logl) +{ + int i; + + OSMO_ASSERT(comp_field); + + switch (comp_field->algo) { + case V42BIS: + if (comp_field->v42bis_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_dcomp_v42bis_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_dcomp_v42bis_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%i;\n", + comp_field->v42bis_params->nsapi_len); + if (comp_field->v42bis_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->v42bis_params->nsapi_len; i++) + LOGP(DSNDCP, logl, + " nsapi[%i]=%i;\n", i, + comp_field->v42bis_params->nsapi[i]); + LOGP(DSNDCP, logl, " p0=%i;\n", + comp_field->v42bis_params->p0); + LOGP(DSNDCP, logl, " p1=%i;\n", + comp_field->v42bis_params->p1); + LOGP(DSNDCP, logl, " p2=%i;\n", + comp_field->v42bis_params->p2); + LOGP(DSNDCP, logl, " }\n"); + break; + case V44: + if (comp_field->v44_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_dcomp_v44_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_dcomp_v44_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%i;\n", + comp_field->v44_params->nsapi_len); + if (comp_field->v44_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->v44_params->nsapi_len; i++) { + LOGP(DSNDCP, logl, + " nsapi[%i]=%i;\n", i, + comp_field->v44_params->nsapi[i]); + } + LOGP(DSNDCP, logl, " c0=%i;\n", + comp_field->v44_params->c0); + LOGP(DSNDCP, logl, " p0=%i;\n", + comp_field->v44_params->p0); + LOGP(DSNDCP, logl, " p1t=%i;\n", + comp_field->v44_params->p1t); + LOGP(DSNDCP, logl, " p1r=%i;\n", + comp_field->v44_params->p1r); + LOGP(DSNDCP, logl, " p3t=%i;\n", + comp_field->v44_params->p3t); + LOGP(DSNDCP, logl, " p3r=%i;\n", + comp_field->v44_params->p3r); + LOGP(DSNDCP, logl, " }\n"); + break; + } +} + +/* Dump a list with SNDCP-XID fields (Debug) */ +void gprs_sndcp_dump_comp_fields(const struct llist_head *comp_fields, + unsigned int logl) +{ + struct gprs_sndcp_comp_field *comp_field; + int i; + int compclass; + + OSMO_ASSERT(comp_fields); + + llist_for_each_entry(comp_field, comp_fields, list) { + LOGP(DSNDCP, logl, "SNDCP-XID:\n"); + LOGP(DSNDCP, logl, "struct gprs_sndcp_comp_field {\n"); + LOGP(DSNDCP, logl, " entity=%i;\n", comp_field->entity); + LOGP(DSNDCP, logl, " algo=%i;\n", comp_field->algo); + LOGP(DSNDCP, logl, " comp_len=%i;\n", comp_field->comp_len); + if (comp_field->comp_len == 0) + LOGP(DSNDCP, logl, " comp[] = NULL;\n"); + for (i = 0; i < comp_field->comp_len; i++) { + LOGP(DSNDCP, logl, " comp[%i]=%i;\n", i, + comp_field->comp[i]); + } + + compclass = gprs_sndcp_get_compression_class(comp_field); + + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + dump_pcomp_params(comp_field, logl); + } else if (compclass == SNDCP_XID_DATA_COMPRESSION) { + dump_dcomp_params(comp_field, logl); + } + + LOGP(DSNDCP, logl, "}\n"); + } + +} diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index ba5ca28..1debb2d 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 74af159..45d1780 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -31,6 +31,7 @@ $(top_builddir)/src/gprs/oap.o \ $(top_builddir)/src/gprs/oap_messages.o \ $(top_builddir)/src/gprs/gprs_llc_xid.o \ + $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ @@ -38,5 +39,5 @@ $(LIBOSMOGB_LIBS) \ $(LIBCARES_LIBS) \ $(LIBCRYPTO_LIBS) \ - -lgtp -lrt + -lgtp -lrt -lm diff --git a/openbsc/tests/sndcp_xid/Makefile.am b/openbsc/tests/sndcp_xid/Makefile.am new file mode 100644 index 0000000..99b9d1a --- /dev/null +++ b/openbsc/tests/sndcp_xid/Makefile.am @@ -0,0 +1,20 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) + +EXTRA_DIST = sndcp_xid_test.ok + +noinst_PROGRAMS = sndcp_xid_test + +sndcp_xid_test_SOURCES = sndcp_xid_test.c + +sndcp_xid_test_LDADD = \ + $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOGB_LIBS) \ + $(LIBCARES_LIBS) \ + $(LIBCRYPTO_LIBS) \ + -lgtp -lrt -lm + + diff --git a/openbsc/tests/sndcp_xid/sndcp_xid_test.c b/openbsc/tests/sndcp_xid/sndcp_xid_test.c new file mode 100644 index 0000000..59ff968 --- /dev/null +++ b/openbsc/tests/sndcp_xid/sndcp_xid_test.c @@ -0,0 +1,283 @@ +/* Test SNDCP-XID Encoding/Decoding */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include + +#include +#include + +#include + +#include +#include + +/* Test SNDCP-XID decoding with a real world sample */ +static void test_xid_decode_realworld(const void *ctx) +{ + struct llist_head *comp_fields; + int rc; + printf("Testing SNDCP XID-Decoder/Encoder (real world data)\n"); + + /* Example of a real world SNDCP-XID message */ + uint8_t xid[] = + { 0x00, 0x01, 0x00, 0x02, 0x31, 0x82, 0x02, 0x27, 0x89, 0xff, 0xe0, + 0x00, 0x0f, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, + 0x01, 0x02, 0x00, 0x03, 0x01, 0x03, 0x00, 0x04, 0x01, 0x04, 0x00, 0x05, + 0x01, 0x05, 0x00, 0x06, 0x00, 0x07, 0x01, 0x07, 0x00, 0x08, 0x01, 0x08, + 0x80, 0x00, 0x04, 0x12, 0x00, 0x40, 0x07 }; + uint8_t xid_r[512]; + + /* Parse and show contained comp fields */ + comp_fields = gprs_sndcp_parse_xid(ctx, xid, sizeof(xid), NULL); + OSMO_ASSERT(comp_fields); + printf("Decoded:\n"); + gprs_sndcp_dump_comp_fields(comp_fields, DSNDCP); + + /* Encode comp-fields again */ + rc = gprs_sndcp_compile_xid(xid_r,sizeof(xid_r), comp_fields); + printf("Result length=%i\n",rc); + printf("Encoded: %s\n", osmo_hexdump_nospc(xid, sizeof(xid))); + printf("Rencoded: %s\n", osmo_hexdump_nospc(xid_r, rc)); + + OSMO_ASSERT(rc == 54); + OSMO_ASSERT(memcmp(xid, xid_r, sizeof(xid)) == 0); + + /* Free comp fields */ + gprs_sndcp_free_comp_fields(comp_fields); + + printf("\n"); +} + +/* Encode and decode test with artificial test data */ +static void test_xid_encode_decode(const void *ctx) +{ + printf("Testing SNDCP XID-Encoder/Decoder\n"); + + LLIST_HEAD(comp_fields); + struct gprs_sndcp_pcomp_rfc1144_params rfc1144_params; + struct gprs_sndcp_comp_field rfc1144_comp_field; + struct gprs_sndcp_pcomp_rfc2507_params rfc2507_params; + struct gprs_sndcp_comp_field rfc2507_comp_field; + struct gprs_sndcp_pcomp_rohc_params rohc_params; + struct gprs_sndcp_comp_field rohc_comp_field; + struct gprs_sndcp_dcomp_v42bis_params v42bis_params; + struct gprs_sndcp_comp_field v42bis_comp_field; + struct gprs_sndcp_dcomp_v44_params v44_params; + struct gprs_sndcp_comp_field v44_comp_field; + struct llist_head *comp_fields_dec; + + uint8_t xid[512]; + unsigned int xid_len = sizeof(xid); + int rc; + + memset(&rfc1144_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + memset(&rfc2507_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + memset(&rohc_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + memset(&v42bis_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + memset(&v44_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + + /* Setup which NSAPIs shall make use of rfc1144 */ + rfc1144_params.nsapi[0] = 5; + rfc1144_params.nsapi_len = 1; + + /* Setup rfc1144 operating parameters */ + rfc1144_params.s01 = 7; + + /* Setup rfc1144 compression field */ + rfc1144_comp_field.p = 1; + rfc1144_comp_field.entity = 0; + rfc1144_comp_field.algo = RFC_1144; + rfc1144_comp_field.comp[RFC1144_PCOMP1] = 1; + rfc1144_comp_field.comp[RFC1144_PCOMP2] = 2; + rfc1144_comp_field.comp_len = RFC1144_PCOMP_NUM; + rfc1144_comp_field.rfc1144_params = &rfc1144_params; + + /* Setup which NSAPIs shall make use of rfc1144 */ + rfc2507_params.nsapi[0] = 6; + rfc2507_params.nsapi_len = 1; + + /* Setup rfc2507 operating parameters */ + rfc2507_params.f_max_period = 256; + rfc2507_params.f_max_time = 5; + rfc2507_params.max_header = 168; + rfc2507_params.tcp_space = 15; + rfc2507_params.non_tcp_space = 15; + + /* Setup rfc2507 compression field */ + rfc2507_comp_field.p = 1; + rfc2507_comp_field.entity = 1; + rfc2507_comp_field.algo = RFC_2507; + rfc2507_comp_field.comp[RFC2507_PCOMP1] = 3; + rfc2507_comp_field.comp[RFC2507_PCOMP2] = 4; + rfc2507_comp_field.comp[RFC2507_PCOMP3] = 5; + rfc2507_comp_field.comp[RFC2507_PCOMP4] = 6; + rfc2507_comp_field.comp[RFC2507_PCOMP5] = 7; + rfc2507_comp_field.comp_len = RFC2507_PCOMP_NUM; + rfc2507_comp_field.rfc2507_params = &rfc2507_params; + + /* Setup which NSAPIs shall make use of ROHC */ + rohc_params.nsapi[0] = 5; + rohc_params.nsapi[1] = 6; + rohc_params.nsapi[2] = 7; + rohc_params.nsapi[3] = 8; + rohc_params.nsapi[4] = 9; + rohc_params.nsapi[5] = 10; + rohc_params.nsapi[6] = 11; + rohc_params.nsapi[7] = 12; + rohc_params.nsapi[8] = 13; + rohc_params.nsapi[9] = 14; + rohc_params.nsapi[10] = 15; + rohc_params.nsapi_len = 11; + + /* Setup ROHC operating parameters */ + rohc_params.max_cid = 15; /* default */ + rohc_params.max_header = 168; /* default */ + rohc_params.profile[0] = ROHC_UNCOMPRESSED; + rohc_params.profile[1] = ROHC_RTP; + rohc_params.profile[2] = ROHCV2_RTP; + rohc_params.profile[3] = ROHC_UDP; + rohc_params.profile[4] = ROHCv2_UDP; + rohc_params.profile[5] = ROHC_ESP; + rohc_params.profile[6] = ROHCV2_ESP; + rohc_params.profile[7] = ROHC_IP; + rohc_params.profile[8] = ROHCV2_IP; + rohc_params.profile[9] = ROHC_LLA; + rohc_params.profile[10] = ROHC_LLA_WITH_R_MODE; + rohc_params.profile[11] = ROHC_TCP; + rohc_params.profile[12] = ROHC_RTP_UDP_LITE; + rohc_params.profile[13] = ROHCV2_RTP_UDP_LITE; + rohc_params.profile[14] = ROHC_UDP_LITE; + rohc_params.profile[15] = ROHCV2_UDP_LITE; + rohc_params.profile_len = 16; + + /* Setup ROHC compression field */ + rohc_comp_field.p = 1; + rohc_comp_field.entity = 2; + rohc_comp_field.algo = ROHC; + rohc_comp_field.comp[ROHC_PCOMP1] = 8; + rohc_comp_field.comp[ROHC_PCOMP2] = 9; + rohc_comp_field.comp_len = ROHC_PCOMP_NUM; + rohc_comp_field.rohc_params = &rohc_params; + + /* Setup which NSAPIs shall make use of v42bis */ + v42bis_params.nsapi[0] = 5; + v42bis_params.nsapi_len = 1; + + /* Setup v42bis operating parameters */ + v42bis_params.p0 = 3; + v42bis_params.p1 = 2048; + v42bis_params.p2 = 20; + + /* Setup v42bis compression field */ + v42bis_comp_field.p = 1; + v42bis_comp_field.entity = 3; + v42bis_comp_field.algo = V42BIS; + v42bis_comp_field.comp[V42BIS_DCOMP1] = 10; + v42bis_comp_field.comp_len = V42BIS_DCOMP_NUM; + v42bis_comp_field.v42bis_params = &v42bis_params; + + /* Setup which NSAPIs shall make use of v44 */ + v44_params.nsapi[0] = 5; + v44_params.nsapi_len = 1; + + /* Setup v44 operating parameters */ + v44_params.c0 = 0x80; + v44_params.p0 = 3; + v44_params.p1t = 300; + v44_params.p1r = 300; + v44_params.p3t = 600; + v44_params.p3r = 600; + + /* Setup v44 compression field */ + v44_comp_field.p = 1; + v44_comp_field.entity = 3; + v44_comp_field.algo = V44; + v44_comp_field.comp[V44_DCOMP1] = 10; + v44_comp_field.comp[V44_DCOMP2] = 11; + v44_comp_field.comp_len = V44_DCOMP_NUM; + v44_comp_field.v44_params = &v44_params; + + /* Add compression field(s) to list */ + llist_add(&v44_comp_field.list, &comp_fields); + llist_add(&v42bis_comp_field.list, &comp_fields); + llist_add(&rfc1144_comp_field.list, &comp_fields); + llist_add(&rfc2507_comp_field.list, &comp_fields); + llist_add(&rohc_comp_field.list, &comp_fields); + printf("Test input data:\n"); + gprs_sndcp_dump_comp_fields(&comp_fields, DSNDCP); + + /* Encode SNDCP-XID fields */ + rc = gprs_sndcp_compile_xid(xid, xid_len, &comp_fields); + OSMO_ASSERT(rc > 0); + + printf("Encoded: %s (%i bytes)\n", osmo_hexdump_nospc(xid, rc), rc); + + /* Parse and show contained comp fields */ + comp_fields_dec = gprs_sndcp_parse_xid(ctx, xid, rc, NULL); + OSMO_ASSERT(comp_fields_dec); + + printf("Decoded:\n"); + gprs_sndcp_dump_comp_fields(comp_fields_dec, DSNDCP); + + /* Free comp fields */ + gprs_sndcp_free_comp_fields(comp_fields_dec); +} + +static struct log_info_cat gprs_categories[] = { + [DSNDCP] = { + .name = "DSNDCP", + .description = + "GPRS Sub-Network Dependent Control Protocol (SNDCP)", + .enabled = 1,.loglevel = LOGL_DEBUG, + } +}; + +static struct log_info info = { + .cat = gprs_categories, + .num_cat = ARRAY_SIZE(gprs_categories), +}; + +int main(int argc, char **argv) +{ + void *xid_ctx; + + osmo_init_logging(&info); + + xid_ctx = talloc_named_const(NULL, 0, "xid_ctx"); + + test_xid_decode_realworld(xid_ctx); + test_xid_encode_decode(xid_ctx); + + printf("Done\n"); + + talloc_report_full(xid_ctx, stderr); + OSMO_ASSERT(talloc_total_blocks(xid_ctx) == 1); + return 0; +} + +/* stubs */ +struct osmo_prim_hdr; +int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) +{ + abort(); +} diff --git a/openbsc/tests/sndcp_xid/sndcp_xid_test.ok b/openbsc/tests/sndcp_xid/sndcp_xid_test.ok new file mode 100644 index 0000000..f357282 --- /dev/null +++ b/openbsc/tests/sndcp_xid/sndcp_xid_test.ok @@ -0,0 +1,11 @@ +Testing SNDCP XID-Decoder/Encoder (real world data) +Decoded: +Result length=54 +Encoded: 000100023182022789ffe0000f00a8000000010101000201020003010300040104000501050006000701070008010880000412004007 +Rencoded: 000100023182022789ffe0000f00a8000000010101000201020003010300040104000501050006000701070008010880000412004007 + +Testing SNDCP XID-Encoder/Decoder +Test input data: +Encoded: 000100011a83010dab00208003012c012c02580258830007a000200308001402408000041200200781010c3456700040010005a80f000f82022789ffe0000f00a80000000101010002010200030103000401040005010500060007010700080108 (97 bytes) +Decoded: +Done diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index 6470ab9..85a81d6 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -129,3 +129,10 @@ cat $abs_srcdir/xid/xid_test.ok > expout AT_CHECK([$abs_top_builddir/tests/xid/xid_test], [], [expout], [ignore]) AT_CLEANUP + +AT_SETUP([sndcp_xid]) +AT_KEYWORDS([sndcp_xid]) +cat $abs_srcdir/sndcp_xid/sndcp_xid_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/sndcp_xid/sndcp_xid_test], [], [expout], [ignore]) +AT_CLEANUP + -- To view, visit https://gerrit.osmocom.org/641 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e Gerrit-PatchSet: 11 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Wed Aug 17 13:14:26 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Wed, 17 Aug 2016 13:14:26 +0000 Subject: [PATCH] openbsc[master]: Adding compression control In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/642 to look at the new patch set (#15). Adding compression control In this commit two modules were added: gprs_sndcp_comp.h/c: This part handles the creation and destruction of conpression entites. It handles the allocation and freeing of the memory and offers functions to query compression parameters (i.e. which compression entity should be used if a packet from NSAPI x has to be compressed?) gprs_sndcp_pcomp.c/h: This is the code that performs the actual header compression. It takes care that the packets are compressed/decompressed with the right modes etc. It works, but is not yet ready for merging. Both files depend on each other so that they only can be merged both at the same time. Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 --- M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_sndcp_comp.h A openbsc/include/openbsc/gprs_sndcp_pcomp.h M openbsc/include/openbsc/sgsn.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_sndcp_comp.c A openbsc/src/gprs/gprs_sndcp_pcomp.c M openbsc/src/gprs/sgsn_vty.c M openbsc/tests/sgsn/Makefile.am 9 files changed, 827 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/42/642/15 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index f402fea..88a7e2c 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,7 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ - slhc.h + slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_sndcp_comp.h b/openbsc/include/openbsc/gprs_sndcp_comp.h new file mode 100644 index 0000000..e2d79ab --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_comp.h @@ -0,0 +1,85 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_SNDCP_COMP_H +#define _GPRS_SNDCP_COMP_H + +#include +#include +#include + +/* Header / Data compression entity */ +struct gprs_sndcp_comp { + struct llist_head list; + + /* Serves as an ID in case we want to delete this entity later */ + int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + + /* Specifies to which NSAPIs the compression entity is assigned */ + int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + int nsapi[11]; /* Applicable NSAPIs (default 0) */ + + /* Assigned pcomp values */ + int comp_len; /* Number of contained PCOMP / DCOMP values */ + int comp[16]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */ + + /* Algorithm parameters */ + int algo; /* Algorithm type (see gprs_sndcp_xid.h) */ + int compclass; /* See gprs_sndcp_xid.h/c */ + void *state; /* Algorithm status and parameters */ +}; + +/* Free a list with compression entities */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities); + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, int entity); + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_entities_add(const void *ctx, struct + llist_head + *comp_entities, const struct + gprs_sndcp_comp_field + *comp_field); + +/* Find compression entity by its entity number */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_entity(const struct llist_head + *comp_entities, int entity); + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head + *comp_entities, int comp); + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head + *comp_entities, int nsapi); + +/* Find a comp_index for a given pcomp/dcomp value */ +int gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp + *comp_entity, int comp); + +/* Find a pcomp/dcomp value for a given comp_index */ +int gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp + *comp_entity, int comp_index); + +#endif diff --git a/openbsc/include/openbsc/gprs_sndcp_pcomp.h b/openbsc/include/openbsc/gprs_sndcp_pcomp.h new file mode 100644 index 0000000..2444260 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_pcomp.h @@ -0,0 +1,47 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_SNDCP_pcomp_H +#define _GPRS_SNDCP_pcomp_H + +#include +#include +#include + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field); + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity); + +/* Expand packet header */ +int gprs_sndcp_pcomp_expand(uint8_t *data_o, uint8_t *data_i, int len, + int pcomp, const struct llist_head *comp_entities); + +/* Compress packet header */ +int gprs_sndcp_pcomp_compress(uint8_t *data_o, uint8_t *data_i, int len, + int *pcomp, + const struct llist_head *comp_entities, + int nsapi); + +#endif diff --git a/openbsc/include/openbsc/sgsn.h b/openbsc/include/openbsc/sgsn.h index 59126fe..2366d7a 100644 --- a/openbsc/include/openbsc/sgsn.h +++ b/openbsc/include/openbsc/sgsn.h @@ -88,6 +88,12 @@ int dynamic_lookup; + /* RFC1144 TCP/IP Header compression */ + struct { + int enabled; + int s01; + } pcomp_rfc1144; + struct oap_config oap; }; diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 245636b..2910c02 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -27,7 +27,7 @@ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ - slhc.c + slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/gprs_sndcp_comp.c b/openbsc/src/gprs/gprs_sndcp_comp.c new file mode 100644 index 0000000..8153fd2 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_comp.c @@ -0,0 +1,320 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +/* Create a new compression entity from a XID-Field */ +static struct gprs_sndcp_comp *gprs_sndcp_comp_create(const void + *ctx, const struct + gprs_sndcp_comp_field + *comp_field) +{ + OSMO_ASSERT(comp_field); + + struct gprs_sndcp_comp *comp_entity; + comp_entity = talloc_zero(ctx, struct gprs_sndcp_comp); + + /* Copy relevant information from the SNDCP-XID field */ + comp_entity->entity = comp_field->entity; + comp_entity->comp_len = comp_field->comp_len; + memcpy(comp_entity->comp, comp_field->comp, + comp_field->comp_len * sizeof(int)); + + if (comp_field->rfc1144_params) { + comp_entity->nsapi_len = comp_field->rfc1144_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc1144_params->nsapi, + comp_entity->nsapi_len * sizeof(int)); + } else if (comp_field->rfc2507_params) { + comp_entity->nsapi_len = comp_field->rfc2507_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc2507_params->nsapi, + comp_entity->nsapi_len * sizeof(int)); + } else if (comp_field->rohc_params) { + comp_entity->nsapi_len = comp_field->rohc_params->nsapi_len; + memcpy(comp_entity->nsapi, comp_field->rohc_params->nsapi, + comp_entity->nsapi_len * sizeof(int)); + } else if (comp_field->v42bis_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + comp_entity->nsapi_len * sizeof(int)); + } else if (comp_field->v44_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + comp_entity->nsapi_len * sizeof(int)); + } else { + talloc_free(comp_entity); + LOGP(DSNDCP, LOGL_ERROR, + "Comp field contained invalid parameters, compression entity not created!\n"); + return NULL; + } + + comp_entity->algo = comp_field->algo; + comp_entity->state = NULL; + + /* Determine of which class our compression entity will be + * (Protocol or Data compresson ?) */ + comp_entity->compclass = gprs_sndcp_get_compression_class(comp_field); + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + if (gprs_sndcp_pcomp_init(ctx, comp_entity, comp_field) == 0) + LOGP(DSNDCP, LOGL_INFO, + "New header compression entity (%i) created.\n", + comp_entity->entity); + else { + talloc_free(comp_entity); + LOGP(DSNDCP, LOGL_ERROR, + "Header compression entity (%i) creation failed!\n", + comp_entity->entity); + return NULL; + } + } else { + LOGP(DSNDCP, LOGL_INFO, + "New data compression entity (%i) created.\n", + comp_entity->entity); + } + + return comp_entity; +} + +/* Free a list with compression entities */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities) +{ + struct llist_head *ce, *ce2; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + /* Free compression entity */ + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %i ...\n", + comp_entity->entity); + gprs_sndcp_pcomp_term(comp_entity); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %i ...\n", + comp_entity->entity); + } + } + + llist_for_each_safe(ce, ce2, comp_entities) { + llist_del(ce); + talloc_free(ce); + } + +} + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, int entity) +{ + struct gprs_sndcp_comp *comp_entity; + struct gprs_sndcp_comp *comp_entity_to_delete = NULL; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) + comp_entity_to_delete = comp_entity; + } + + if (comp_entity_to_delete) { + if (comp_entity_to_delete->compclass == + SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %i ...\n", + comp_entity_to_delete->entity); + gprs_sndcp_pcomp_term(comp_entity_to_delete); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %i ...\n", + comp_entity_to_delete->entity); + } + + /* Delete compression entity */ + llist_del(&comp_entity_to_delete->list); + talloc_free(comp_entity_to_delete); + } + +} + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_entities_add(const void *ctx, struct + llist_head + *comp_entities, const struct + gprs_sndcp_comp_field + *comp_field) +{ + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(comp_entities); + OSMO_ASSERT(comp_field); + + /* Just to be sure, if the entity is already in + * the list it will be deleted now */ + gprs_sndcp_comp_delete(comp_entities, comp_field->entity); + + /* Create and add a new entity to the list */ + comp_entity = gprs_sndcp_comp_create(ctx, comp_field); + + if (comp_entity) { + llist_add(&comp_entity->list, comp_entities); + return comp_entity; + } + + return NULL; +} + +/* Find compression entity by its entity number */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_entity(const struct + llist_head + *comp_entities, int entity) +{ + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) + return comp_entity; + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given entity number %i.\n", + entity); + return NULL; +} + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct + llist_head + *comp_entities, int comp) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return comp_entity; + } + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given pcomp/dcomp value %i.\n", + comp); + return NULL; +} + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct + llist_head + *comp_entities, int nsapi) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->nsapi_len; i++) { + if (comp_entity->nsapi[i] == nsapi) + return comp_entity; + } + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given nsapi value %i\n", + nsapi); + return NULL; + +} + +/* Find a comp_index for a given pcomp/dcomp value */ +int gprs_sndcp_comp_get_idx(const struct + gprs_sndcp_comp + *comp_entity, int comp) +{ + int i; + + OSMO_ASSERT(comp_entity); + + /* A pcomp/dcomp field set to zero always disables + * all sort of compression and is assigned fix. So we + * just return zero in this case */ + if (comp == 0) + return 0; + + /* Look in the pcomp/dcomp list for the index */ + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return i + 1; + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching comp_index for given pcomp/dcomp value %i\n", + comp); + return 0; + +} + +/* Find a pcomp/dcomp value for a given comp_index */ +int gprs_sndcp_comp_get_comp(const struct + gprs_sndcp_comp + *comp_entity, int comp_index) +{ + OSMO_ASSERT(comp_entity); + + /* A comp_index of zero translates to zero right away. */ + if (comp_index == 0) + return 0; + + if (comp_index > comp_entity->comp_len) { + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching pcomp/dcomp value for given comp_index value %i.\n", + comp_index); + return 0; + } + + /* Look in the pcomp/dcomp list for the comp_index */ + return comp_entity->comp[comp_index - 1]; + +} diff --git a/openbsc/src/gprs/gprs_sndcp_pcomp.c b/openbsc/src/gprs/gprs_sndcp_pcomp.c new file mode 100644 index 0000000..41f6c6a --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_pcomp.c @@ -0,0 +1,334 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG_RFC1144 1 + +/* Show details of the RFC1144 compressed packet header */ +static void debug_rfc1144_header(uint8_t *header) +{ +#if DEBUG_RFC1144 == 1 + + int t,c,i,p,s,a,w,u = 0; + t = (header[0] >> 7) & 1; + c = (header[0] >> 6) & 1; + i = (header[0] >> 5) & 1; + p = (header[0] >> 4) & 1; + s = (header[0] >> 3) & 1; + a = (header[0] >> 2) & 1; + w = (header[0] >> 1) & 1; + u = header[0] & 1; + + DEBUGP(DSNDCP,"rfc1144 header:\n"); + DEBUGP(DSNDCP," Tag bit = %d\n",t); + DEBUGP(DSNDCP," C = %d\n",c); + DEBUGP(DSNDCP," I = %d\n",i); + DEBUGP(DSNDCP," P = %d\n",p); + DEBUGP(DSNDCP," S = %d\n",s); + DEBUGP(DSNDCP," A = %d\n",a); + DEBUGP(DSNDCP," W = %d\n",w); + DEBUGP(DSNDCP," U = %d\n",u); + + header++; + if(c) { + DEBUGP(DSNDCP," Connection number (C) = %d\n",*header); + header++; + } + + DEBUGP(DSNDCP," TCP Checksum = %02x%02x\n",header[0],header[1]); + header+=2; + + if(s && w && u) { + DEBUGP(DSNDCP," Special case I (SPECIAL_I) => short header\n"); + return; + } else if(s && a && w && u) { + DEBUGP(DSNDCP," Special case D (SPECIAL_D) => short header\n"); + return; + } + + if(u) { + DEBUGP(DSNDCP," Urgent Pointer (U) = %02x\n",*header); + header++; + } + if(w) { + DEBUGP(DSNDCP," Delta Window (W) = %02x\n",*header); + header++; + } + if(a) { + DEBUGP(DSNDCP," Delta Ack (A) = %02x\n",*header); + header++; + } + if(s) { + DEBUGP(DSNDCP," Delta Sequence (S) = %02x\n",*header); + header++; + } + if(i) { + DEBUGP(DSNDCP," Delta IP ID (I) = %02x\n",*header); + header++; + } + + /* FIXME: Header values will be usually fit in 8 bits, implement + * implement variable length decoding for values larger then 8 bit */ +#endif +} + + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a new header compression + * entity is created by gprs_sndcp.c */ + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + comp_entity->state = + slhc_init(ctx, comp_field->rfc1144_params->s01 + 1, + comp_field->rfc1144_params->s01 + 1); + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression initalized.\n"); + return 0; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a header compression + * entity is deleted by gprs_sndcp.c */ + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + if (comp_entity->state) { + slhc_free((struct slcompress *)comp_entity->state); + comp_entity->state = NULL; + } + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression terminated.\n"); + return; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Compress a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_compress(int *pcomp_index, uint8_t *data_o, + uint8_t *data_i, int len, + struct slcompress *comp) +{ + uint8_t *comp_ptr; /* Not used */ + int compr_len; + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Run compressor */ + compr_len = slhc_compress(comp, data_i, len, data_o, &comp_ptr, 0); + + /* Generate pcomp_index */ + if (data_o[0] & SL_TYPE_COMPRESSED_TCP) { + *pcomp_index = 2; + data_o[0] &= ~SL_TYPE_COMPRESSED_TCP; + debug_rfc1144_header(data_o); + } else if ((data_o[0] & SL_TYPE_UNCOMPRESSED_TCP) == + SL_TYPE_UNCOMPRESSED_TCP) { + *pcomp_index = 1; + data_o[0] &= 0x4F; + } else + *pcomp_index = 0; + + return compr_len; +} + +/* Expand a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_expand(uint8_t *data_o, uint8_t *data_i, + int len, int pcomp_index, + struct slcompress *comp) +{ + int data_decompressed_len; + int type = -1; + + /* Note: this function should never be called with pcomp_index=0, + * since this condition is already filtered + * out by gprs_sndcp_pcomp_expand() */ + + /* Determine the data type by the PCOMP index */ + switch (pcomp_index) { + case 1: + type = SL_TYPE_UNCOMPRESSED_TCP; + break; + case 2: + type = SL_TYPE_COMPRESSED_TCP; + break; + } + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Restore the original version nibble on + * marked uncompressed packets */ + if (type == SL_TYPE_UNCOMPRESSED_TCP) { + + /* Just in case the phone tags uncompressed tcp-datas + * (normally this is handled by pcomp so there is + * no need for tagging the datas) */ + data_o[0] &= 0x4F; + data_decompressed_len = slhc_remember(comp, data_o, len); + return data_decompressed_len; + } + + /* Uncompress compressed packets */ + else if (type == SL_TYPE_COMPRESSED_TCP) { + data_decompressed_len = slhc_uncompress(comp, data_o, len); + return data_decompressed_len; + } + + /* Regular or unknown packets will not be touched */ + return len; +} + +/* Expand packet header */ +int gprs_sndcp_pcomp_expand(uint8_t *data_o, uint8_t *data_i, int len, + int pcomp, const struct llist_head *comp_entities) +{ + int rc; + int pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data_o); + OSMO_ASSERT(data_i); + OSMO_ASSERT(comp_entities); + + /* Skip on pcomp=0 */ + if (pcomp == 0) { + memcpy(data_o,data_i,len); + return len; + } + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_comp(comp_entities, pcomp); + + /* Skip compression if no suitable compression entity can be found */ + if (comp_entity == NULL) { + memcpy(data_o,data_i,len); + return len; + } + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION); + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144); + + /* Find pcomp_index */ + pcomp_index = gprs_sndcp_comp_get_idx(comp_entity, pcomp); + + /* Run decompression algo */ + rc = gprs_sndcp_pcomp_rfc1144_expand(data_o, data_i, len, pcomp_index, + comp_entity->state); + slhc_i_status(comp_entity->state); + slhc_o_status(comp_entity->state); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header expansion done, old length=%i, new length=%i\n", + len, rc); + + return rc; +} + +/* Compress packet header */ +int gprs_sndcp_pcomp_compress(uint8_t *data_o, uint8_t *data_i, int len, + int *pcomp, + const struct llist_head *comp_entities, int nsapi) +{ + int rc; + int pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data_o); + OSMO_ASSERT(data_i); + OSMO_ASSERT(pcomp); + OSMO_ASSERT(comp_entities); + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_nsapi(comp_entities, nsapi); + + /* Skip compression if no suitable compression entity can be found */ + if (!comp_entity) { + *pcomp = 0; + memcpy(data_o,data_i,len); + return len; + } + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION); + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144); + + /* Run compression algo */ + rc = gprs_sndcp_pcomp_rfc1144_compress(&pcomp_index, data_o, data_i, + len, comp_entity->state); + slhc_i_status(comp_entity->state); + slhc_o_status(comp_entity->state); + + /* Find pcomp value */ + *pcomp = gprs_sndcp_comp_get_comp(comp_entity, pcomp_index); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header compression done, old length=%i, new length=%i\n", + len, rc); + return rc; +} diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c index e6dc68d..1b67092 100644 --- a/openbsc/src/gprs/sgsn_vty.c +++ b/openbsc/src/gprs/sgsn_vty.c @@ -269,6 +269,13 @@ vty_out(vty, " timer t3395 %d%s", g_cfg->timers.T3395, VTY_NEWLINE); vty_out(vty, " timer t3397 %d%s", g_cfg->timers.T3397, VTY_NEWLINE); + if (g_cfg->pcomp_rfc1144.enabled) { + vty_out(vty, " compression rfc1144 slots %d%s", + g_cfg->pcomp_rfc1144.s01+1, VTY_NEWLINE); + } else { + vty_out(vty, " no compression rfc1144%s", VTY_NEWLINE); + } + return CMD_SUCCESS; } @@ -1074,6 +1081,27 @@ return CMD_SUCCESS; } +DEFUN(cfg_no_comp_rfc1144, cfg_no_comp_rfc1144_cmd, + "no compression rfc1144", + NO_STR "compression\n" + "disable rfc1144 TCP/IP header compression\n") +{ + g_cfg->pcomp_rfc1144.enabled = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_comp_rfc1144, cfg_comp_rfc1144_cmd, + "compression rfc1144 slots <1-256>", + "Configure compression\n" + "RFC1144 Header compresion scheme\n" + "Number of compression state slots\n" + "number\n") +{ + g_cfg->pcomp_rfc1144.enabled = 1; + g_cfg->pcomp_rfc1144.s01 = atoi(argv[0]) - 1; + return CMD_SUCCESS; +} + int sgsn_vty_init(void) { install_element_ve(&show_sgsn_cmd); @@ -1128,6 +1156,9 @@ install_element(SGSN_NODE, &cfg_sgsn_T3395_cmd); install_element(SGSN_NODE, &cfg_sgsn_T3397_cmd); + install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd); + install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd); + return 0; } diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 3e66978..1804280 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -33,6 +33,8 @@ $(top_builddir)/src/gprs/gprs_llc_xid.o \ $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ $(top_builddir)/src/gprs/slhc.o \ + $(top_builddir)/src/gprs/gprs_sndcp_comp.o \ + $(top_builddir)/src/gprs/gprs_sndcp_pcomp.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ -- To view, visit https://gerrit.osmocom.org/642 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 Gerrit-PatchSet: 15 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Wed Aug 17 13:14:26 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Wed, 17 Aug 2016 13:14:26 +0000 Subject: [PATCH] openbsc[master]: V42BIS integration In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/644 to look at the new patch set (#20). V42BIS integration The previously committed SPANDSP v42bis implementation has been edited to function outside the SPANDSP library. Debug printf statements were changed into DEBUGP statements. Als removed the assembely code in top_bit(). Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d --- M openbsc/.gitignore M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/debug.h M openbsc/include/openbsc/v42bis.h R openbsc/include/openbsc/v42bis_private.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/sgsn_main.c M openbsc/src/gprs/v42bis.c M openbsc/tests/Makefile.am M openbsc/tests/testsuite.at A openbsc/tests/v42bis/Makefile.am A openbsc/tests/v42bis/v42bis_test.c A openbsc/tests/v42bis/v42bis_test.ok 14 files changed, 252 insertions(+), 24 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/44/644/20 diff --git a/openbsc/.gitignore b/openbsc/.gitignore index e75b9eb..6fbd463 100644 --- a/openbsc/.gitignore +++ b/openbsc/.gitignore @@ -84,6 +84,7 @@ tests/xid/xid_test tests/sndcp_xid/sndcp_xid_test tests/slhc/slhc_test +tests/v42bis/v42bis_test tests/atconfig tests/atlocal diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 18980b0..1df14fe 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -232,6 +232,7 @@ tests/xid/Makefile tests/sndcp_xid/Makefile tests/slhc/Makefile + tests/v42bis/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 88a7e2c..bc56d0d 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,7 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ - slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h + slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h v42bis.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 90ddca5..ca3d4ad 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -37,6 +37,7 @@ DGTPHUB, DRANAP, DSUA, + DV42BIS, Debug_LastEntry, }; diff --git a/openbsc/include/openbsc/v42bis.h b/openbsc/include/openbsc/v42bis.h index f13e5c5..1025296 100644 --- a/openbsc/include/openbsc/v42bis.h +++ b/openbsc/include/openbsc/v42bis.h @@ -33,9 +33,13 @@ \section v42bis_page_sec_2 How does it work? */ +#include + #if !defined(_SPANDSP_V42BIS_H_) #define _SPANDSP_V42BIS_H_ +#define SPAN_DECLARE(x) x + #define V42BIS_MAX_BITS 12 #define V42BIS_MAX_CODEWORDS 4096 /* 2^V42BIS_MAX_BITS */ #define V42BIS_TABLE_SIZE 5021 /* This should be a prime >(2^V42BIS_MAX_BITS) */ diff --git a/openbsc/include/openbsc/private_v42bis.h b/openbsc/include/openbsc/v42bis_private.h similarity index 100% rename from openbsc/include/openbsc/private_v42bis.h rename to openbsc/include/openbsc/v42bis_private.h diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 2910c02..f479d56 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -27,7 +27,7 @@ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ - slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c + slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c v42bis.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c index 894ce84..44a8921 100644 --- a/openbsc/src/gprs/sgsn_main.c +++ b/openbsc/src/gprs/sgsn_main.c @@ -297,6 +297,11 @@ .description = "RFC1144 TCP/IP Header compression (SLHC)", .enabled = 1, .loglevel = LOGL_DEBUG, }, + [DV42BIS] = { + .name = "DV42BIS", + .description = "V42.bis data compression (SNDCP)", + .enabled = 1, .loglevel = LOGL_DEBUG, + } }; static const struct log_info gprs_log_info = { diff --git a/openbsc/src/gprs/v42bis.c b/openbsc/src/gprs/v42bis.c index 6d38916..de9c2af 100644 --- a/openbsc/src/gprs/v42bis.c +++ b/openbsc/src/gprs/v42bis.c @@ -31,9 +31,8 @@ /*! \file */ -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif +#define FALSE 0 +#define TRUE 1 #include #include @@ -44,13 +43,10 @@ #include #include -#include "spandsp/telephony.h" -#include "spandsp/logging.h" -#include "spandsp/bit_operations.h" -#include "spandsp/v42bis.h" +#include +#include +#include -#include "spandsp/private/logging.h" -#include "spandsp/private/v42bis.h" /* Fixed parameters from the spec. */ #define V42BIS_N3 8 /* Character size (bits) */ @@ -310,7 +306,7 @@ { if (ss->transparent) { - printf("Going compressed\n"); + DEBUGP(DV42BIS,"Going compressed\n"); /* 7.8.1 Transition to compressed mode */ /* Switch out of transparent now, between codes. We need to send the octet which did not match, just before switching. */ @@ -332,7 +328,7 @@ { if (!ss->transparent) { - printf("Going transparent\n"); + DEBUGP(DV42BIS,"Going transparent\n"); /* 7.8.2 Transition to transparent mode */ /* Switch into transparent now, between codes, and the unmatched octet should go out in transparent mode, just below */ @@ -401,7 +397,7 @@ { if (s->compress.dict[i].parent_code != 0xFFFF) { - printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); + DEBUGP(DV42BIS,"Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); } } return 0; @@ -454,13 +450,13 @@ ss->escaped = FALSE; if (code == V42BIS_ECM) { - printf("Hit V42BIS_ECM\n"); + DEBUGP(DV42BIS,"Hit V42BIS_ECM\n"); ss->transparent = FALSE; code_len = ss->v42bis_parm_c2; } else if (code == V42BIS_EID) { - printf("Hit V42BIS_EID\n"); + DEBUGP(DV42BIS,"Hit V42BIS_EID\n"); ss->output_buf[ss->output_octet_count++] = ss->escape_code - 1; if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) { @@ -470,11 +466,11 @@ } else if (code == V42BIS_RESET) { - printf("Hit V42BIS_RESET\n"); + DEBUGP(DV42BIS,"Hit V42BIS_RESET\n"); } else { - printf("Hit V42BIS_???? - %" PRIu32 "\n", code); + DEBUGP(DV42BIS,"Hit V42BIS_???? - %" PRIu32 "\n", code); } } else if (code == ss->escape_code) @@ -500,17 +496,17 @@ switch (new_code) { case V42BIS_ETM: - printf("Hit V42BIS_ETM\n"); + DEBUGP(DV42BIS,"Hit V42BIS_ETM\n"); ss->transparent = TRUE; code_len = 8; break; case V42BIS_FLUSH: - printf("Hit V42BIS_FLUSH\n"); + DEBUGP(DV42BIS,"Hit V42BIS_FLUSH\n"); v42bis_decompress_flush(s); break; case V42BIS_STEPUP: /* We need to increase the codeword size */ - printf("Hit V42BIS_STEPUP\n"); + DEBUGP(DV42BIS,"Hit V42BIS_STEPUP\n"); if (ss->v42bis_parm_c3 >= s->v42bis_parm_n2) { /* Invalid condition */ @@ -547,7 +543,7 @@ /* Trace back through the octets which form the string, and output them. */ while (code >= V42BIS_N5) { -if (code > 4095) {printf("Code is 0x%" PRIu32 "\n", code); exit(2);} +if (code > 4095) {DEBUGP(DV42BIS,"Code is 0x%" PRIu32 "\n", code); exit(2);} *string-- = ss->dict[code].node_octet; code = ss->dict[code].parent_code; } @@ -631,7 +627,7 @@ { if (s->decompress.dict[i].parent_code != 0xFFFF) { - printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); + DEBUGP(DV42BIS,"Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); } } return 0; diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index d5aa356..7acebc0 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid slhc +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid slhc v42bis if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index 5f37b8e..f18b734 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -141,3 +141,9 @@ cat $abs_srcdir/slhc/slhc_test.ok > expout AT_CHECK([$abs_top_builddir/tests/slhc/slhc_test], [], [expout], [ignore]) AT_CLEANUP + +AT_SETUP([v42bis]) +AT_KEYWORDS([v42bis]) +cat $abs_srcdir/v42bis/v42bis_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/v42bis/v42bis_test], [], [expout], [ignore]) +AT_CLEANUP diff --git a/openbsc/tests/v42bis/Makefile.am b/openbsc/tests/v42bis/Makefile.am new file mode 100644 index 0000000..9001c0f --- /dev/null +++ b/openbsc/tests/v42bis/Makefile.am @@ -0,0 +1,21 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) + +EXTRA_DIST = v42bis_test.ok + +noinst_PROGRAMS = v42bis_test + +v42bis_test_SOURCES = v42bis_test.c + +v42bis_test_LDADD = \ + $(top_builddir)/src/gprs/v42bis.o \ + $(top_builddir)/src/libcommon/libcommon.a \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOGB_LIBS) \ + $(LIBCARES_LIBS) \ + $(LIBCRYPTO_LIBS) \ + -lgtp -lrt -lm + + diff --git a/openbsc/tests/v42bis/v42bis_test.c b/openbsc/tests/v42bis/v42bis_test.c new file mode 100644 index 0000000..aad94e3 --- /dev/null +++ b/openbsc/tests/v42bis/v42bis_test.c @@ -0,0 +1,189 @@ +/* Test v42bis Compression/Decompression */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#define BLOCK_SIZE 100 +#define MAX_BLOCK_SIZE 2048 + +/* A struct to capture the output data of compressor and decompressor */ +struct v42bis_output_buffer_t { + uint8_t *buf; + uint8_t *buf_pointer; + int len; +}; + +/* A simple testpattern generator */ +static void gen_test_pattern(uint8_t *data, int len) +{ + int i; + for (i = 0; i < len; i++) + data[i] = i & 0xF0; +} + +/* Handler to capture the output data from the compressor */ +void tx_v42bis_frame_handler(void *user_data, const uint8_t *pkt, int len) +{ + struct v42bis_output_buffer_t *output_buffer = + (struct v42bis_output_buffer_t *)user_data; + memcpy(output_buffer->buf_pointer, pkt, len); + output_buffer->buf_pointer += len; + output_buffer->len += len; + return; +} + +/* Handler to capture the output data from the decompressor */ +void tx_v42bis_data_handler(void *user_data, const uint8_t *buf, int len) +{ + /* stub */ + return; +} + +/* Handler to capture the output data from the compressor */ +void rx_v42bis_frame_handler(void *user_data, const uint8_t *pkt, int len) +{ + /* stub */ + return; +} + +/* Handler to capture the output data from the decompressor */ +void rx_v42bis_data_handler(void *user_data, const uint8_t *buf, int len) +{ + struct v42bis_output_buffer_t *output_buffer = + (struct v42bis_output_buffer_t *)user_data; + memcpy(output_buffer->buf_pointer, buf, len); + output_buffer->buf_pointer += len; + output_buffer->len += len; + return; +} + +/* Test V42.bis compression and decompression */ +static void test_v42bis(const void *ctx) +{ + v42bis_state_t *tx_state; + v42bis_state_t *rx_state; + + uint8_t uncompressed_original[BLOCK_SIZE]; + uint8_t compressed[BLOCK_SIZE]; + uint8_t uncompressed[BLOCK_SIZE]; + + int rc; + struct v42bis_output_buffer_t compressed_data; + struct v42bis_output_buffer_t uncompressed_data; + + /* Initalize */ + tx_state = + v42bis_init(NULL, 3, MAX_BLOCK_SIZE, 6, &tx_v42bis_frame_handler, + NULL, MAX_BLOCK_SIZE, &tx_v42bis_data_handler, NULL, + MAX_BLOCK_SIZE); + OSMO_ASSERT(tx_state); + rx_state = + v42bis_init(NULL, 3, MAX_BLOCK_SIZE, 6, &rx_v42bis_frame_handler, + NULL, MAX_BLOCK_SIZE, &rx_v42bis_data_handler, NULL, + MAX_BLOCK_SIZE); + OSMO_ASSERT(rx_state); + v42bis_compression_control(tx_state, V42BIS_COMPRESSION_MODE_ALWAYS); + v42bis_compression_control(rx_state, V42BIS_COMPRESSION_MODE_ALWAYS); + + /* Generate test pattern for input */ + gen_test_pattern(uncompressed_original, sizeof(uncompressed_original)); + + /* Run compressor */ + compressed_data.buf = compressed; + compressed_data.buf_pointer = compressed; + compressed_data.len = 0; + tx_state->compress.user_data = (&compressed_data); + rc = v42bis_compress(tx_state, uncompressed_original, + sizeof(uncompressed_original)); + OSMO_ASSERT(rc == 0); + rc = v42bis_compress_flush(tx_state); + OSMO_ASSERT(rc == 0); + + /* Decompress again */ + uncompressed_data.buf = uncompressed; + uncompressed_data.buf_pointer = uncompressed; + uncompressed_data.len = 0; + rx_state->decompress.user_data = (&uncompressed_data); + rc = v42bis_decompress(rx_state, compressed_data.buf, + compressed_data.len); + OSMO_ASSERT(rc == 0); + rc = v42bis_decompress_flush(rx_state); + OSMO_ASSERT(rc == 0); + + /* Check results */ + printf("uncompressed_original= %s\n", + osmo_hexdump_nospc(uncompressed_original, + sizeof(uncompressed_original))); + printf("uncompressed= %s\n", + osmo_hexdump_nospc(uncompressed_data.buf, + uncompressed_data.len)); + printf("compressed= %s\n", + osmo_hexdump_nospc(compressed_data.buf, compressed_data.len)); + rc = memcmp(uncompressed, uncompressed_original, BLOCK_SIZE); + OSMO_ASSERT(rc == 0); +} + +static struct log_info_cat gprs_categories[] = { + [DV42BIS] = { + .name = "DV42BIS", + .description = "V42.bis data compression (SNDCP)", + .enabled = 1,.loglevel = LOGL_DEBUG, + } +}; + +static struct log_info info = { + .cat = gprs_categories, + .num_cat = ARRAY_SIZE(gprs_categories), +}; + +int main(int argc, char **argv) +{ + void *v42bis_ctx; + + osmo_init_logging(&info); + + v42bis_ctx = talloc_named_const(NULL, 0, "v42bis_ctx"); + + test_v42bis(v42bis_ctx); + printf("Done\n"); + + talloc_report_full(v42bis_ctx, stderr); + OSMO_ASSERT(talloc_total_blocks(v42bis_ctx) == 1); + return 0; +} + +/* stubs */ +struct osmo_prim_hdr; +int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) +{ + abort(); +} diff --git a/openbsc/tests/v42bis/v42bis_test.ok b/openbsc/tests/v42bis/v42bis_test.ok new file mode 100644 index 0000000..16c8612 --- /dev/null +++ b/openbsc/tests/v42bis/v42bis_test.ok @@ -0,0 +1,4 @@ +uncompressed_original= 00000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060 +uncompressed= 00000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060 +compressed= 0180e0703824120a1309c1e0f0884424462385c2e190c868cc670f87c4221112190e27138a4522a5329c5e2f188c464c6638d804 +Done -- To view, visit https://gerrit.osmocom.org/644 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d Gerrit-PatchSet: 20 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Wed Aug 17 13:14:26 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Wed, 17 Aug 2016 13:14:26 +0000 Subject: [PATCH] openbsc[master]: Adding SLHC (RFC1144 header compression) code from linux kernel In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/634 to look at the new patch set (#9). Adding SLHC (RFC1144 header compression) code from linux kernel Slhc is an Implementation of RFC1144 TCP/IP header compression. We will need RFC1144 compression to compress GPRS TCP/IP traffic. The implementation pushed with this commit was taken from git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git git://git.kernel.org/pub/scm/linux/kernel/git/wtarreau/linux-2.4.git commit 29b4817d4018df78086157ea3a55c1d9424a7cfc Change-Id: Ied69c143678dc4a64cecc671f5c4dfebe19d8519 --- A openbsc/include/openbsc/slhc_vj.h M openbsc/src/gprs/sgsn_main.c A openbsc/src/gprs/slhc.c 3 files changed, 932 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/34/634/9 diff --git a/openbsc/include/openbsc/slhc_vj.h b/openbsc/include/openbsc/slhc_vj.h new file mode 100644 index 0000000..8716d59 --- /dev/null +++ b/openbsc/include/openbsc/slhc_vj.h @@ -0,0 +1,183 @@ +#ifndef _SLHC_H +#define _SLHC_H +/* + * Definitions for tcp compression routines. + * + * $Header: slcompress.h,v 1.10 89/12/31 08:53:02 van Exp $ + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van at helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + * + * + * modified for KA9Q Internet Software Package by + * Katie Stevens (dkstevens at ucdavis.edu) + * University of California, Davis + * Computing Services + * - 01-31-90 initial adaptation + * + * - Feb 1991 Bill_Simpson at um.cc.umich.edu + * variable number of conversation slots + * allow zero or one slots + * separate routines + * status display + */ + +/* + * Compressed packet format: + * + * The first octet contains the packet type (top 3 bits), TCP + * 'push' bit, and flags that indicate which of the 4 TCP sequence + * numbers have changed (bottom 5 bits). The next octet is a + * conversation number that associates a saved IP/TCP header with + * the compressed packet. The next two octets are the TCP checksum + * from the original datagram. The next 0 to 15 octets are + * sequence number changes, one change per bit set in the header + * (there may be no changes and there are two special cases where + * the receiver implicitly knows what changed -- see below). + * + * There are 5 numbers which can change (they are always inserted + * in the following order): TCP urgent pointer, window, + * acknowledgment, sequence number and IP ID. (The urgent pointer + * is different from the others in that its value is sent, not the + * change in value.) Since typical use of SLIP links is biased + * toward small packets (see comments on MTU/MSS below), changes + * use a variable length coding with one octet for numbers in the + * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the + * range 256 - 65535 or 0. (If the change in sequence number or + * ack is more than 65535, an uncompressed packet is sent.) + */ + +/* + * Packet types (must not conflict with IP protocol version) + * + * The top nibble of the first octet is the packet type. There are + * three possible types: IP (not proto TCP or tcp with one of the + * control flags set); uncompressed TCP (a normal IP/TCP packet but + * with the 8-bit protocol field replaced by an 8-bit connection id -- + * this type of packet syncs the sender & receiver); and compressed + * TCP (described above). + * + * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and + * is logically part of the 4-bit "changes" field that follows. Top + * three bits are actual packet type. For backward compatibility + * and in the interest of conserving bits, numbers are chosen so the + * IP protocol version number (4) which normally appears in this nibble + * means "IP packet". + */ + + +#include +#include + +/* SLIP compression masks for len/vers byte */ +#define SL_TYPE_IP 0x40 +#define SL_TYPE_UNCOMPRESSED_TCP 0x70 +#define SL_TYPE_COMPRESSED_TCP 0x80 +#define SL_TYPE_ERROR 0x00 + +/* Bits in first octet of compressed packet */ +#define NEW_C 0x40 /* flag bits for what changed in a packet */ +#define NEW_I 0x20 +#define NEW_S 0x08 +#define NEW_A 0x04 +#define NEW_W 0x02 +#define NEW_U 0x01 + +/* reserved, special-case values of above */ +#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */ +#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */ +#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U) + +#define TCP_PUSH_BIT 0x10 + +/* + * data type and sizes conversion assumptions: + * + * VJ code KA9Q style generic + * u_char byte_t unsigned char 8 bits + * u_short int16 unsigned short 16 bits + * u_int int16 unsigned short 16 bits + * u_long unsigned long unsigned long 32 bits + * int int32 long 32 bits + */ + +typedef __u8 byte_t; +typedef __u32 int32; + +/* + * "state" data for each active tcp conversation on the wire. This is + * basically a copy of the entire IP/TCP header from the last packet + * we saw from the conversation together with a small identifier + * the transmit & receive ends of the line use to locate saved header. + */ +struct cstate { + byte_t cs_this; /* connection id number (xmit) */ + struct cstate *next; /* next in ring (xmit) */ + struct iphdr cs_ip; /* ip/tcp hdr from most recent packet */ + struct tcphdr cs_tcp; + unsigned char cs_ipopt[64]; + unsigned char cs_tcpopt[64]; + int cs_hsize; +}; +#define NULLSLSTATE (struct cstate *)0 + +/* + * all the state data for one serial line (we need one of these per line). + */ +struct slcompress { + struct cstate *tstate; /* transmit connection states (array)*/ + struct cstate *rstate; /* receive connection states (array)*/ + + byte_t tslot_limit; /* highest transmit slot id (0-l)*/ + byte_t rslot_limit; /* highest receive slot id (0-l)*/ + + byte_t xmit_oldest; /* oldest xmit in ring */ + byte_t xmit_current; /* most recent xmit id */ + byte_t recv_current; /* most recent rcvd id */ + + byte_t flags; +#define SLF_TOSS 0x01 /* tossing rcvd frames until id received */ + + int32 sls_o_nontcp; /* outbound non-TCP packets */ + int32 sls_o_tcp; /* outbound TCP packets */ + int32 sls_o_uncompressed; /* outbound uncompressed packets */ + int32 sls_o_compressed; /* outbound compressed packets */ + int32 sls_o_searches; /* searches for connection state */ + int32 sls_o_misses; /* times couldn't find conn. state */ + + int32 sls_i_uncompressed; /* inbound uncompressed packets */ + int32 sls_i_compressed; /* inbound compressed packets */ + int32 sls_i_error; /* inbound error packets */ + int32 sls_i_tossed; /* inbound packets tossed because of error */ + + int32 sls_i_runt; + int32 sls_i_badcheck; +}; +#define NULLSLCOMPR (struct slcompress *)0 + +/* In slhc.c: */ +struct slcompress *slhc_init(int rslots, int tslots); +void slhc_free(struct slcompress *comp); + +int slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, + unsigned char *ocp, unsigned char **cpp, int compress_cid); +int slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize); +int slhc_remember(struct slcompress *comp, unsigned char *icp, int isize); +int slhc_toss(struct slcompress *comp); + +#endif /* _SLHC_H */ diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c index 52fc985..894ce84 100644 --- a/openbsc/src/gprs/sgsn_main.c +++ b/openbsc/src/gprs/sgsn_main.c @@ -292,6 +292,11 @@ .description = "SCCP User Adaptation (SUA)", .enabled = 1, .loglevel = LOGL_DEBUG, }, + [DSLHC] = { + .name = "DSLHC", + .description = "RFC1144 TCP/IP Header compression (SLHC)", + .enabled = 1, .loglevel = LOGL_DEBUG, + }, }; static const struct log_info gprs_log_info = { diff --git a/openbsc/src/gprs/slhc.c b/openbsc/src/gprs/slhc.c new file mode 100644 index 0000000..27ed252 --- /dev/null +++ b/openbsc/src/gprs/slhc.c @@ -0,0 +1,744 @@ +/* + * Routines to compress and uncompress tcp packets (for transmission + * over low speed serial lines). + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van at helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + * + * + * modified for KA9Q Internet Software Package by + * Katie Stevens (dkstevens at ucdavis.edu) + * University of California, Davis + * Computing Services + * - 01-31-90 initial adaptation (from 1.19) + * PPP.05 02-15-90 [ks] + * PPP.08 05-02-90 [ks] use PPP protocol field to signal compression + * PPP.15 09-90 [ks] improve mbuf handling + * PPP.16 11-02 [karn] substantially rewritten to use NOS facilities + * + * - Feb 1991 Bill_Simpson at um.cc.umich.edu + * variable number of conversation slots + * allow zero or one slots + * separate routines + * status display + * - Jul 1994 Dmitry Gorodchanin + * Fixes for memory leaks. + * - Oct 1994 Dmitry Gorodchanin + * Modularization. + * - Jan 1995 Bjorn Ekwall + * Use ip_fast_csum from ip.h + * - July 1995 Christos A. Polyzols + * Spotted bug in tcp option checking + * + * + * This module is a difficult issue. It's clearly inet code but it's also clearly + * driver code belonging close to PPP and SLIP + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_INET +/* Entire module is for IP only */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned char *encode(unsigned char *cp, unsigned short n); +static long decode(unsigned char **cpp); +static unsigned char * put16(unsigned char *cp, unsigned short x); +static unsigned short pull16(unsigned char **cpp); + +/* Allocate compression data structure + * slots must be in range 0 to 255 (zero meaning no compression) + * Returns pointer to structure or ERR_PTR() on error. + */ +struct slcompress * +slhc_init(int rslots, int tslots) +{ + register short i; + register struct cstate *ts; + struct slcompress *comp; + + if (rslots < 0 || rslots > 255 || tslots < 0 || tslots > 255) + return ERR_PTR(-EINVAL); + + comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL); + if (! comp) + goto out_fail; + + if (rslots > 0) { + size_t rsize = rslots * sizeof(struct cstate); + comp->rstate = kzalloc(rsize, GFP_KERNEL); + if (! comp->rstate) + goto out_free; + comp->rslot_limit = rslots - 1; + } + + if (tslots > 0) { + size_t tsize = tslots * sizeof(struct cstate); + comp->tstate = kzalloc(tsize, GFP_KERNEL); + if (! comp->tstate) + goto out_free2; + comp->tslot_limit = tslots - 1; + } + + comp->xmit_oldest = 0; + comp->xmit_current = 255; + comp->recv_current = 255; + /* + * don't accept any packets with implicit index until we get + * one with an explicit index. Otherwise the uncompress code + * will try to use connection 255, which is almost certainly + * out of range + */ + comp->flags |= SLF_TOSS; + + if ( tslots > 0 ) { + ts = comp->tstate; + for(i = comp->tslot_limit; i > 0; --i){ + ts[i].cs_this = i; + ts[i].next = &(ts[i - 1]); + } + ts[0].next = &(ts[comp->tslot_limit]); + ts[0].cs_this = 0; + } + return comp; + +out_free2: + kfree(comp->rstate); +out_free: + kfree(comp); +out_fail: + return ERR_PTR(-ENOMEM); +} + + +/* Free a compression data structure */ +void +slhc_free(struct slcompress *comp) +{ + if ( comp == NULLSLCOMPR ) + return; + + if ( comp->tstate != NULLSLSTATE ) + kfree( comp->tstate ); + + if ( comp->rstate != NULLSLSTATE ) + kfree( comp->rstate ); + + kfree( comp ); +} + + +/* Put a short in host order into a char array in network order */ +static inline unsigned char * +put16(unsigned char *cp, unsigned short x) +{ + *cp++ = x >> 8; + *cp++ = x; + + return cp; +} + + +/* Encode a number */ +static unsigned char * +encode(unsigned char *cp, unsigned short n) +{ + if(n >= 256 || n == 0){ + *cp++ = 0; + cp = put16(cp,n); + } else { + *cp++ = n; + } + return cp; +} + +/* Pull a 16-bit integer in host order from buffer in network byte order */ +static unsigned short +pull16(unsigned char **cpp) +{ + short rval; + + rval = *(*cpp)++; + rval <<= 8; + rval |= *(*cpp)++; + return rval; +} + +/* Decode a number */ +static long +decode(unsigned char **cpp) +{ + register int x; + + x = *(*cpp)++; + if(x == 0){ + return pull16(cpp) & 0xffff; /* pull16 returns -1 on error */ + } else { + return x & 0xff; /* -1 if PULLCHAR returned error */ + } +} + +/* + * icp and isize are the original packet. + * ocp is a place to put a copy if necessary. + * cpp is initially a pointer to icp. If the copy is used, + * change it to ocp. + */ + +int +slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, + unsigned char *ocp, unsigned char **cpp, int compress_cid) +{ + register struct cstate *ocs = &(comp->tstate[comp->xmit_oldest]); + register struct cstate *lcs = ocs; + register struct cstate *cs = lcs->next; + register unsigned long deltaS, deltaA; + register short changes = 0; + int hlen; + unsigned char new_seq[16]; + register unsigned char *cp = new_seq; + struct iphdr *ip; + struct tcphdr *th, *oth; + __sum16 csum; + + + /* + * Don't play with runt packets. + */ + + if(isizeprotocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x3fff)) { + /* Send as regular IP */ + if(ip->protocol != IPPROTO_TCP) + comp->sls_o_nontcp++; + else + comp->sls_o_tcp++; + return isize; + } + /* Extract TCP header */ + + th = (struct tcphdr *)(((unsigned char *)ip) + ip->ihl*4); + hlen = ip->ihl*4 + th->doff*4; + + /* Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or + * some other control bit is set). Also uncompressible if + * it's a runt. + */ + if(hlen > isize || th->syn || th->fin || th->rst || + ! (th->ack)){ + /* TCP connection stuff; send as regular IP */ + comp->sls_o_tcp++; + return isize; + } + /* + * Packet is compressible -- we're going to send either a + * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way, + * we need to locate (or create) the connection state. + * + * States are kept in a circularly linked list with + * xmit_oldest pointing to the end of the list. The + * list is kept in lru order by moving a state to the + * head of the list whenever it is referenced. Since + * the list is short and, empirically, the connection + * we want is almost always near the front, we locate + * states via linear search. If we don't find a state + * for the datagram, the oldest state is (re-)used. + */ + for ( ; ; ) { + if( ip->saddr == cs->cs_ip.saddr + && ip->daddr == cs->cs_ip.daddr + && th->source == cs->cs_tcp.source + && th->dest == cs->cs_tcp.dest) + goto found; + + /* if current equal oldest, at end of list */ + if ( cs == ocs ) + break; + lcs = cs; + cs = cs->next; + comp->sls_o_searches++; + } + /* + * Didn't find it -- re-use oldest cstate. Send an + * uncompressed packet that tells the other side what + * connection number we're using for this conversation. + * + * Note that since the state list is circular, the oldest + * state points to the newest and we only need to set + * xmit_oldest to update the lru linkage. + */ + comp->sls_o_misses++; + comp->xmit_oldest = lcs->cs_this; + goto uncompressed; + +found: + /* + * Found it -- move to the front on the connection list. + */ + if(lcs == ocs) { + /* found at most recently used */ + } else if (cs == ocs) { + /* found at least recently used */ + comp->xmit_oldest = lcs->cs_this; + } else { + /* more than 2 elements */ + lcs->next = cs->next; + cs->next = ocs->next; + ocs->next = cs; + } + + /* + * Make sure that only what we expect to change changed. + * Check the following: + * IP protocol version, header length & type of service. + * The "Don't fragment" bit. + * The time-to-live field. + * The TCP header length. + * IP options, if any. + * TCP options, if any. + * If any of these things are different between the previous & + * current datagram, we send the current datagram `uncompressed'. + */ + oth = &cs->cs_tcp; + + if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl + || ip->tos != cs->cs_ip.tos + || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000)) + || ip->ttl != cs->cs_ip.ttl + || th->doff != cs->cs_tcp.doff + || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) + || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){ + goto uncompressed; + } + + /* + * Figure out which of the changing fields changed. The + * receiver expects changes in the order: urgent, window, + * ack, seq (the order minimizes the number of temporaries + * needed in this section of code). + */ + if(th->urg){ + deltaS = ntohs(th->urg_ptr); + cp = encode(cp,deltaS); + changes |= NEW_U; + } else if(th->urg_ptr != oth->urg_ptr){ + /* argh! URG not set but urp changed -- a sensible + * implementation should never do this but RFC793 + * doesn't prohibit the change so we have to deal + * with it. */ + goto uncompressed; + } + if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){ + cp = encode(cp,deltaS); + changes |= NEW_W; + } + if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){ + if(deltaA > 0x0000ffff) + goto uncompressed; + cp = encode(cp,deltaA); + changes |= NEW_A; + } + if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){ + if(deltaS > 0x0000ffff) + goto uncompressed; + cp = encode(cp,deltaS); + changes |= NEW_S; + } + + switch(changes){ + case 0: /* Nothing changed. If this packet contains data and the + * last one didn't, this is probably a data packet following + * an ack (normal on an interactive connection) and we send + * it compressed. Otherwise it's probably a retransmit, + * retransmitted ack or window probe. Send it uncompressed + * in case the other side missed the compressed version. + */ + if(ip->tot_len != cs->cs_ip.tot_len && + ntohs(cs->cs_ip.tot_len) == hlen) + break; + goto uncompressed; + case SPECIAL_I: + case SPECIAL_D: + /* actual changes match one of our special case encodings -- + * send packet uncompressed. + */ + goto uncompressed; + case NEW_S|NEW_A: + if(deltaS == deltaA && + deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ + /* special case for echoed terminal traffic */ + changes = SPECIAL_I; + cp = new_seq; + } + break; + case NEW_S: + if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ + /* special case for data xfer */ + changes = SPECIAL_D; + cp = new_seq; + } + break; + } + deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id); + if(deltaS != 1){ + cp = encode(cp,deltaS); + changes |= NEW_I; + } + if(th->psh) + changes |= TCP_PUSH_BIT; + /* Grab the cksum before we overwrite it below. Then update our + * state with this packet's header. + */ + csum = th->check; + memcpy(&cs->cs_ip,ip,20); + memcpy(&cs->cs_tcp,th,20); + /* We want to use the original packet as our compressed packet. + * (cp - new_seq) is the number of bytes we need for compressed + * sequence numbers. In addition we need one byte for the change + * mask, one for the connection id and two for the tcp checksum. + * So, (cp - new_seq) + 4 bytes of header are needed. + */ + deltaS = cp - new_seq; + if(compress_cid == 0 || comp->xmit_current != cs->cs_this){ + cp = ocp; + *cpp = ocp; + *cp++ = changes | NEW_C; + *cp++ = cs->cs_this; + comp->xmit_current = cs->cs_this; + } else { + cp = ocp; + *cpp = ocp; + *cp++ = changes; + } + *(__sum16 *)cp = csum; + cp += 2; +/* deltaS is now the size of the change section of the compressed header */ + memcpy(cp,new_seq,deltaS); /* Write list of deltas */ + memcpy(cp+deltaS,icp+hlen,isize-hlen); + comp->sls_o_compressed++; + ocp[0] |= SL_TYPE_COMPRESSED_TCP; + return isize - hlen + deltaS + (cp - ocp); + + /* Update connection state cs & send uncompressed packet (i.e., + * a regular ip/tcp packet but with the 'conversation id' we hope + * to use on future compressed packets in the protocol field). + */ +uncompressed: + memcpy(&cs->cs_ip,ip,20); + memcpy(&cs->cs_tcp,th,20); + if (ip->ihl > 5) + memcpy(cs->cs_ipopt, ip+1, ((ip->ihl) - 5) * 4); + if (th->doff > 5) + memcpy(cs->cs_tcpopt, th+1, ((th->doff) - 5) * 4); + comp->xmit_current = cs->cs_this; + comp->sls_o_uncompressed++; + memcpy(ocp, icp, isize); + *cpp = ocp; + ocp[9] = cs->cs_this; + ocp[0] |= SL_TYPE_UNCOMPRESSED_TCP; + return isize; +} + + +int +slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) +{ + register int changes; + long x; + register struct tcphdr *thp; + register struct iphdr *ip; + register struct cstate *cs; + int len, hdrlen; + unsigned char *cp = icp; + + /* We've got a compressed packet; read the change byte */ + comp->sls_i_compressed++; + if(isize < 3){ + comp->sls_i_error++; + return 0; + } + changes = *cp++; + if(changes & NEW_C){ + /* Make sure the state index is in range, then grab the state. + * If we have a good state index, clear the 'discard' flag. + */ + x = *cp++; /* Read conn index */ + if(x < 0 || x > comp->rslot_limit) + goto bad; + + comp->flags &=~ SLF_TOSS; + comp->recv_current = x; + } else { + /* this packet has an implicit state index. If we've + * had a line error since the last time we got an + * explicit state index, we have to toss the packet. */ + if(comp->flags & SLF_TOSS){ + comp->sls_i_tossed++; + return 0; + } + } + cs = &comp->rstate[comp->recv_current]; + thp = &cs->cs_tcp; + ip = &cs->cs_ip; + + thp->check = *(__sum16 *)cp; + cp += 2; + + thp->psh = (changes & TCP_PUSH_BIT) ? 1 : 0; +/* + * we can use the same number for the length of the saved header and + * the current one, because the packet wouldn't have been sent + * as compressed unless the options were the same as the previous one + */ + + hdrlen = ip->ihl * 4 + thp->doff * 4; + + switch(changes & SPECIALS_MASK){ + case SPECIAL_I: /* Echoed terminal traffic */ + { + register short i; + i = ntohs(ip->tot_len) - hdrlen; + thp->ack_seq = htonl( ntohl(thp->ack_seq) + i); + thp->seq = htonl( ntohl(thp->seq) + i); + } + break; + + case SPECIAL_D: /* Unidirectional data */ + thp->seq = htonl( ntohl(thp->seq) + + ntohs(ip->tot_len) - hdrlen); + break; + + default: + if(changes & NEW_U){ + thp->urg = 1; + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->urg_ptr = htons(x); + } else + thp->urg = 0; + if(changes & NEW_W){ + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->window = htons( ntohs(thp->window) + x); + } + if(changes & NEW_A){ + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->ack_seq = htonl( ntohl(thp->ack_seq) + x); + } + if(changes & NEW_S){ + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->seq = htonl( ntohl(thp->seq) + x); + } + break; + } + if(changes & NEW_I){ + if((x = decode(&cp)) == -1) { + goto bad; + } + ip->id = htons (ntohs (ip->id) + x); + } else + ip->id = htons (ntohs (ip->id) + 1); + + /* + * At this point, cp points to the first byte of data in the + * packet. Put the reconstructed TCP and IP headers back on the + * packet. Recalculate IP checksum (but not TCP checksum). + */ + + len = isize - (cp - icp); + if (len < 0) + goto bad; + len += hdrlen; + ip->tot_len = htons(len); + ip->check = 0; + + memmove(icp + hdrlen, cp, len - hdrlen); + + cp = icp; + memcpy(cp, ip, 20); + cp += 20; + + if (ip->ihl > 5) { + memcpy(cp, cs->cs_ipopt, (ip->ihl - 5) * 4); + cp += (ip->ihl - 5) * 4; + } + + put_unaligned(ip_fast_csum(icp, ip->ihl), + &((struct iphdr *)icp)->check); + + memcpy(cp, thp, 20); + cp += 20; + + if (thp->doff > 5) { + memcpy(cp, cs->cs_tcpopt, ((thp->doff) - 5) * 4); + cp += ((thp->doff) - 5) * 4; + } + + return len; +bad: + comp->sls_i_error++; + return slhc_toss( comp ); +} + + +int +slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +{ + register struct cstate *cs; + unsigned ihl; + + unsigned char index; + + if(isize < 20) { + /* The packet is shorter than a legal IP header */ + comp->sls_i_runt++; + return slhc_toss( comp ); + } + /* Peek at the IP header's IHL field to find its length */ + ihl = icp[0] & 0xf; + if(ihl < 20 / 4){ + /* The IP header length field is too small */ + comp->sls_i_runt++; + return slhc_toss( comp ); + } + index = icp[9]; + icp[9] = IPPROTO_TCP; + + if (ip_fast_csum(icp, ihl)) { + /* Bad IP header checksum; discard */ + comp->sls_i_badcheck++; + return slhc_toss( comp ); + } + if(index > comp->rslot_limit) { + comp->sls_i_error++; + return slhc_toss(comp); + } + + /* Update local state */ + cs = &comp->rstate[comp->recv_current = index]; + comp->flags &=~ SLF_TOSS; + memcpy(&cs->cs_ip,icp,20); + memcpy(&cs->cs_tcp,icp + ihl*4,20); + if (ihl > 5) + memcpy(cs->cs_ipopt, icp + sizeof(struct iphdr), (ihl - 5) * 4); + if (cs->cs_tcp.doff > 5) + memcpy(cs->cs_tcpopt, icp + ihl*4 + sizeof(struct tcphdr), (cs->cs_tcp.doff - 5) * 4); + cs->cs_hsize = ihl*2 + cs->cs_tcp.doff*2; + /* Put headers back on packet + * Neither header checksum is recalculated + */ + comp->sls_i_uncompressed++; + return isize; +} + +int +slhc_toss(struct slcompress *comp) +{ + if ( comp == NULLSLCOMPR ) + return 0; + + comp->flags |= SLF_TOSS; + return 0; +} + +#else /* CONFIG_INET */ + +int +slhc_toss(struct slcompress *comp) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss"); + return -EINVAL; +} +int +slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress"); + return -EINVAL; +} +int +slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, + unsigned char *ocp, unsigned char **cpp, int compress_cid) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress"); + return -EINVAL; +} + +int +slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember"); + return -EINVAL; +} + +void +slhc_free(struct slcompress *comp) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free"); +} +struct slcompress * +slhc_init(int rslots, int tslots) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init"); + return NULL; +} + +#endif /* CONFIG_INET */ + +/* VJ header compression */ +EXPORT_SYMBOL(slhc_init); +EXPORT_SYMBOL(slhc_free); +EXPORT_SYMBOL(slhc_remember); +EXPORT_SYMBOL(slhc_compress); +EXPORT_SYMBOL(slhc_uncompress); +EXPORT_SYMBOL(slhc_toss); + +MODULE_LICENSE("Dual BSD/GPL"); -- To view, visit https://gerrit.osmocom.org/634 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ied69c143678dc4a64cecc671f5c4dfebe19d8519 Gerrit-PatchSet: 9 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Wed Aug 17 13:14:26 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Wed, 17 Aug 2016 13:14:26 +0000 Subject: [PATCH] openbsc[master]: SLHC (RFC1144 header compression) integration and unit-test In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/635 to look at the new patch set (#10). SLHC (RFC1144 header compression) integration and unit-test The previously pushed slhc implementation has been modified to compile and function outside of the kernel. Also debug log messages were added and datatypes ware matched. The implementation is now ready to be used Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 --- M openbsc/.gitignore M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/debug.h R openbsc/include/openbsc/slhc.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/slhc.c M openbsc/tests/Makefile.am M openbsc/tests/sgsn/Makefile.am A openbsc/tests/slhc/Makefile.am A openbsc/tests/slhc/packets.txt A openbsc/tests/slhc/slhc_test.c A openbsc/tests/slhc/slhc_test.ok M openbsc/tests/testsuite.at 14 files changed, 576 insertions(+), 91 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/35/635/10 diff --git a/openbsc/.gitignore b/openbsc/.gitignore index 8ce3b70..e75b9eb 100644 --- a/openbsc/.gitignore +++ b/openbsc/.gitignore @@ -83,6 +83,7 @@ tests/mm_auth/mm_auth_test tests/xid/xid_test tests/sndcp_xid/sndcp_xid_test +tests/slhc/slhc_test tests/atconfig tests/atlocal diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 53072bd..18980b0 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -231,6 +231,7 @@ tests/mm_auth/Makefile tests/xid/Makefile tests/sndcp_xid/Makefile + tests/slhc/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index e200b05..f402fea 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,8 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h + gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ + slhc.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 43ebb19..90ddca5 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -29,6 +29,7 @@ DBSSGP, DLLC, DSNDCP, + DSLHC, DNAT, DCTRL, DSMPP, diff --git a/openbsc/include/openbsc/slhc_vj.h b/openbsc/include/openbsc/slhc.h similarity index 97% rename from openbsc/include/openbsc/slhc_vj.h rename to openbsc/include/openbsc/slhc.h index 8716d59..cd5a47c 100644 --- a/openbsc/include/openbsc/slhc_vj.h +++ b/openbsc/include/openbsc/slhc.h @@ -171,7 +171,8 @@ #define NULLSLCOMPR (struct slcompress *)0 /* In slhc.c: */ -struct slcompress *slhc_init(int rslots, int tslots); +struct slcompress *slhc_init(const void *ctx, int rslots, int tslots); + void slhc_free(struct slcompress *comp); int slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, @@ -180,4 +181,7 @@ int slhc_remember(struct slcompress *comp, unsigned char *icp, int isize); int slhc_toss(struct slcompress *comp); +void slhc_i_status(struct slcompress *comp); +void slhc_o_status(struct slcompress *comp); + #endif /* _SLHC_H */ diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index fa4a3dd..245636b 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -26,7 +26,8 @@ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ - oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c + oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ + slhc.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/slhc.c b/openbsc/src/gprs/slhc.c index 27ed252..cbdf8db 100644 --- a/openbsc/src/gprs/slhc.c +++ b/openbsc/src/gprs/slhc.c @@ -50,61 +50,77 @@ * driver code belonging close to PPP and SLIP */ -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#ifdef CONFIG_INET -/* Entire module is for IP only */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#define ERR_PTR(x) x + static unsigned char *encode(unsigned char *cp, unsigned short n); static long decode(unsigned char **cpp); static unsigned char * put16(unsigned char *cp, unsigned short x); static unsigned short pull16(unsigned char **cpp); +/* Replacement for kernel space function ip_fast_csum() */ +static uint16_t ip_fast_csum(uint8_t *iph, int ihl) +{ + int i; + uint16_t temp; + uint32_t accumulator = 0xFFFF; + + for(i=0;i0xFFFF) + { + accumulator++; + accumulator&=0xFFFF; + } + } + + return (uint16_t)(htons(~accumulator)&0xFFFF); +} + +/* Replacement for kernel space function put_unaligned() */ +static void put_unaligned(uint16_t val, void *ptr) +{ + memcpy(ptr,&val,sizeof(val)); +} + + /* Allocate compression data structure * slots must be in range 0 to 255 (zero meaning no compression) * Returns pointer to structure or ERR_PTR() on error. */ struct slcompress * -slhc_init(int rslots, int tslots) +slhc_init(const void *ctx, int rslots, int tslots) { register short i; register struct cstate *ts; struct slcompress *comp; if (rslots < 0 || rslots > 255 || tslots < 0 || tslots > 255) - return ERR_PTR(-EINVAL); + return NULL; - comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL); + comp = (struct slcompress *)talloc_zero_size(ctx,sizeof(struct slcompress)); if (! comp) goto out_fail; if (rslots > 0) { size_t rsize = rslots * sizeof(struct cstate); - comp->rstate = kzalloc(rsize, GFP_KERNEL); + comp->rstate = (struct cstate *) talloc_zero_size(ctx, rsize); if (! comp->rstate) goto out_free; comp->rslot_limit = rslots - 1; @@ -112,7 +128,7 @@ if (tslots > 0) { size_t tsize = tslots * sizeof(struct cstate); - comp->tstate = kzalloc(tsize, GFP_KERNEL); + comp->tstate = (struct cstate *) talloc_zero_size(ctx, tsize); if (! comp->tstate) goto out_free2; comp->tslot_limit = tslots - 1; @@ -141,11 +157,11 @@ return comp; out_free2: - kfree(comp->rstate); + talloc_free(comp->rstate); out_free: - kfree(comp); + talloc_free(comp); out_fail: - return ERR_PTR(-ENOMEM); + return NULL; } @@ -153,16 +169,18 @@ void slhc_free(struct slcompress *comp) { + DEBUGP(DSLHC, "slhc_free(): Freeing compression states...\n"); + if ( comp == NULLSLCOMPR ) return; if ( comp->tstate != NULLSLSTATE ) - kfree( comp->tstate ); + talloc_free(comp->tstate ); if ( comp->rstate != NULLSLSTATE ) - kfree( comp->rstate ); + talloc_free( comp->rstate ); - kfree( comp ); + talloc_free( comp ); } @@ -187,6 +205,8 @@ } else { *cp++ = n; } + + DEBUGP(DSLHC, "encode(): n=%04x\n",n); return cp; } @@ -256,6 +276,7 @@ comp->sls_o_nontcp++; else comp->sls_o_tcp++; + DEBUGP(DSLHC, "slhc_compress(): Not a TCP packat, will not touch...\n"); return isize; } /* Extract TCP header */ @@ -271,6 +292,7 @@ ! (th->ack)){ /* TCP connection stuff; send as regular IP */ comp->sls_o_tcp++; + DEBUGP(DSLHC, "slhc_compress(): Packet is part of a TCP connection, will not touch...\n"); return isize; } /* @@ -287,6 +309,9 @@ * states via linear search. If we don't find a state * for the datagram, the oldest state is (re-)used. */ + + DEBUGP(DSLHC, "slhc_compress(): Compressible packet detected!\n"); + for ( ; ; ) { if( ip->saddr == cs->cs_ip.saddr && ip->daddr == cs->cs_ip.daddr @@ -310,11 +335,14 @@ * state points to the newest and we only need to set * xmit_oldest to update the lru linkage. */ + + DEBUGP(DSLHC, "slhc_compress(): Header not yet seen, will memorize header for the next turn...\n"); comp->sls_o_misses++; comp->xmit_oldest = lcs->cs_this; goto uncompressed; found: + DEBUGP(DSLHC, "slhc_compress(): Header already seen, trying to compress...\n"); /* * Found it -- move to the front on the connection list. */ @@ -344,6 +372,39 @@ */ oth = &cs->cs_tcp; + /* Display a little more debug information about which of the + * header fields changed unexpectedly */ + if(ip->version != cs->cs_ip.version) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->version != cs->cs_ip.version\n"); + if(ip->ihl != cs->cs_ip.ihl) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->ihl != cs->cs_ip.ihl\n"); + if(ip->tos != cs->cs_ip.tos) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->tos != cs->cs_ip.tos\n"); + if((ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))\n"); + if(ip->ttl != cs->cs_ip.ttl) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->ttl != cs->cs_ip.ttl\n"); + if(th->doff != cs->cs_tcp.doff) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: th->doff != cs->cs_tcp.doff\n"); + if(ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) { + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0)\n"); + DEBUGP(DSLHC, "slhc_compress(): ip->ihl = %i\n", ip->ihl); + DEBUGP(DSLHC, "slhc_compress(): ip+1 = %s\n", + osmo_hexdump_nospc((uint8_t*)(ip+1),((ip->ihl)-5)*4)); + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: cs->cs_ipopt = %s\n", + osmo_hexdump_nospc((uint8_t*)(cs->cs_ipopt),((ip->ihl)-5)*4)); + } + if(th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0) { + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)\n"); + DEBUGP(DSLHC, "slhc_compress(): th->doff = %i\n", th->doff); + DEBUGP(DSLHC, "slhc_compress(): th+1 = %s\n", + osmo_hexdump_nospc((uint8_t*)(th+1),((th->doff)-5)*4)); + DEBUGP(DSLHC, "slhc_compress(): cs->cs_tcpopt = %s\n", + osmo_hexdump_nospc((uint8_t*)cs->cs_tcpopt, + ((th->doff)-5)*4)); + } + + if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl || ip->tos != cs->cs_ip.tos || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000)) @@ -351,6 +412,7 @@ || th->doff != cs->cs_tcp.doff || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){ + DEBUGP(DSLHC, "slhc_compress(): The header contains unexpected changes, can't compress...\n"); goto uncompressed; } @@ -362,6 +424,7 @@ */ if(th->urg){ deltaS = ntohs(th->urg_ptr); + DEBUGP(DSLHC, "slhc_compress(): flag: Urgent Pointer (U) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_U; } else if(th->urg_ptr != oth->urg_ptr){ @@ -369,21 +432,29 @@ * implementation should never do this but RFC793 * doesn't prohibit the change so we have to deal * with it. */ + DEBUGP(DSLHC, "slhc_compress(): URG not set but urp changed, can't compress...\n"); goto uncompressed; } if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){ + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Window (W) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_W; } if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){ - if(deltaA > 0x0000ffff) + if(deltaA > 0x0000ffff) { + DEBUGP(DSLHC, "slhc_compress(): (deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L, can't compress...\n"); goto uncompressed; + } + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Ack (A) = 1\n"); cp = encode(cp,deltaA); changes |= NEW_A; } if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){ - if(deltaS > 0x0000ffff) + if(deltaS > 0x0000ffff) { + DEBUGP(DSLHC, "slhc_compress(): (deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L, can't compress...\n"); goto uncompressed; + } + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_S; } @@ -399,17 +470,21 @@ if(ip->tot_len != cs->cs_ip.tot_len && ntohs(cs->cs_ip.tot_len) == hlen) break; + DEBUGP(DSLHC, "slhc_compress(): Retransmitted packet detected, can't compress...\n"); goto uncompressed; case SPECIAL_I: case SPECIAL_D: /* actual changes match one of our special case encodings -- * send packet uncompressed. */ + DEBUGP(DSLHC, "slhc_compress(): Special case detected, can't compress...\n"); goto uncompressed; case NEW_S|NEW_A: if(deltaS == deltaA && deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ /* special case for echoed terminal traffic */ + DEBUGP(DSLHC, "slhc_compress(): Special case for echoed terminal traffic detected...\n"); + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1, Delta Window (W) = 1, Urgent Pointer (U) = 1\n"); changes = SPECIAL_I; cp = new_seq; } @@ -417,6 +492,8 @@ case NEW_S: if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ /* special case for data xfer */ + DEBUGP(DSLHC, "slhc_compress(): Special case for data xfer detected...\n"); + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1, Delta Ack (A) = 1, Delta Window (W) = 1, Urgent Pointer (U) = 1\n"); changes = SPECIAL_D; cp = new_seq; } @@ -424,11 +501,14 @@ } deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id); if(deltaS != 1){ + DEBUGP(DSLHC, "slhc_compress(): flag: Delta IP ID (I) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_I; } - if(th->psh) + if(th->psh) { + DEBUGP(DSLHC, "slhc_compress(): flag: Push (P) = 1\n"); changes |= TCP_PUSH_BIT; + } /* Grab the cksum before we overwrite it below. Then update our * state with this packet's header. */ @@ -445,6 +525,7 @@ if(compress_cid == 0 || comp->xmit_current != cs->cs_this){ cp = ocp; *cpp = ocp; + DEBUGP(DSLHC, "slhc_compress(): flag: Connection number (C) = 1\n"); *cp++ = changes | NEW_C; *cp++ = cs->cs_this; comp->xmit_current = cs->cs_this; @@ -456,6 +537,10 @@ *(__sum16 *)cp = csum; cp += 2; /* deltaS is now the size of the change section of the compressed header */ + + DEBUGP(DSLHC, "slhc_compress(): Delta-list length (deltaS) = %li\n",deltaS); + DEBUGP(DSLHC, "slhc_compress(): Original header len (hlen) = %i\n",hlen); + memcpy(cp,new_seq,deltaS); /* Write list of deltas */ memcpy(cp+deltaS,icp+hlen,isize-hlen); comp->sls_o_compressed++; @@ -467,6 +552,7 @@ * to use on future compressed packets in the protocol field). */ uncompressed: + DEBUGP(DSLHC, "slhc_compress(): Packet will be sent uncompressed...\n"); memcpy(&cs->cs_ip,ip,20); memcpy(&cs->cs_tcp,th,20); if (ip->ihl > 5) @@ -538,6 +624,8 @@ switch(changes & SPECIALS_MASK){ case SPECIAL_I: /* Echoed terminal traffic */ + DEBUGP(DSLHC, "slhc_uncompress(): Echoed terminal traffic detected\n"); + { register short i; i = ntohs(ip->tot_len) - hdrlen; @@ -547,11 +635,13 @@ break; case SPECIAL_D: /* Unidirectional data */ + DEBUGP(DSLHC, "slhc_uncompress(): Unidirectional data detected\n"); thp->seq = htonl( ntohl(thp->seq) + ntohs(ip->tot_len) - hdrlen); break; default: + DEBUGP(DSLHC, "slhc_uncompress(): default packet type detected\n"); if(changes & NEW_U){ thp->urg = 1; if((x = decode(&cp)) == -1) { @@ -601,6 +691,7 @@ ip->tot_len = htons(len); ip->check = 0; + DEBUGP(DSLHC, "slhc_uncompress(): making space for the reconstructed header...\n"); memmove(icp + hdrlen, cp, len - hdrlen); cp = icp; @@ -625,6 +716,7 @@ return len; bad: + DEBUGP(DSLHC, "slhc_uncompress(): bad packet detected!\n"); comp->sls_i_error++; return slhc_toss( comp ); } @@ -641,6 +733,7 @@ if(isize < 20) { /* The packet is shorter than a legal IP header */ comp->sls_i_runt++; + DEBUGP(DSLHC, "slhc_remember(): The packet is shorter than a legal IP header ==> slhc_toss()\n"); return slhc_toss( comp ); } /* Peek at the IP header's IHL field to find its length */ @@ -648,6 +741,7 @@ if(ihl < 20 / 4){ /* The IP header length field is too small */ comp->sls_i_runt++; + DEBUGP(DSLHC, "slhc_remember(): The IP header length field is too small ==> slhc_toss()\n"); return slhc_toss( comp ); } index = icp[9]; @@ -656,10 +750,12 @@ if (ip_fast_csum(icp, ihl)) { /* Bad IP header checksum; discard */ comp->sls_i_badcheck++; + DEBUGP(DSLHC, "slhc_remember(): Bad IP header checksum; discard ==> slhc_toss()\n"); return slhc_toss( comp ); } if(index > comp->rslot_limit) { comp->sls_i_error++; + DEBUGP(DSLHC, "slhc_remember(): index > comp->rslot_limit ==> slhc_toss()\n"); return slhc_toss(comp); } @@ -683,6 +779,7 @@ int slhc_toss(struct slcompress *comp) { + DEBUGP(DSLHC, "slhc_toss(): Reset compression state...\n"); if ( comp == NULLSLCOMPR ) return 0; @@ -690,55 +787,27 @@ return 0; } -#else /* CONFIG_INET */ - -int -slhc_toss(struct slcompress *comp) +void slhc_i_status(struct slcompress *comp) { - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss"); - return -EINVAL; -} -int -slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress"); - return -EINVAL; -} -int -slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, - unsigned char *ocp, unsigned char **cpp, int compress_cid) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress"); - return -EINVAL; + if (comp != NULLSLCOMPR) { + DEBUGP(DSLHC, "slhc_i_status(): %d Cmp, %d Uncmp, %d Bad, %d Tossed\n", + comp->sls_i_compressed, + comp->sls_i_uncompressed, + comp->sls_i_error, + comp->sls_i_tossed); + } } -int -slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +void slhc_o_status(struct slcompress *comp) { - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember"); - return -EINVAL; + if (comp != NULLSLCOMPR) { + DEBUGP(DSLHC, "slhc_o_status(): %d Cmp, %d Uncmp, %d AsIs, %d NotTCP %d Searches, %d Misses\n", + comp->sls_o_compressed, + comp->sls_o_uncompressed, + comp->sls_o_tcp, + comp->sls_o_nontcp, + comp->sls_o_searches, + comp->sls_o_misses); + } } -void -slhc_free(struct slcompress *comp) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free"); -} -struct slcompress * -slhc_init(int rslots, int tslots) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init"); - return NULL; -} - -#endif /* CONFIG_INET */ - -/* VJ header compression */ -EXPORT_SYMBOL(slhc_init); -EXPORT_SYMBOL(slhc_free); -EXPORT_SYMBOL(slhc_remember); -EXPORT_SYMBOL(slhc_compress); -EXPORT_SYMBOL(slhc_uncompress); -EXPORT_SYMBOL(slhc_toss); - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index 1debb2d..d5aa356 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid slhc if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 45d1780..3e66978 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -32,6 +32,7 @@ $(top_builddir)/src/gprs/oap_messages.o \ $(top_builddir)/src/gprs/gprs_llc_xid.o \ $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ + $(top_builddir)/src/gprs/slhc.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ diff --git a/openbsc/tests/slhc/Makefile.am b/openbsc/tests/slhc/Makefile.am new file mode 100644 index 0000000..d21990f --- /dev/null +++ b/openbsc/tests/slhc/Makefile.am @@ -0,0 +1,21 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) + +EXTRA_DIST = slhc_test.ok + +noinst_PROGRAMS = slhc_test + +slhc_test_SOURCES = slhc_test.c + +slhc_test_LDADD = \ + $(top_builddir)/src/gprs/slhc.o \ + $(top_builddir)/src/libcommon/libcommon.a \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOGB_LIBS) \ + $(LIBCARES_LIBS) \ + $(LIBCRYPTO_LIBS) \ + -lgtp -lrt -lm + + diff --git a/openbsc/tests/slhc/packets.txt b/openbsc/tests/slhc/packets.txt new file mode 100644 index 0000000..9f7adeb --- /dev/null +++ b/openbsc/tests/slhc/packets.txt @@ -0,0 +1,6 @@ +4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 +4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 +4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 +4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 +4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a +4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20 diff --git a/openbsc/tests/slhc/slhc_test.c b/openbsc/tests/slhc/slhc_test.c new file mode 100644 index 0000000..41babae --- /dev/null +++ b/openbsc/tests/slhc/slhc_test.c @@ -0,0 +1,311 @@ +/* Test SLHC/RFC1144 TCP/IP Header compression/decompression */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include + +#include +#include + +#include + +#include +#include +#include + +/* Number of compression slots (S0-1) */ +#define SLOTS 8 + +/* Maximum packet bytes to display */ +#define DISP_MAX_BYTES 100 + +/* Compress a packet using Van Jacobson RFC1144 header compression */ +static int compress(uint8_t *data_o, uint8_t *data_i, int len, + struct slcompress *comp) +{ + uint8_t *comp_ptr; /* Not used */ + int compr_len; + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Run compressor */ + compr_len = slhc_compress(comp, data_i, len, data_o, &comp_ptr, 0); + return compr_len; +} + +/* Expand a packet using Van Jacobson RFC1144 header compression */ +static int expand(uint8_t *data_o, uint8_t *data_i, int len, + struct slcompress *comp) +{ + int data_decompressed_len; + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Handle an uncompressed packet (learn header information */ + if ((data_i[0] & SL_TYPE_UNCOMPRESSED_TCP) == SL_TYPE_UNCOMPRESSED_TCP) { + data_o[0] &= 0x4F; + data_decompressed_len = slhc_remember(comp, data_o, len); + return data_decompressed_len; + } + + /* Uncompress compressed packets */ + else if (data_o[0] & SL_TYPE_COMPRESSED_TCP) { + data_decompressed_len = slhc_uncompress(comp, data_o, len); + return data_decompressed_len; + } + + /* Regular or unknown packets will not be touched */ + return len; +} + +/* Calculate TCP/IP checksum */ +static uint16_t calc_ip_csum(uint8_t *data, int len) +{ + int i; + uint32_t accumulator = 0; + uint16_t *pointer = (uint16_t *) data; + + for (i = len; i > 1; i -= 2) { + accumulator += *pointer; + pointer++; + } + + if (len % 2) + accumulator += *pointer; + + accumulator = (accumulator & 0xffff) + ((accumulator >> 16) & 0xffff); + accumulator += (accumulator >> 16) & 0xffff; + return (~accumulator); +} + +/* Calculate TCP/IP checksum */ +static uint16_t calc_tcpip_csum(const void *ctx, uint8_t *packet, int len) +{ + uint8_t *buf; + uint16_t csum; + + buf = talloc_zero_size(ctx, len); + memset(buf, 0, len); + memcpy(buf, packet + 12, 8); + buf[9] = packet[9]; + buf[11] = (len - 20) & 0xFF; + buf[10] = (len - 20) >> 8 & 0xFF; + memcpy(buf + 12, packet + 20, len - 20); + csum = calc_ip_csum(buf, len - 20 + 12); + talloc_free(buf); + return csum; +} + +/* Check TCP/IP packet */ +static void check_packet(const void *ctx, uint8_t *packet, int len) +{ + /* Check IP header */ + OSMO_ASSERT(len > 20); + OSMO_ASSERT(calc_ip_csum(packet, 20) == 0); + + /* Check TCP packet */ + if (packet[9] != 0x06) + return; + OSMO_ASSERT(len > 40); + OSMO_ASSERT(calc_tcpip_csum(ctx, packet, len) == 0); +} + +/* Strip TCP options from TCP/IP packet */ +static int strip_tcp_options(const void *ctx, uint8_t *packet, int len) +{ + uint8_t doff; + uint16_t csum; + + /* Check if the packet can be handled here */ + if (len < 37) + return len; + if (packet[9] != 0x06) + return len; + + /* Strip TCP/IP options from packet */ + doff = ((packet[32] >> 4) & 0x0F) * 4; + memmove(packet + 40, packet + doff + 20, len - 40 - (doff - 20)); + len = len - (doff - 20); + + /* Repair data offset (TCP header length) */ + packet[32] &= 0x0F; + packet[32] |= 0x50; + + /* Repair checksum */ + packet[36] = 0; + packet[37] = 0; + csum = calc_tcpip_csum(ctx, packet, len); + packet[36] = csum & 0xFF; + packet[37] = csum >> 8 & 0xFF; + + /* Repair total length */ + packet[3] = len & 0xFF; + packet[2] = len >> 8 & 0xFF; + + /* Repair IP header checksum */ + packet[10] = 0; + packet[11] = 0; + csum = calc_ip_csum(packet, 20); + packet[10] = csum & 0xFF; + packet[11] = csum >> 8 & 0xFF; + printf("csum=%04x\n", csum); + + return len; +} + +/* osmo_hexparse() does not like line breaks, this fixes that */ +static void fixup_hexstring(char *str) +{ + int i; + for (i = 0; i < strlen(str); i++) { + if (str[i] == '\n') + str[i] = 0; + } +} + +/* Compress / Decompress packets */ +static void test_slhc(const void *ctx) +{ + char packet_ascii[2048]; + FILE *fd = NULL; + char *rc_fgets; + + struct slcompress *comp; + uint8_t packet[1024]; + int packet_len; + uint8_t packet_compr[1024]; + int packet_compr_len; + uint8_t packet_decompr[1024]; + int packet_decompr_len; + + + printf("Allocating compression state...\n"); + comp = slhc_init(ctx, SLOTS, SLOTS); + OSMO_ASSERT(comp); + + printf("Opening file with sample packets...\n"); + fd = fopen("packets.txt", "r"); + OSMO_ASSERT(fd) + printf("\n"); + + while (1) { + /* Read input file */ + memset(packet_ascii, 0, sizeof(packet_ascii)); + memset(packet, 0, sizeof(packet)); + memset(packet_compr, 0, sizeof(packet_compr)); + memset(packet_decompr, 0, sizeof(packet_decompr)); + printf("Reading packet from file...\n"); + rc_fgets = fgets(packet_ascii, sizeof(packet_ascii), fd); + if (rc_fgets == NULL || strlen(packet_ascii) < 20) { + printf("=> End of file detected, test done!\n\n"); + break; + } + fixup_hexstring(packet_ascii); + packet_len = + osmo_hexparse(packet_ascii, packet, sizeof(packet)); + check_packet(ctx, packet, packet_len); + packet_len = strip_tcp_options(ctx, packet, packet_len); + check_packet(ctx, packet, packet_len); + + /* Run compression/decompression algorithm */ + printf("Compressing...\n"); + packet_compr_len = + compress(packet_compr, packet, packet_len, comp); + printf("Decompressing...\n"); + packet_decompr_len = + expand(packet_decompr, packet_compr, packet_compr_len, + comp); + OSMO_ASSERT(packet_decompr_len == packet_len); + check_packet(ctx,packet_decompr,packet_decompr_len); + + /* Display results */ + printf("Results:\n"); + if (packet_compr_len > DISP_MAX_BYTES) + packet_compr_len = DISP_MAX_BYTES; + if (packet_len > DISP_MAX_BYTES) + packet_len = DISP_MAX_BYTES; + if (packet_decompr_len > DISP_MAX_BYTES) + packet_decompr_len = DISP_MAX_BYTES; + printf("Original Packet: (%i bytes) %s\n", packet_len, + osmo_hexdump_nospc(packet, packet_len)); + printf("DecompressedPacket: (%i bytes) %s\n", + packet_decompr_len, osmo_hexdump_nospc(packet_decompr, + packet_decompr_len)); + printf("CompressedPacket: (%i bytes) %s\n", packet_compr_len, + osmo_hexdump_nospc(packet_compr, packet_compr_len)); + slhc_o_status(comp); + slhc_o_status(comp); + + printf("\n"); + } + + printf("Freeing compression state...\n"); + slhc_free(comp); + printf("\n"); + fclose(fd); +} + +static struct log_info_cat gprs_categories[] = { + [DSNDCP] = { + .name = "DSNDCP", + .description = + "GPRS Sub-Network Dependent Control Protocol (SNDCP)", + .enabled = 1,.loglevel = LOGL_DEBUG, + }, + [DSLHC] = { + .name = "DSLHC", + .description = + "Van Jacobson RFC1144 TCP/IP header compression (SLHC)", + .enabled = 1,.loglevel = LOGL_DEBUG, + } +}; + +static struct log_info info = { + .cat = gprs_categories, + .num_cat = ARRAY_SIZE(gprs_categories), +}; + +int main(int argc, char **argv) +{ + void *ctx; + + osmo_init_logging(&info); + + ctx = talloc_named_const(NULL, 0, "slhc_ctx"); + + test_slhc(ctx); + + printf("Done\n"); + + talloc_report_full(ctx, stderr); + OSMO_ASSERT(talloc_total_blocks(ctx) == 1); + return 0; +} + +/* stubs */ +struct osmo_prim_hdr; +int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) +{ + abort(); +} diff --git a/openbsc/tests/slhc/slhc_test.ok b/openbsc/tests/slhc/slhc_test.ok new file mode 100644 index 0000000..3f802ea --- /dev/null +++ b/openbsc/tests/slhc/slhc_test.ok @@ -0,0 +1,63 @@ +Allocating compression state... +Opening file with sample packets... + +Reading packet from file... +csum=b3a9 +Compressing... +Decompressing... +Results: +Original Packet: (52 bytes) 4510003446dd40004006a9b3c0a8646ec0a864640017ad8b81980100f3ac984d501800e371410000fffd18fffd20fffd23fffd27 +DecompressedPacket: (52 bytes) 4510003446dd40004006a9b3c0a8646ec0a864640017ad8b81980100f3ac984d501800e371410000fffd18fffd20fffd23fffd27 +CompressedPacket: (52 bytes) 7510003446dd40004000a9b3c0a8646ec0a864640017ad8b81980100f3ac984d501800e371410000fffd18fffd20fffd23fffd27 + +Reading packet from file... +csum=97a9 +Compressing... +Decompressing... +Results: +Original Packet: (79 bytes) 4510004f46de40004006a997c0a8646ec0a864640017ad8b8198010cf3ac984d501800e3cda40000fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 +DecompressedPacket: (79 bytes) 4510004f46de40004006a997c0a8646ec0a864640017ad8b8198010cf3ac984d501800e3cda40000fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 +CompressedPacket: (43 bytes) df00cda4fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 + +Reading packet from file... +csum=baa9 +Compressing... +Decompressing... +Results: +Original Packet: (43 bytes) 4510002b46df40004006a9bac0a8646ec0a864640017ad8b81980133f3ac989f501800e3a70a0000fffd01 +DecompressedPacket: (43 bytes) 4510002b46df40004006a9bac0a8646ec0a864640017ad8b81980133f3ac989f501800e3a70a0000fffd01 +CompressedPacket: (9 bytes) dc00a70a5227fffd01 + +Reading packet from file... +csum=b9a9 +Compressing... +Decompressing... +Results: +Original Packet: (43 bytes) 4510002b46e040004006a9b9c0a8646ec0a864640017ad8b81980136f3ac98a2501800e3a7060000fffb01 +DecompressedPacket: (43 bytes) 4510002b46e040004006a9b9c0a8646ec0a864640017ad8b81980136f3ac98a2501800e3a7060000fffb01 +CompressedPacket: (7 bytes) db00a706fffb01 + +Reading packet from file... +csum=7ba9 +Compressing... +Decompressing... +Results: +Original Packet: (100 bytes) 4510006846e140004006a97bc0a8646ec0a864640017ad8b81980139f3ac98a5501800e3c2d000000d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d +DecompressedPacket: (100 bytes) 4510006846e140004006a97bc0a8646ec0a864640017ad8b81980139f3ac98a5501800e3c2d000000d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d +CompressedPacket: (68 bytes) db00c2d00d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a + +Reading packet from file... +csum=aca9 +Compressing... +Decompressing... +Results: +Original Packet: (54 bytes) 4510003646e240004006a9acc0a8646ec0a864640017ad8b81980179f3ac98a5501800e321fb0000706f6c6c7578206c6f67696e3a20 +DecompressedPacket: (54 bytes) 4510003646e240004006a9acc0a8646ec0a864640017ad8b81980179f3ac98a5501800e321fb0000706f6c6c7578206c6f67696e3a20 +CompressedPacket: (18 bytes) df0021fb706f6c6c7578206c6f67696e3a20 + +Reading packet from file... +=> End of file detected, test done! + +Freeing compression state... + +Done diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index 85a81d6..5f37b8e 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -136,3 +136,8 @@ AT_CHECK([$abs_top_builddir/tests/sndcp_xid/sndcp_xid_test], [], [expout], [ignore]) AT_CLEANUP +AT_SETUP([slhc]) +AT_KEYWORDS([slhc]) +cat $abs_srcdir/slhc/slhc_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/slhc/slhc_test], [], [expout], [ignore]) +AT_CLEANUP -- To view, visit https://gerrit.osmocom.org/635 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 Gerrit-PatchSet: 10 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Wed Aug 17 13:21:35 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Wed, 17 Aug 2016 13:21:35 +0000 Subject: [PATCH] osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/655 to look at the new patch set (#16). Modify EGPRS DL TBF flow to support SPB Modify the EGPRS DL TBF flow to support Split block during Retx. This patch will also Upgrade the test suite with test cases to validate the EGPRS Downlink SPB for Retransmission Scenarios like MCS6->MCS3, MCS4->MCS1, MCS5->MCS2, MCS9->MCS3 MCS7->MCS2, MCS8->MCS3 have been simulated and Integration tested in NuRAN 1.0 hardware thoroughly. Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 --- M src/gprs_coding_scheme.h M src/pcu_main.cpp M src/pcu_vty.c M src/rlc.cpp M src/rlc.h M src/tbf.h M src/tbf_dl.cpp M tests/edge/EdgeTest.cpp M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 11 files changed, 956 insertions(+), 80 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/55/655/16 diff --git a/src/gprs_coding_scheme.h b/src/gprs_coding_scheme.h index 60a8e79..3b15372 100644 --- a/src/gprs_coding_scheme.h +++ b/src/gprs_coding_scheme.h @@ -113,7 +113,8 @@ static const char *modeName(Mode mode); static Scheme get_retx_mcs(const GprsCodingScheme mcs, - const GprsCodingScheme retx_mcs); + const GprsCodingScheme retx_mcs, + const unsigned arq_type); static enum Scheme egprs_mcs_retx_tbl[MAX_NUM_ARQ] [MAX_NUM_MCS][MAX_NUM_MCS]; @@ -232,8 +233,9 @@ } inline GprsCodingScheme::Scheme GprsCodingScheme::get_retx_mcs( const GprsCodingScheme mcs, - const GprsCodingScheme demanded_mcs) + const GprsCodingScheme demanded_mcs, + const unsigned arq_type) { - return egprs_mcs_retx_tbl[EGPRS_ARQ2][mcs.to_num() - 1] + return egprs_mcs_retx_tbl[arq_type][mcs.to_num() - 1] [demanded_mcs.to_num() - 1]; } diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2d86cda..e34d534 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -210,6 +210,12 @@ bts->dl_tbf_idle_msec = 2000; bts->llc_idle_ack_csec = 10; + /* + * By default resegmentation is supported in DL + * can also be configured through VTY + */ + bts->dl_arq_type = EGPRS_ARQ1; + msgb_set_talloc_ctx(tall_pcu_ctx); osmo_init_logging(&gprs_log_info); diff --git a/src/pcu_vty.c b/src/pcu_vty.c index 58fea99..ea0d2d5 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -129,6 +129,10 @@ vty_out(vty, " window-size %d %d%s", bts->ws_base, bts->ws_pdch, VTY_NEWLINE); + if (bts->dl_arq_type) + vty_out(vty, " dl arq-type %d%s", bts->dl_arq_type, + VTY_NEWLINE); + if (bts->force_llc_lifetime == 0xffff) vty_out(vty, " queue lifetime infinite%s", VTY_NEWLINE); else if (bts->force_llc_lifetime) @@ -476,6 +480,23 @@ bts->max_mcs_dl = 0; bts->max_mcs_ul = 0; + + return CMD_SUCCESS; +} + +DEFUN(cfg_pcu_dl_arq_type, + cfg_pcu_dl_arq_cmd, + "dl arq-type (spb|arq2)", + EGPRS_STR "DL ARQ options\n" + "enable DL SPB(ARQ1) support\n" + "enable DL ARQ2 support") +{ + struct gprs_rlcmac_bts *bts = bts_main_data(); + + if (!strcmp(argv[0], "arq2")) + bts->arq_type = 1; + else + bts->arq_type = 0; return CMD_SUCCESS; } @@ -954,6 +975,7 @@ install_element(PCU_NODE, &cfg_pcu_no_cs_downgrade_thrsh_cmd); install_element(PCU_NODE, &cfg_pcu_cs_lqual_ranges_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_cmd); + install_element(PCU_NODE, &cfg_pcu_dl_arq_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_max_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_max_cmd); diff --git a/src/rlc.cpp b/src/rlc.cpp index 6770043..e69d1fc 100644 --- a/src/rlc.cpp +++ b/src/rlc.cpp @@ -285,7 +285,8 @@ } static void gprs_rlc_data_header_init(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding, unsigned int header_bits) + GprsCodingScheme cs, bool with_padding, unsigned int header_bits, + const unsigned int spb) { unsigned int i; unsigned int padding_bits = with_padding ? cs.optionalPaddingBits() : 0; @@ -300,7 +301,7 @@ for (i = 0; i < rlc->num_data_blocks; i++) { gprs_rlc_data_block_info_init(&rlc->block_info[i], cs, - with_padding); + with_padding, spb); rlc->data_offs_bits[i] = header_bits + padding_bits + @@ -310,21 +311,25 @@ } void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsDL()); + cs.numDataHeaderBitsDL(), spb); } void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding) { + /* + * last parameter is sent as 0 since common function used + * for both DL and UL + */ return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsUL()); + cs.numDataHeaderBitsUL(), 0); } void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { unsigned int data_len = cs.maxDataBlockBytes(); if (with_padding) @@ -336,7 +341,7 @@ rdbi->e = 1; rdbi->cv = 15; rdbi->pi = 0; - rdbi->spb = 0; + rdbi->spb = spb; } unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, @@ -411,8 +416,18 @@ enum egprs_puncturing_values gprs_get_punct_scheme( enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current) + const GprsCodingScheme &cs_current, + const enum egprs_rlcmac_dl_spb spb) { + + /* + * 10.4.8b of TS 44.060 + * If it is second segment of the block + * dont change the puncturing scheme + */ + if (spb == EGPRS_RLCMAC_DL_SEC_SEG) + return punct; + /* TS 44.060 9.3.2.1.1 */ if ((GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS9) && (GprsCodingScheme::Scheme(cs_current) == GprsCodingScheme::MCS6)) { diff --git a/src/rlc.h b/src/rlc.h index b1a1fba..b693418 100644 --- a/src/rlc.h +++ b/src/rlc.h @@ -213,18 +213,19 @@ }; void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding); void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, enum egprs_puncturing_values punct, enum egprs_puncturing_values punct2, int with_padding); void gprs_rlc_mcs_cps_decode(unsigned int cps, GprsCodingScheme cs, int *punct, int *punct2, int *with_padding); enum egprs_puncturing_values gprs_get_punct_scheme(enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current_trans); + const GprsCodingScheme &cs_current_trans, + const enum egprs_rlcmac_dl_spb spb); void gprs_update_punct_scheme(enum egprs_puncturing_values *punct, const GprsCodingScheme &cs); /* diff --git a/src/tbf.h b/src/tbf.h index 1bd7878..2a1bfe8 100644 --- a/src/tbf.h +++ b/src/tbf.h @@ -421,6 +421,11 @@ int analyse_errors(char *show_rbb, uint8_t ssn, ana_result *res); void schedule_next_frame(); + enum egprs_rlc_dl_reseg_bsn_state egprs_dl_get_data + (int bsn, uint8_t **block_data); + unsigned int get_egprs_dl_spb_status(int bsn); + enum egprs_rlcmac_dl_spb get_egprs_dl_spb(int bsn); + struct osmo_timer_list m_llc_timer; }; diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp index 07a747a..a24cc21 100644 --- a/src/tbf_dl.cpp +++ b/src/tbf_dl.cpp @@ -375,21 +375,28 @@ return -1; if (is_egprs_enabled()) { + /* Table 8.1.1.2 and Table 8.1.1.1 of 44.060 */ m_rlc.block(bsn)->cs_current_trans = - GprsCodingScheme::get_retx_mcs( - m_rlc.block(bsn)->cs_last, ms()->current_cs_dl()); + GprsCodingScheme::get_retx_mcs( + m_rlc.block(bsn)->cs_init, + ms()->current_cs_dl(), + bts->bts_data()->dl_arq_type); LOGP(DRLCMACDL, LOGL_DEBUG, - "- current_cs_dl(%d) demanded_mcs(%d) cs_trans(%d)\n", - m_rlc.block(bsn)->cs_last.to_num(), - ms()->current_cs_dl().to_num(), - m_rlc.block(bsn)->cs_current_trans.to_num()); + "- initial_cs_dl(%d) last_mcs(%d)" + " demanded_mcs(%d) cs_trans(%d)" + " arq_type(%d) bsn(%d)\n", + m_rlc.block(bsn)->cs_init.to_num(), + m_rlc.block(bsn)->cs_last.to_num(), + ms()->current_cs_dl().to_num(), + m_rlc.block(bsn)->cs_current_trans.to_num(), + bts->bts_data()->dl_arq_type, bsn); /* TODO: Need to remove this check when MCS-8 -> MCS-6 * transistion is handled. * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 */ - if (m_rlc.block(bsn)->cs_last == GprsCodingScheme::MCS8) + if (m_rlc.block(bsn)->cs_init == GprsCodingScheme::MCS8) m_rlc.block(bsn)->cs_current_trans = GprsCodingScheme::MCS8; } else @@ -523,6 +530,11 @@ data = rlc_data->prepare(block_data_len); rlc_data->cs_last = cs; rlc_data->cs_current_trans = cs; + + /* Initialise the variable related to DL SPB */ + rlc_data->spb_status.block_status_dl = EGPRS_RESEG_DL_DEFAULT; + rlc_data->cs_init = cs; + rlc_data->len = block_data_len; rdbi = &(rlc_data->block_info); @@ -616,7 +628,8 @@ unsigned num_bsns; enum egprs_puncturing_values punct[ARRAY_SIZE(rlc.block_info)]; bool need_padding = false; - + enum egprs_rlcmac_dl_spb spb = EGPRS_RLCMAC_DL_NO_RETX; + unsigned int spb_status = get_egprs_dl_spb_status(index); /* * TODO: This is an experimental work-around to put 2 BSN into * MSC-7 to MCS-9 encoded messages. It just sends the same BSN @@ -626,6 +639,7 @@ * the current limit. */ cs = m_rlc.block(index)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(index)->cs_init; bsns[0] = index; num_bsns = 1; @@ -634,7 +648,17 @@ num_bsns += 1; } - if (num_bsns == 1) { + /* + * if the intial mcs is 8 and retransmission mcs is either 6 or 3 + * we have to include the padding of 6 octets in first segment + */ + if ((GprsCodingScheme::Scheme(cs_init) == GprsCodingScheme::MCS8) && + (GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS6 || + GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS3)) { + if (spb_status == EGPRS_RESEG_DL_DEFAULT || + spb_status == EGPRS_RESEG_SECOND_SEG_SENT) + need_padding = true; + } else if (num_bsns == 1) { /* TODO: remove the conditional when MCS-6 padding isn't * failing to be decoded by MEs anymore */ /* TODO: support of MCS-8 -> MCS-6 transition should be @@ -646,7 +670,14 @@ cs.decToSingleBlock(&need_padding); } - gprs_rlc_data_info_init_dl(&rlc, cs, need_padding); + spb = get_egprs_dl_spb(index); + + LOGP(DRLCMACDL, LOGL_DEBUG, "- need_padding %d spb_status %d spb %d" + "(BSN1 %d BSN2 %d)\n", + need_padding, + spb_status, spb, index, index2); + + gprs_rlc_data_info_init_dl(&rlc, cs, need_padding, spb); rlc.usf = 7; /* will be set at scheduler */ rlc.pr = 0; /* FIXME: power reduction */ @@ -665,10 +696,9 @@ data_block_idx++) { int bsn; - GprsCodingScheme cs_enc; uint8_t *block_data; gprs_rlc_data_block_info *rdbi, *block_info; - enum egprs_puncturing_values punct_scheme; + enum egprs_rlc_dl_reseg_bsn_state reseg_status; /* Check if there are more blocks than BSNs */ if (data_block_idx < num_bsns) @@ -676,38 +706,43 @@ else bsn = bsns[0]; - cs_enc = m_rlc.block(bsn)->cs_current_trans; - /* get data and header from current block */ - block_data = m_rlc.block(bsn)->block; - /* Get current puncturing scheme from block */ - punct_scheme = gprs_get_punct_scheme( + + m_rlc.block(bsn)->next_ps = gprs_get_punct_scheme( m_rlc.block(bsn)->next_ps, - m_rlc.block(bsn)->cs_last, cs); + m_rlc.block(bsn)->cs_last, cs, spb); if (cs.isEgprs()) { - OSMO_ASSERT(punct_scheme >= EGPRS_PS_1); - OSMO_ASSERT(punct_scheme <= EGPRS_PS_3); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps >= EGPRS_PS_1); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps <= EGPRS_PS_3); } - punct[data_block_idx] = punct_scheme; + punct[data_block_idx] = m_rlc.block(bsn)->next_ps; rdbi = &rlc.block_info[data_block_idx]; block_info = &m_rlc.block(bsn)->block_info; - if(rdbi->data_len != m_rlc.block(bsn)->len) { - LOGP(DRLCMACDL, LOGL_ERROR, - "ERROR: Expected len = %d for %s instead of " - "%d in data unit %d (BSN %d, %s)\n", - rdbi->data_len, cs.name(), m_rlc.block(bsn)->len, - data_block_idx, bsn, cs_enc.name()); - OSMO_ASSERT(rdbi->data_len == m_rlc.block(bsn)->len); - } - - /* TODO: Need to handle 2 same bsns - * in header type 1 + /* + * get data and header from current block + * function returns the reseg status */ - gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, - cs); + reseg_status = egprs_dl_get_data(bsn, &block_data); + m_rlc.block(bsn)->spb_status.block_status_dl = reseg_status; + + /* + * If it is first segment of the split block set the state of + * bsn to nacked. If it is the first segment dont update the + * next ps value of bsn. since next segment also needs same cps + */ + if (spb == EGPRS_RLCMAC_DL_FIRST_SEG) + m_window.m_v_b.mark_nacked(bsn); + else { + /* + * TODO: Need to handle 2 same bsns + * in header type 1 + */ + gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, + cs); + } m_rlc.block(bsn)->cs_last = cs; rdbi->e = block_info->e; @@ -1169,3 +1204,118 @@ keep_time_frames = msecs_to_frames(bts_data()->dl_tbf_idle_msec); return frames_since_last_drain(fn) <= keep_time_frames; } + +/* + * This function returns the pointer to data which needs + * to be copied. Also updates the status of the block related to + * Split block handling in the RLC/MAC block. + */ +enum egprs_rlc_dl_reseg_bsn_state + gprs_rlcmac_dl_tbf::egprs_dl_get_data(int bsn, uint8_t **block_data) +{ + gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state *block_status_dl = + &rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + *block_data = &rlc_data->block[0]; + + /* + * Table 10.3a.0.1 of 44.060 + * MCS6,9: second segment starts at 74/2 = 37 + * MCS5,7: second segment starts at 56/2 = 28 + * MCS8: second segment starts at 31 + * MCS4: second segment starts at 44/2 = 22 + */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + if (*block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + switch (GprsCodingScheme::Scheme(cs_init)) { + case GprsCodingScheme::MCS6 : + case GprsCodingScheme::MCS9 : + *block_data = &rlc_data->block[37]; + break; + case GprsCodingScheme::MCS7 : + case GprsCodingScheme::MCS5 : + *block_data = &rlc_data->block[28]; + break; + case GprsCodingScheme::MCS8 : + *block_data = &rlc_data->block[31]; + break; + case GprsCodingScheme::MCS4 : + *block_data = &rlc_data->block[22]; + break; + default: + LOGP(DRLCMACDL, LOGL_ERROR, "Software error: " + "--%s hit invalid condition. headerType(%d) " + " blockstatus(%d) cs(%s) PLEASE FIX!\n", name(), + cs_current_trans.headerTypeData(), + *block_status_dl, cs_init.name()); + break; + + } + return EGPRS_RESEG_SECOND_SEG_SENT; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } + } + return EGPRS_RESEG_DL_DEFAULT; +} + +/* + * This function returns the status of split block + * for RLC/MAC block. + */ +unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_status(const int bsn) +{ + const gprs_rlc_data *rlc_data = m_rlc.block(bsn); + + return rlc_data->spb_status.block_status_dl; +} + +/* + * This function returns the spb value to be sent OTA + * for RLC/MAC block. + */ +enum egprs_rlcmac_dl_spb gprs_rlcmac_dl_tbf::get_egprs_dl_spb(const int bsn) +{ + struct gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state block_status_dl = + rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + + /* Table 10.4.8b.1 of 44.060 */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + /* + * if we are sending the second segment the spb should be 3 + * other wise it should be 2 + */ + if (block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + return EGPRS_RLCMAC_DL_SEC_SEG; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RLCMAC_DL_FIRST_SEG; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RLCMAC_DL_FIRST_SEG; + } + } + /* Non SPB cases 0 is reurned */ + return EGPRS_RLCMAC_DL_NO_RETX; +} diff --git a/tests/edge/EdgeTest.cpp b/tests/edge/EdgeTest.cpp index 807102c..9081d4d 100644 --- a/tests/edge/EdgeTest.cpp +++ b/tests/edge/EdgeTest.cpp @@ -517,7 +517,7 @@ /* TS 44.060, B.1 */ cs = GprsCodingScheme::CS4; - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -570,7 +570,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -592,7 +592,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -630,7 +630,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -669,7 +669,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -694,7 +694,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -719,7 +719,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -740,7 +740,7 @@ OSMO_ASSERT(data[0] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -777,7 +777,7 @@ cs = GprsCodingScheme::MCS4; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -835,7 +835,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -872,7 +872,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -923,7 +923,7 @@ OSMO_ASSERT(data[3] == 0); /* Block 3 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -967,7 +967,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -993,7 +993,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1020,7 +1020,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1074,7 +1074,7 @@ block_idx++) { struct gprs_rlc_data_info rlc; - gprs_rlc_data_info_init_dl(&rlc, cs, false); + gprs_rlc_data_info_init_dl(&rlc, cs, false, 0); memset(bits, pattern, sizeof(bits)); Decoding::rlc_copy_to_aligned_buffer( @@ -1118,12 +1118,14 @@ struct gprs_rlc_data_info rlc; printf("=== start %s ===\n", __func__); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::CS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::CS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 24); OSMO_ASSERT(rlc.block_info[0].data_len == 20); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::MCS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::MCS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 33); OSMO_ASSERT(rlc.block_info[0].data_len == 22); diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..5e45506 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -1814,6 +1814,203 @@ } +static void egprs_spb_to_normal_validation(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + uint16_t bsn1, bsn2, bsn3; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + struct gprs_rlc_dl_header_egprs_2 *egprs2; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + if (!(mcs == 6 && demanded_mcs == 3)) + return; + + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + bsn1 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) + || (egprs2->bsn1_lo); + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(bsn1 == 0); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + bsn2 = (egprs3->bsn1_hi << 9) || (egprs3->bsn1_mid << 1) || + (egprs3->bsn1_lo); + OSMO_ASSERT(bsn2 == bsn1); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Handle (MCS3, MCS3) -> MCS6 case */ + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + mcs)); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs2->cps == 0); + bsn3 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) || + (egprs2->bsn1_lo); + OSMO_ASSERT(bsn3 == bsn2); + + tbf_cleanup(dl_tbf); +} +static void establish_and_use_egprs_dl_tbf_for_spb(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + /* TODO: Need to support of MCS8 -> MCS6 ->MCS3 transistion + * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 + * dated 2016-02-07 23:45:40 (UTC) + */ + if (!(((mcs == 5) && (demanded_mcs == 2)) || + ((mcs == 6) && (demanded_mcs == 3)) || + ((mcs == 4) && (demanded_mcs == 1)))) + return; + + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + tbf_cleanup(dl_tbf); +} + static void establish_and_use_egprs_dl_tbf_for_retx(BTS *the_bts, int mcs, int demanded_mcs) { @@ -1972,6 +2169,9 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; + /* First parameter is current MCS, second one is demanded_mcs */ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 6); @@ -1981,6 +2181,38 @@ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 9); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 7, 5); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 9, 6); + + printf("=== end %s ===\n", __func__); +} + +static void test_tbf_egprs_spb_dl(void) +{ + BTS the_bts; + gprs_rlcmac_bts *bts; + uint8_t ts_no = 4; + int i, j; + + printf("=== start %s ===\n", __func__); + + bts = the_bts.bts_data(); + bts->cs_downgrade_threshold = 0; + setup_bts(&the_bts, ts_no); + bts->dl_tbf_idle_msec = 200; + bts->egprs_enabled = 1; + + /* ARQ I resegmentation support */ + bts->dl_arq_type = EGPRS_ARQ1; + + /* + * First parameter is current MCS, second one is demanded_mcs + * currently only MCS5->MCS2, MCS6->3, MCS4->MCS1 is tested in UT + * rest scenarios has been integration tested + */ + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 6, 3); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 5, 2); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 4, 1); + /* check MCS6->(MCS3+MCS3)->MCS6 case */ + egprs_spb_to_normal_validation(&the_bts, 6, 3); printf("=== end %s ===\n", __func__); } @@ -1999,6 +2231,8 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; for (i = 1; i <= 9; i++) establish_and_use_egprs_dl_tbf(&the_bts, i); @@ -2071,6 +2305,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_egprs_spb_dl(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..1ba4189 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -72,6 +72,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -81,6 +82,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -157,6 +159,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -166,6 +169,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -242,6 +246,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -251,6 +256,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -259,6 +265,7 @@ - Sending new block at BSN 2, CS=CS-1 -- Chunk with length 160 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=13 block=3 data=07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b @@ -267,6 +274,7 @@ - Sending new block at BSN 3, CS=CS-1 -- Chunk with length 140 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=17 block=4 data=07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @@ -275,6 +283,7 @@ - Sending new block at BSN 4, CS=CS-1 -- Chunk with length 120 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=21 block=5 data=07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 @@ -283,6 +292,7 @@ - Sending new block at BSN 5, CS=CS-1 -- Chunk with length 100 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=26 block=6 data=07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 @@ -291,6 +301,7 @@ - Sending new block at BSN 6, CS=CS-1 -- Chunk with length 80 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=30 block=7 data=07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b @@ -299,6 +310,7 @@ - Sending new block at BSN 7, CS=CS-1 -- Chunk with length 60 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=34 block=8 data=07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f @@ -307,6 +319,7 @@ - Sending new block at BSN 8, CS=CS-1 -- Chunk with length 40 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=39 block=9 data=07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 @@ -315,6 +328,7 @@ - Sending new block at BSN 9, CS=CS-1 -- Chunk with length 20 would exactly fit into space (20): add length header with LI=0, to make frame extend to next block, and we are done data block (BSN 9, CS-1): 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=43 block=10 data=07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 @@ -326,6 +340,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=47 block=11 data=07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 @@ -334,6 +349,7 @@ - Sending new block at BSN 11, CS=CS-1 -- Chunk with length 182 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=52 block=0 data=07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 @@ -342,6 +358,7 @@ - Sending new block at BSN 12, CS=CS-1 -- Chunk with length 162 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=56 block=1 data=07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 @@ -350,6 +367,7 @@ - Sending new block at BSN 13, CS=CS-1 -- Chunk with length 142 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 13, CS-1): 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=60 block=2 data=07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d @@ -358,6 +376,7 @@ - Sending new block at BSN 14, CS=CS-1 -- Chunk with length 122 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=65 block=3 data=07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 @@ -366,6 +385,7 @@ - Sending new block at BSN 15, CS=CS-1 -- Chunk with length 102 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=69 block=4 data=07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 @@ -374,6 +394,7 @@ - Sending new block at BSN 16, CS=CS-1 -- Chunk with length 82 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=73 block=5 data=07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 @@ -382,6 +403,7 @@ - Sending new block at BSN 17, CS=CS-1 -- Chunk with length 62 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=78 block=6 data=07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d @@ -390,6 +412,7 @@ - Sending new block at BSN 18, CS=CS-1 -- Chunk with length 42 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=82 block=7 data=07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 @@ -398,6 +421,7 @@ - Sending new block at BSN 19, CS=CS-1 -- Chunk with length 22 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=86 block=8 data=07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 @@ -411,6 +435,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=16 data block (BSN 20, CS-1): 0a 41 c6 c7 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -449,6 +474,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 data block (BSN 21, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -468,6 +494,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 22, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FINISHED) @@ -1481,6 +1508,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 0, CS-1): 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 MSG = 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 @@ -1491,6 +1519,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 1, CS-1): 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 MSG = 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 @@ -1501,6 +1530,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FINISHED data block (BSN 2, CS-1): 4d 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling cannot be scheduled in this TS 7 (first control TS 4) @@ -1784,6 +1814,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=10 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 0, CS-4): 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654292 TS 7 @@ -1797,6 +1828,7 @@ TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) downlink (V(A)==0 .. V(S)==1) - Restarting at BSN 0, because all blocks have been transmitted. - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-4): 07 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 @@ -2365,6 +2397,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654279 block=10 data=00 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 @@ -2384,6 +2417,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -2406,6 +2440,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654288 block=0 data=00 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 @@ -2425,6 +2460,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654292 block=1 data=00 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2447,6 +2483,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654296 block=2 data=00 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c @@ -2466,6 +2503,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654301 block=3 data=00 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b @@ -2488,6 +2526,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 6, CS-1): 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654305 block=4 data=00 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 @@ -2507,6 +2546,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654309 block=5 data=00 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 @@ -2526,6 +2566,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654314 block=6 data=00 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 @@ -2548,6 +2589,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654318 block=7 data=00 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 @@ -2567,6 +2609,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654322 block=8 data=00 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2589,6 +2632,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654327 block=9 data=00 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c @@ -2608,6 +2652,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654331 block=10 data=00 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b @@ -2630,6 +2675,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 13, CS-1): 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654335 block=11 data=00 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 @@ -2649,6 +2695,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654340 block=0 data=00 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 @@ -2668,6 +2715,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654344 block=1 data=00 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 @@ -2690,6 +2738,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654348 block=2 data=00 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 @@ -2709,6 +2758,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654353 block=3 data=00 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2731,6 +2781,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654357 block=4 data=00 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c @@ -2750,6 +2801,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654361 block=5 data=00 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b @@ -2772,6 +2824,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 20, CS-1): 16 35 45 54 20 32 38 4c 4c 43 20 50 41 43 4b 45 54 20 32 39 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because 20 blocks sent. TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW): Scheduling polling at FN 2654379 TS 7 @@ -2795,6 +2848,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 21, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) msg block (BSN 21, CS-1): 07 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654370 block=7 data=00 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 @@ -2814,6 +2868,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 22, CS-1): 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) msg block (BSN 22, CS-1): 07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654374 block=8 data=07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 @@ -2836,6 +2891,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 23, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) msg block (BSN 23, CS-1): 07 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654379 block=9 data=00 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 @@ -2855,6 +2911,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 24, CS-1): 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) msg block (BSN 24, CS-1): 07 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654383 block=10 data=00 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2877,6 +2934,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 25, CS-1): 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 25 BSN2 -1) - Copying data unit 0 (BSN 25) msg block (BSN 25, CS-1): 07 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654387 block=11 data=00 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c @@ -2896,6 +2954,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 26, CS-1): 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 26 BSN2 -1) - Copying data unit 0 (BSN 26) msg block (BSN 26, CS-1): 07 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654392 block=0 data=00 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b @@ -2918,6 +2977,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 27, CS-1): 16 35 45 54 20 33 38 4c 4c 43 20 50 41 43 4b 45 54 20 33 39 +- need_padding 0 spb_status 0 spb 0(BSN1 27 BSN2 -1) - Copying data unit 0 (BSN 27) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) @@ -3028,6 +3088,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654405 block=3 data=00 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 @@ -3047,6 +3108,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654409 block=4 data=00 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 @@ -3066,6 +3128,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (16) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654413 block=5 data=00 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 @@ -3085,6 +3148,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (14) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654418 block=6 data=00 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 @@ -3104,6 +3168,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654422 block=7 data=00 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -3123,6 +3188,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654426 block=8 data=00 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 @@ -3142,6 +3208,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654431 block=9 data=00 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b @@ -3161,6 +3228,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654435 block=10 data=00 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 @@ -3180,6 +3248,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654439 block=11 data=00 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 @@ -3199,6 +3268,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654444 block=0 data=00 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c @@ -3218,6 +3288,7 @@ Complete DL frame for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=21 TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 10, CS-1): 4d 43 20 50 41 43 4b 45 54 20 30 39 20 28 54 42 46 20 32 29 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654461 TS 7 @@ -3698,6 +3769,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 0, MCS-1): 14 15 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3711,6 +3783,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3721,6 +3794,7 @@ - Sending new block at BSN 2, CS=MCS-1 -- Chunk with length 490 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3731,6 +3805,7 @@ - Sending new block at BSN 3, CS=MCS-1 -- Chunk with length 468 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3741,6 +3816,7 @@ - Sending new block at BSN 4, CS=MCS-1 -- Chunk with length 446 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3751,6 +3827,7 @@ - Sending new block at BSN 5, CS=MCS-1 -- Chunk with length 424 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3761,6 +3838,7 @@ - Sending new block at BSN 6, CS=MCS-1 -- Chunk with length 402 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3771,6 +3849,7 @@ - Sending new block at BSN 7, CS=MCS-1 -- Chunk with length 380 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3781,6 +3860,7 @@ - Sending new block at BSN 8, CS=MCS-1 -- Chunk with length 358 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3791,6 +3871,7 @@ - Sending new block at BSN 9, CS=MCS-1 -- Chunk with length 336 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3801,6 +3882,7 @@ - Sending new block at BSN 10, CS=MCS-1 -- Chunk with length 314 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3811,6 +3893,7 @@ - Sending new block at BSN 11, CS=MCS-1 -- Chunk with length 292 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3821,6 +3904,7 @@ - Sending new block at BSN 12, CS=MCS-1 -- Chunk with length 270 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3831,6 +3915,7 @@ - Sending new block at BSN 13, CS=MCS-1 -- Chunk with length 248 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3841,6 +3926,7 @@ - Sending new block at BSN 14, CS=MCS-1 -- Chunk with length 226 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3851,6 +3937,7 @@ - Sending new block at BSN 15, CS=MCS-1 -- Chunk with length 204 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3861,6 +3948,7 @@ - Sending new block at BSN 16, CS=MCS-1 -- Chunk with length 182 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3871,6 +3959,7 @@ - Sending new block at BSN 17, CS=MCS-1 -- Chunk with length 160 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3881,6 +3970,7 @@ - Sending new block at BSN 18, CS=MCS-1 -- Chunk with length 138 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3891,6 +3981,7 @@ - Sending new block at BSN 19, CS=MCS-1 -- Chunk with length 116 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 19, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3901,6 +3992,7 @@ - Sending new block at BSN 20, CS=MCS-1 -- Chunk with length 94 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 20, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3911,6 +4003,7 @@ - Sending new block at BSN 21, CS=MCS-1 -- Chunk with length 72 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 21, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3921,6 +4014,7 @@ - Sending new block at BSN 22, CS=MCS-1 -- Chunk with length 50 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 22, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3931,6 +4025,7 @@ - Sending new block at BSN 23, CS=MCS-1 -- Chunk with length 28 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 23, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3946,6 +4041,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 24, MCS-1): 0c 1d 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4006,6 +4102,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=16 data block (BSN 0, MCS-2): 14 21 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4019,6 +4116,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4029,6 +4127,7 @@ - Sending new block at BSN 2, CS=MCS-2 -- Chunk with length 484 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4039,6 +4138,7 @@ - Sending new block at BSN 3, CS=MCS-2 -- Chunk with length 456 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4049,6 +4149,7 @@ - Sending new block at BSN 4, CS=MCS-2 -- Chunk with length 428 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4059,6 +4160,7 @@ - Sending new block at BSN 5, CS=MCS-2 -- Chunk with length 400 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4069,6 +4171,7 @@ - Sending new block at BSN 6, CS=MCS-2 -- Chunk with length 372 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4079,6 +4182,7 @@ - Sending new block at BSN 7, CS=MCS-2 -- Chunk with length 344 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4089,6 +4193,7 @@ - Sending new block at BSN 8, CS=MCS-2 -- Chunk with length 316 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4099,6 +4204,7 @@ - Sending new block at BSN 9, CS=MCS-2 -- Chunk with length 288 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4109,6 +4215,7 @@ - Sending new block at BSN 10, CS=MCS-2 -- Chunk with length 260 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4119,6 +4226,7 @@ - Sending new block at BSN 11, CS=MCS-2 -- Chunk with length 232 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4129,6 +4237,7 @@ - Sending new block at BSN 12, CS=MCS-2 -- Chunk with length 204 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4139,6 +4248,7 @@ - Sending new block at BSN 13, CS=MCS-2 -- Chunk with length 176 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4149,6 +4259,7 @@ - Sending new block at BSN 14, CS=MCS-2 -- Chunk with length 148 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4159,6 +4270,7 @@ - Sending new block at BSN 15, CS=MCS-2 -- Chunk with length 120 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4169,6 +4281,7 @@ - Sending new block at BSN 16, CS=MCS-2 -- Chunk with length 92 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4179,6 +4292,7 @@ - Sending new block at BSN 17, CS=MCS-2 -- Chunk with length 64 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4189,6 +4303,7 @@ - Sending new block at BSN 18, CS=MCS-2 -- Chunk with length 36 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4204,6 +4319,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=18 data block (BSN 19, MCS-2): 10 25 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4264,6 +4380,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=25 data block (BSN 0, MCS-3): 14 33 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4277,6 +4394,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4287,6 +4405,7 @@ - Sending new block at BSN 2, CS=MCS-3 -- Chunk with length 475 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4297,6 +4416,7 @@ - Sending new block at BSN 3, CS=MCS-3 -- Chunk with length 438 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4307,6 +4427,7 @@ - Sending new block at BSN 4, CS=MCS-3 -- Chunk with length 401 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4317,6 +4438,7 @@ - Sending new block at BSN 5, CS=MCS-3 -- Chunk with length 364 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4327,6 +4449,7 @@ - Sending new block at BSN 6, CS=MCS-3 -- Chunk with length 327 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4337,6 +4460,7 @@ - Sending new block at BSN 7, CS=MCS-3 -- Chunk with length 290 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4347,6 +4471,7 @@ - Sending new block at BSN 8, CS=MCS-3 -- Chunk with length 253 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4357,6 +4482,7 @@ - Sending new block at BSN 9, CS=MCS-3 -- Chunk with length 216 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4367,6 +4493,7 @@ - Sending new block at BSN 10, CS=MCS-3 -- Chunk with length 179 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4377,6 +4504,7 @@ - Sending new block at BSN 11, CS=MCS-3 -- Chunk with length 142 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4387,6 +4515,7 @@ - Sending new block at BSN 12, CS=MCS-3 -- Chunk with length 105 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4397,6 +4526,7 @@ - Sending new block at BSN 13, CS=MCS-3 -- Chunk with length 68 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4410,6 +4540,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-3): 3f 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4425,6 +4556,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=34 data block (BSN 15, MCS-3): 02 45 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4485,6 +4617,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=32 data block (BSN 0, MCS-4): 14 41 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4498,6 +4631,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4508,6 +4642,7 @@ - Sending new block at BSN 2, CS=MCS-4 -- Chunk with length 468 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4518,6 +4653,7 @@ - Sending new block at BSN 3, CS=MCS-4 -- Chunk with length 424 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4528,6 +4664,7 @@ - Sending new block at BSN 4, CS=MCS-4 -- Chunk with length 380 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4538,6 +4675,7 @@ - Sending new block at BSN 5, CS=MCS-4 -- Chunk with length 336 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4548,6 +4686,7 @@ - Sending new block at BSN 6, CS=MCS-4 -- Chunk with length 292 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4558,6 +4697,7 @@ - Sending new block at BSN 7, CS=MCS-4 -- Chunk with length 248 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4568,6 +4708,7 @@ - Sending new block at BSN 8, CS=MCS-4 -- Chunk with length 204 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4578,6 +4719,7 @@ - Sending new block at BSN 9, CS=MCS-4 -- Chunk with length 160 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4588,6 +4730,7 @@ - Sending new block at BSN 10, CS=MCS-4 -- Chunk with length 116 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4598,6 +4741,7 @@ - Sending new block at BSN 11, CS=MCS-4 -- Chunk with length 72 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4613,6 +4757,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 12, MCS-4): 38 1d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4673,6 +4818,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-5): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4686,6 +4832,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4696,6 +4843,7 @@ - Sending new block at BSN 2, CS=MCS-5 -- Chunk with length 456 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4706,6 +4854,7 @@ - Sending new block at BSN 3, CS=MCS-5 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4716,6 +4865,7 @@ - Sending new block at BSN 4, CS=MCS-5 -- Chunk with length 344 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4726,6 +4876,7 @@ - Sending new block at BSN 5, CS=MCS-5 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4736,6 +4887,7 @@ - Sending new block at BSN 6, CS=MCS-5 -- Chunk with length 232 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4746,6 +4898,7 @@ - Sending new block at BSN 7, CS=MCS-5 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4756,6 +4909,7 @@ - Sending new block at BSN 8, CS=MCS-5 -- Chunk with length 120 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4766,6 +4920,7 @@ - Sending new block at BSN 9, CS=MCS-5 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4781,6 +4936,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-5): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4841,6 +4997,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-6): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4854,6 +5011,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4864,6 +5022,7 @@ - Sending new block at BSN 2, CS=MCS-6 -- Chunk with length 438 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4874,6 +5033,7 @@ - Sending new block at BSN 3, CS=MCS-6 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4884,6 +5044,7 @@ - Sending new block at BSN 4, CS=MCS-6 -- Chunk with length 290 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4894,6 +5055,7 @@ - Sending new block at BSN 5, CS=MCS-6 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4904,6 +5066,7 @@ - Sending new block at BSN 6, CS=MCS-6 -- Chunk with length 142 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4917,6 +5080,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-6): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4932,6 +5096,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-6): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4993,6 +5158,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-7): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5002,12 +5168,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(7) last_mcs(5) demanded_mcs(7) cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-7 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5022,6 +5189,7 @@ - Sending new block at BSN 3, CS=MCS-7 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5036,6 +5204,7 @@ - Sending new block at BSN 5, CS=MCS-7 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5050,6 +5219,7 @@ - Sending new block at BSN 7, CS=MCS-7 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5064,6 +5234,7 @@ - Sending new block at BSN 9, CS=MCS-7 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 9) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5081,6 +5252,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-7): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5142,6 +5314,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=56 data block (BSN 0, MCS-8): 14 71 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5152,12 +5325,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(8) demanded_mcs(8) cs_trans(8) +- initial_cs_dl(8) last_mcs(8) demanded_mcs(8) cs_trans(8) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-8 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5172,6 +5346,7 @@ - Sending new block at BSN 3, CS=MCS-8 -- Chunk with length 376 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5186,6 +5361,7 @@ - Sending new block at BSN 5, CS=MCS-8 -- Chunk with length 240 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5200,6 +5376,7 @@ - Sending new block at BSN 7, CS=MCS-8 -- Chunk with length 104 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5217,6 +5394,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=30 data block (BSN 8, MCS-8): 48 3d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5279,6 +5457,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-9): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5288,12 +5467,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(9) last_mcs(6) demanded_mcs(9) cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-9 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5308,6 +5488,7 @@ - Sending new block at BSN 3, CS=MCS-9 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5322,6 +5503,7 @@ - Sending new block at BSN 5, CS=MCS-9 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5339,6 +5521,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-9): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5356,6 +5539,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-9): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5402,11 +5586,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(6) cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5450,11 +5636,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 96 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(1) demanded_mcs(1) cs_trans(1) +- initial_cs_dl(1) last_mcs(1) demanded_mcs(1) cs_trans(1) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 98 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5498,11 +5686,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-2): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 92 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(2) demanded_mcs(2) cs_trans(2) +- initial_cs_dl(2) last_mcs(2) demanded_mcs(2) cs_trans(2) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 94 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5546,6 +5736,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5557,6 +5748,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-5): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5564,10 +5756,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-5): 0f 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7) cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7) cs_trans(7) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-7): 07 00 00 02 c0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 @@ -5612,6 +5805,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5623,6 +5817,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-6): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5630,10 +5825,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-6): 0f 40 00 00 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9) cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9) cs_trans(9) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-9): 07 00 00 02 28 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 @@ -5686,6 +5882,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-7): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5694,13 +5891,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-7): 0f 00 00 02 a0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5) cs_trans(5) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5) cs_trans(5) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-5): 07 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5752,6 +5951,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-9): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5760,13 +5960,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-9): 0f 00 00 02 00 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6) cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6) cs_trans(6) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-6): 07 40 00 02 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5780,3 +5982,233 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-5 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(2) cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 d2 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(2) demanded_mcs(2) cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 f2 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-4 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (44) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-4): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-4): 07 00 00 80 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(4) demanded_mcs(1) cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 d6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(1) demanded_mcs(1) cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 f6 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(6) cs_trans(6) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 2 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..c38417d 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,9 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_egprs_spb_dl === +Testing retx for MCS 6 to reseg_mcs 3 +Testing retx for MCS 5 to reseg_mcs 2 +Testing retx for MCS 4 to reseg_mcs 1 +Testing retx for MCS 6 to reseg_mcs 3 +=== end test_tbf_egprs_spb_dl === -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 16 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Wed Aug 17 13:24:58 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Wed, 17 Aug 2016 13:24:58 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 16: (1 comment) https://gerrit.osmocom.org/#/c/655/16/src/pcu_vty.c File src/pcu_vty.c: Line 497: bts->arq_type = 1; Modify here -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 16 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Wed Aug 17 13:26:20 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Wed, 17 Aug 2016 13:26:20 +0000 Subject: [PATCH] osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/655 to look at the new patch set (#17). Modify EGPRS DL TBF flow to support SPB Modify the EGPRS DL TBF flow to support Split block during Retx. This patch will also Upgrade the test suite with test cases to validate the EGPRS Downlink SPB for Retransmission Scenarios like MCS6->MCS3, MCS4->MCS1, MCS5->MCS2, MCS9->MCS3 MCS7->MCS2, MCS8->MCS3 have been simulated and Integration tested in NuRAN 1.0 hardware thoroughly. Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 --- M src/gprs_coding_scheme.h M src/pcu_main.cpp M src/pcu_vty.c M src/rlc.cpp M src/rlc.h M src/tbf.h M src/tbf_dl.cpp M tests/edge/EdgeTest.cpp M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 11 files changed, 956 insertions(+), 80 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/55/655/17 diff --git a/src/gprs_coding_scheme.h b/src/gprs_coding_scheme.h index 60a8e79..3b15372 100644 --- a/src/gprs_coding_scheme.h +++ b/src/gprs_coding_scheme.h @@ -113,7 +113,8 @@ static const char *modeName(Mode mode); static Scheme get_retx_mcs(const GprsCodingScheme mcs, - const GprsCodingScheme retx_mcs); + const GprsCodingScheme retx_mcs, + const unsigned arq_type); static enum Scheme egprs_mcs_retx_tbl[MAX_NUM_ARQ] [MAX_NUM_MCS][MAX_NUM_MCS]; @@ -232,8 +233,9 @@ } inline GprsCodingScheme::Scheme GprsCodingScheme::get_retx_mcs( const GprsCodingScheme mcs, - const GprsCodingScheme demanded_mcs) + const GprsCodingScheme demanded_mcs, + const unsigned arq_type) { - return egprs_mcs_retx_tbl[EGPRS_ARQ2][mcs.to_num() - 1] + return egprs_mcs_retx_tbl[arq_type][mcs.to_num() - 1] [demanded_mcs.to_num() - 1]; } diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2d86cda..e34d534 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -210,6 +210,12 @@ bts->dl_tbf_idle_msec = 2000; bts->llc_idle_ack_csec = 10; + /* + * By default resegmentation is supported in DL + * can also be configured through VTY + */ + bts->dl_arq_type = EGPRS_ARQ1; + msgb_set_talloc_ctx(tall_pcu_ctx); osmo_init_logging(&gprs_log_info); diff --git a/src/pcu_vty.c b/src/pcu_vty.c index 58fea99..9898a86 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -129,6 +129,10 @@ vty_out(vty, " window-size %d %d%s", bts->ws_base, bts->ws_pdch, VTY_NEWLINE); + if (bts->dl_arq_type) + vty_out(vty, " dl arq-type %d%s", bts->dl_arq_type, + VTY_NEWLINE); + if (bts->force_llc_lifetime == 0xffff) vty_out(vty, " queue lifetime infinite%s", VTY_NEWLINE); else if (bts->force_llc_lifetime) @@ -476,6 +480,23 @@ bts->max_mcs_dl = 0; bts->max_mcs_ul = 0; + + return CMD_SUCCESS; +} + +DEFUN(cfg_pcu_dl_arq_type, + cfg_pcu_dl_arq_cmd, + "dl arq-type (spb|arq2)", + EGPRS_STR "DL ARQ options\n" + "enable DL SPB(ARQ1) support\n" + "enable DL ARQ2 support") +{ + struct gprs_rlcmac_bts *bts = bts_main_data(); + + if (!strcmp(argv[0], "arq2")) + bts->dl_arq_type = 1; + else + bts->dl_arq_type = 0; return CMD_SUCCESS; } @@ -954,6 +975,7 @@ install_element(PCU_NODE, &cfg_pcu_no_cs_downgrade_thrsh_cmd); install_element(PCU_NODE, &cfg_pcu_cs_lqual_ranges_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_cmd); + install_element(PCU_NODE, &cfg_pcu_dl_arq_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_max_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_max_cmd); diff --git a/src/rlc.cpp b/src/rlc.cpp index 6770043..e69d1fc 100644 --- a/src/rlc.cpp +++ b/src/rlc.cpp @@ -285,7 +285,8 @@ } static void gprs_rlc_data_header_init(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding, unsigned int header_bits) + GprsCodingScheme cs, bool with_padding, unsigned int header_bits, + const unsigned int spb) { unsigned int i; unsigned int padding_bits = with_padding ? cs.optionalPaddingBits() : 0; @@ -300,7 +301,7 @@ for (i = 0; i < rlc->num_data_blocks; i++) { gprs_rlc_data_block_info_init(&rlc->block_info[i], cs, - with_padding); + with_padding, spb); rlc->data_offs_bits[i] = header_bits + padding_bits + @@ -310,21 +311,25 @@ } void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsDL()); + cs.numDataHeaderBitsDL(), spb); } void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding) { + /* + * last parameter is sent as 0 since common function used + * for both DL and UL + */ return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsUL()); + cs.numDataHeaderBitsUL(), 0); } void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { unsigned int data_len = cs.maxDataBlockBytes(); if (with_padding) @@ -336,7 +341,7 @@ rdbi->e = 1; rdbi->cv = 15; rdbi->pi = 0; - rdbi->spb = 0; + rdbi->spb = spb; } unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, @@ -411,8 +416,18 @@ enum egprs_puncturing_values gprs_get_punct_scheme( enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current) + const GprsCodingScheme &cs_current, + const enum egprs_rlcmac_dl_spb spb) { + + /* + * 10.4.8b of TS 44.060 + * If it is second segment of the block + * dont change the puncturing scheme + */ + if (spb == EGPRS_RLCMAC_DL_SEC_SEG) + return punct; + /* TS 44.060 9.3.2.1.1 */ if ((GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS9) && (GprsCodingScheme::Scheme(cs_current) == GprsCodingScheme::MCS6)) { diff --git a/src/rlc.h b/src/rlc.h index b1a1fba..b693418 100644 --- a/src/rlc.h +++ b/src/rlc.h @@ -213,18 +213,19 @@ }; void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding); void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, enum egprs_puncturing_values punct, enum egprs_puncturing_values punct2, int with_padding); void gprs_rlc_mcs_cps_decode(unsigned int cps, GprsCodingScheme cs, int *punct, int *punct2, int *with_padding); enum egprs_puncturing_values gprs_get_punct_scheme(enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current_trans); + const GprsCodingScheme &cs_current_trans, + const enum egprs_rlcmac_dl_spb spb); void gprs_update_punct_scheme(enum egprs_puncturing_values *punct, const GprsCodingScheme &cs); /* diff --git a/src/tbf.h b/src/tbf.h index 1bd7878..2a1bfe8 100644 --- a/src/tbf.h +++ b/src/tbf.h @@ -421,6 +421,11 @@ int analyse_errors(char *show_rbb, uint8_t ssn, ana_result *res); void schedule_next_frame(); + enum egprs_rlc_dl_reseg_bsn_state egprs_dl_get_data + (int bsn, uint8_t **block_data); + unsigned int get_egprs_dl_spb_status(int bsn); + enum egprs_rlcmac_dl_spb get_egprs_dl_spb(int bsn); + struct osmo_timer_list m_llc_timer; }; diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp index 07a747a..a24cc21 100644 --- a/src/tbf_dl.cpp +++ b/src/tbf_dl.cpp @@ -375,21 +375,28 @@ return -1; if (is_egprs_enabled()) { + /* Table 8.1.1.2 and Table 8.1.1.1 of 44.060 */ m_rlc.block(bsn)->cs_current_trans = - GprsCodingScheme::get_retx_mcs( - m_rlc.block(bsn)->cs_last, ms()->current_cs_dl()); + GprsCodingScheme::get_retx_mcs( + m_rlc.block(bsn)->cs_init, + ms()->current_cs_dl(), + bts->bts_data()->dl_arq_type); LOGP(DRLCMACDL, LOGL_DEBUG, - "- current_cs_dl(%d) demanded_mcs(%d) cs_trans(%d)\n", - m_rlc.block(bsn)->cs_last.to_num(), - ms()->current_cs_dl().to_num(), - m_rlc.block(bsn)->cs_current_trans.to_num()); + "- initial_cs_dl(%d) last_mcs(%d)" + " demanded_mcs(%d) cs_trans(%d)" + " arq_type(%d) bsn(%d)\n", + m_rlc.block(bsn)->cs_init.to_num(), + m_rlc.block(bsn)->cs_last.to_num(), + ms()->current_cs_dl().to_num(), + m_rlc.block(bsn)->cs_current_trans.to_num(), + bts->bts_data()->dl_arq_type, bsn); /* TODO: Need to remove this check when MCS-8 -> MCS-6 * transistion is handled. * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 */ - if (m_rlc.block(bsn)->cs_last == GprsCodingScheme::MCS8) + if (m_rlc.block(bsn)->cs_init == GprsCodingScheme::MCS8) m_rlc.block(bsn)->cs_current_trans = GprsCodingScheme::MCS8; } else @@ -523,6 +530,11 @@ data = rlc_data->prepare(block_data_len); rlc_data->cs_last = cs; rlc_data->cs_current_trans = cs; + + /* Initialise the variable related to DL SPB */ + rlc_data->spb_status.block_status_dl = EGPRS_RESEG_DL_DEFAULT; + rlc_data->cs_init = cs; + rlc_data->len = block_data_len; rdbi = &(rlc_data->block_info); @@ -616,7 +628,8 @@ unsigned num_bsns; enum egprs_puncturing_values punct[ARRAY_SIZE(rlc.block_info)]; bool need_padding = false; - + enum egprs_rlcmac_dl_spb spb = EGPRS_RLCMAC_DL_NO_RETX; + unsigned int spb_status = get_egprs_dl_spb_status(index); /* * TODO: This is an experimental work-around to put 2 BSN into * MSC-7 to MCS-9 encoded messages. It just sends the same BSN @@ -626,6 +639,7 @@ * the current limit. */ cs = m_rlc.block(index)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(index)->cs_init; bsns[0] = index; num_bsns = 1; @@ -634,7 +648,17 @@ num_bsns += 1; } - if (num_bsns == 1) { + /* + * if the intial mcs is 8 and retransmission mcs is either 6 or 3 + * we have to include the padding of 6 octets in first segment + */ + if ((GprsCodingScheme::Scheme(cs_init) == GprsCodingScheme::MCS8) && + (GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS6 || + GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS3)) { + if (spb_status == EGPRS_RESEG_DL_DEFAULT || + spb_status == EGPRS_RESEG_SECOND_SEG_SENT) + need_padding = true; + } else if (num_bsns == 1) { /* TODO: remove the conditional when MCS-6 padding isn't * failing to be decoded by MEs anymore */ /* TODO: support of MCS-8 -> MCS-6 transition should be @@ -646,7 +670,14 @@ cs.decToSingleBlock(&need_padding); } - gprs_rlc_data_info_init_dl(&rlc, cs, need_padding); + spb = get_egprs_dl_spb(index); + + LOGP(DRLCMACDL, LOGL_DEBUG, "- need_padding %d spb_status %d spb %d" + "(BSN1 %d BSN2 %d)\n", + need_padding, + spb_status, spb, index, index2); + + gprs_rlc_data_info_init_dl(&rlc, cs, need_padding, spb); rlc.usf = 7; /* will be set at scheduler */ rlc.pr = 0; /* FIXME: power reduction */ @@ -665,10 +696,9 @@ data_block_idx++) { int bsn; - GprsCodingScheme cs_enc; uint8_t *block_data; gprs_rlc_data_block_info *rdbi, *block_info; - enum egprs_puncturing_values punct_scheme; + enum egprs_rlc_dl_reseg_bsn_state reseg_status; /* Check if there are more blocks than BSNs */ if (data_block_idx < num_bsns) @@ -676,38 +706,43 @@ else bsn = bsns[0]; - cs_enc = m_rlc.block(bsn)->cs_current_trans; - /* get data and header from current block */ - block_data = m_rlc.block(bsn)->block; - /* Get current puncturing scheme from block */ - punct_scheme = gprs_get_punct_scheme( + + m_rlc.block(bsn)->next_ps = gprs_get_punct_scheme( m_rlc.block(bsn)->next_ps, - m_rlc.block(bsn)->cs_last, cs); + m_rlc.block(bsn)->cs_last, cs, spb); if (cs.isEgprs()) { - OSMO_ASSERT(punct_scheme >= EGPRS_PS_1); - OSMO_ASSERT(punct_scheme <= EGPRS_PS_3); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps >= EGPRS_PS_1); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps <= EGPRS_PS_3); } - punct[data_block_idx] = punct_scheme; + punct[data_block_idx] = m_rlc.block(bsn)->next_ps; rdbi = &rlc.block_info[data_block_idx]; block_info = &m_rlc.block(bsn)->block_info; - if(rdbi->data_len != m_rlc.block(bsn)->len) { - LOGP(DRLCMACDL, LOGL_ERROR, - "ERROR: Expected len = %d for %s instead of " - "%d in data unit %d (BSN %d, %s)\n", - rdbi->data_len, cs.name(), m_rlc.block(bsn)->len, - data_block_idx, bsn, cs_enc.name()); - OSMO_ASSERT(rdbi->data_len == m_rlc.block(bsn)->len); - } - - /* TODO: Need to handle 2 same bsns - * in header type 1 + /* + * get data and header from current block + * function returns the reseg status */ - gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, - cs); + reseg_status = egprs_dl_get_data(bsn, &block_data); + m_rlc.block(bsn)->spb_status.block_status_dl = reseg_status; + + /* + * If it is first segment of the split block set the state of + * bsn to nacked. If it is the first segment dont update the + * next ps value of bsn. since next segment also needs same cps + */ + if (spb == EGPRS_RLCMAC_DL_FIRST_SEG) + m_window.m_v_b.mark_nacked(bsn); + else { + /* + * TODO: Need to handle 2 same bsns + * in header type 1 + */ + gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, + cs); + } m_rlc.block(bsn)->cs_last = cs; rdbi->e = block_info->e; @@ -1169,3 +1204,118 @@ keep_time_frames = msecs_to_frames(bts_data()->dl_tbf_idle_msec); return frames_since_last_drain(fn) <= keep_time_frames; } + +/* + * This function returns the pointer to data which needs + * to be copied. Also updates the status of the block related to + * Split block handling in the RLC/MAC block. + */ +enum egprs_rlc_dl_reseg_bsn_state + gprs_rlcmac_dl_tbf::egprs_dl_get_data(int bsn, uint8_t **block_data) +{ + gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state *block_status_dl = + &rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + *block_data = &rlc_data->block[0]; + + /* + * Table 10.3a.0.1 of 44.060 + * MCS6,9: second segment starts at 74/2 = 37 + * MCS5,7: second segment starts at 56/2 = 28 + * MCS8: second segment starts at 31 + * MCS4: second segment starts at 44/2 = 22 + */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + if (*block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + switch (GprsCodingScheme::Scheme(cs_init)) { + case GprsCodingScheme::MCS6 : + case GprsCodingScheme::MCS9 : + *block_data = &rlc_data->block[37]; + break; + case GprsCodingScheme::MCS7 : + case GprsCodingScheme::MCS5 : + *block_data = &rlc_data->block[28]; + break; + case GprsCodingScheme::MCS8 : + *block_data = &rlc_data->block[31]; + break; + case GprsCodingScheme::MCS4 : + *block_data = &rlc_data->block[22]; + break; + default: + LOGP(DRLCMACDL, LOGL_ERROR, "Software error: " + "--%s hit invalid condition. headerType(%d) " + " blockstatus(%d) cs(%s) PLEASE FIX!\n", name(), + cs_current_trans.headerTypeData(), + *block_status_dl, cs_init.name()); + break; + + } + return EGPRS_RESEG_SECOND_SEG_SENT; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } + } + return EGPRS_RESEG_DL_DEFAULT; +} + +/* + * This function returns the status of split block + * for RLC/MAC block. + */ +unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_status(const int bsn) +{ + const gprs_rlc_data *rlc_data = m_rlc.block(bsn); + + return rlc_data->spb_status.block_status_dl; +} + +/* + * This function returns the spb value to be sent OTA + * for RLC/MAC block. + */ +enum egprs_rlcmac_dl_spb gprs_rlcmac_dl_tbf::get_egprs_dl_spb(const int bsn) +{ + struct gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state block_status_dl = + rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + + /* Table 10.4.8b.1 of 44.060 */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + /* + * if we are sending the second segment the spb should be 3 + * other wise it should be 2 + */ + if (block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + return EGPRS_RLCMAC_DL_SEC_SEG; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RLCMAC_DL_FIRST_SEG; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RLCMAC_DL_FIRST_SEG; + } + } + /* Non SPB cases 0 is reurned */ + return EGPRS_RLCMAC_DL_NO_RETX; +} diff --git a/tests/edge/EdgeTest.cpp b/tests/edge/EdgeTest.cpp index 807102c..9081d4d 100644 --- a/tests/edge/EdgeTest.cpp +++ b/tests/edge/EdgeTest.cpp @@ -517,7 +517,7 @@ /* TS 44.060, B.1 */ cs = GprsCodingScheme::CS4; - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -570,7 +570,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -592,7 +592,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -630,7 +630,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -669,7 +669,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -694,7 +694,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -719,7 +719,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -740,7 +740,7 @@ OSMO_ASSERT(data[0] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -777,7 +777,7 @@ cs = GprsCodingScheme::MCS4; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -835,7 +835,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -872,7 +872,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -923,7 +923,7 @@ OSMO_ASSERT(data[3] == 0); /* Block 3 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -967,7 +967,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -993,7 +993,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1020,7 +1020,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1074,7 +1074,7 @@ block_idx++) { struct gprs_rlc_data_info rlc; - gprs_rlc_data_info_init_dl(&rlc, cs, false); + gprs_rlc_data_info_init_dl(&rlc, cs, false, 0); memset(bits, pattern, sizeof(bits)); Decoding::rlc_copy_to_aligned_buffer( @@ -1118,12 +1118,14 @@ struct gprs_rlc_data_info rlc; printf("=== start %s ===\n", __func__); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::CS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::CS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 24); OSMO_ASSERT(rlc.block_info[0].data_len == 20); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::MCS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::MCS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 33); OSMO_ASSERT(rlc.block_info[0].data_len == 22); diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..5e45506 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -1814,6 +1814,203 @@ } +static void egprs_spb_to_normal_validation(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + uint16_t bsn1, bsn2, bsn3; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + struct gprs_rlc_dl_header_egprs_2 *egprs2; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + if (!(mcs == 6 && demanded_mcs == 3)) + return; + + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + bsn1 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) + || (egprs2->bsn1_lo); + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(bsn1 == 0); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + bsn2 = (egprs3->bsn1_hi << 9) || (egprs3->bsn1_mid << 1) || + (egprs3->bsn1_lo); + OSMO_ASSERT(bsn2 == bsn1); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Handle (MCS3, MCS3) -> MCS6 case */ + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + mcs)); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs2->cps == 0); + bsn3 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) || + (egprs2->bsn1_lo); + OSMO_ASSERT(bsn3 == bsn2); + + tbf_cleanup(dl_tbf); +} +static void establish_and_use_egprs_dl_tbf_for_spb(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + /* TODO: Need to support of MCS8 -> MCS6 ->MCS3 transistion + * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 + * dated 2016-02-07 23:45:40 (UTC) + */ + if (!(((mcs == 5) && (demanded_mcs == 2)) || + ((mcs == 6) && (demanded_mcs == 3)) || + ((mcs == 4) && (demanded_mcs == 1)))) + return; + + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + tbf_cleanup(dl_tbf); +} + static void establish_and_use_egprs_dl_tbf_for_retx(BTS *the_bts, int mcs, int demanded_mcs) { @@ -1972,6 +2169,9 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; + /* First parameter is current MCS, second one is demanded_mcs */ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 6); @@ -1981,6 +2181,38 @@ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 9); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 7, 5); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 9, 6); + + printf("=== end %s ===\n", __func__); +} + +static void test_tbf_egprs_spb_dl(void) +{ + BTS the_bts; + gprs_rlcmac_bts *bts; + uint8_t ts_no = 4; + int i, j; + + printf("=== start %s ===\n", __func__); + + bts = the_bts.bts_data(); + bts->cs_downgrade_threshold = 0; + setup_bts(&the_bts, ts_no); + bts->dl_tbf_idle_msec = 200; + bts->egprs_enabled = 1; + + /* ARQ I resegmentation support */ + bts->dl_arq_type = EGPRS_ARQ1; + + /* + * First parameter is current MCS, second one is demanded_mcs + * currently only MCS5->MCS2, MCS6->3, MCS4->MCS1 is tested in UT + * rest scenarios has been integration tested + */ + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 6, 3); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 5, 2); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 4, 1); + /* check MCS6->(MCS3+MCS3)->MCS6 case */ + egprs_spb_to_normal_validation(&the_bts, 6, 3); printf("=== end %s ===\n", __func__); } @@ -1999,6 +2231,8 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; for (i = 1; i <= 9; i++) establish_and_use_egprs_dl_tbf(&the_bts, i); @@ -2071,6 +2305,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_egprs_spb_dl(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..1ba4189 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -72,6 +72,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -81,6 +82,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -157,6 +159,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -166,6 +169,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -242,6 +246,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -251,6 +256,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -259,6 +265,7 @@ - Sending new block at BSN 2, CS=CS-1 -- Chunk with length 160 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=13 block=3 data=07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b @@ -267,6 +274,7 @@ - Sending new block at BSN 3, CS=CS-1 -- Chunk with length 140 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=17 block=4 data=07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @@ -275,6 +283,7 @@ - Sending new block at BSN 4, CS=CS-1 -- Chunk with length 120 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=21 block=5 data=07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 @@ -283,6 +292,7 @@ - Sending new block at BSN 5, CS=CS-1 -- Chunk with length 100 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=26 block=6 data=07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 @@ -291,6 +301,7 @@ - Sending new block at BSN 6, CS=CS-1 -- Chunk with length 80 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=30 block=7 data=07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b @@ -299,6 +310,7 @@ - Sending new block at BSN 7, CS=CS-1 -- Chunk with length 60 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=34 block=8 data=07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f @@ -307,6 +319,7 @@ - Sending new block at BSN 8, CS=CS-1 -- Chunk with length 40 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=39 block=9 data=07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 @@ -315,6 +328,7 @@ - Sending new block at BSN 9, CS=CS-1 -- Chunk with length 20 would exactly fit into space (20): add length header with LI=0, to make frame extend to next block, and we are done data block (BSN 9, CS-1): 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=43 block=10 data=07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 @@ -326,6 +340,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=47 block=11 data=07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 @@ -334,6 +349,7 @@ - Sending new block at BSN 11, CS=CS-1 -- Chunk with length 182 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=52 block=0 data=07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 @@ -342,6 +358,7 @@ - Sending new block at BSN 12, CS=CS-1 -- Chunk with length 162 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=56 block=1 data=07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 @@ -350,6 +367,7 @@ - Sending new block at BSN 13, CS=CS-1 -- Chunk with length 142 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 13, CS-1): 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=60 block=2 data=07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d @@ -358,6 +376,7 @@ - Sending new block at BSN 14, CS=CS-1 -- Chunk with length 122 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=65 block=3 data=07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 @@ -366,6 +385,7 @@ - Sending new block at BSN 15, CS=CS-1 -- Chunk with length 102 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=69 block=4 data=07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 @@ -374,6 +394,7 @@ - Sending new block at BSN 16, CS=CS-1 -- Chunk with length 82 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=73 block=5 data=07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 @@ -382,6 +403,7 @@ - Sending new block at BSN 17, CS=CS-1 -- Chunk with length 62 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=78 block=6 data=07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d @@ -390,6 +412,7 @@ - Sending new block at BSN 18, CS=CS-1 -- Chunk with length 42 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=82 block=7 data=07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 @@ -398,6 +421,7 @@ - Sending new block at BSN 19, CS=CS-1 -- Chunk with length 22 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=86 block=8 data=07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 @@ -411,6 +435,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=16 data block (BSN 20, CS-1): 0a 41 c6 c7 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -449,6 +474,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 data block (BSN 21, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -468,6 +494,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 22, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FINISHED) @@ -1481,6 +1508,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 0, CS-1): 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 MSG = 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 @@ -1491,6 +1519,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 1, CS-1): 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 MSG = 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 @@ -1501,6 +1530,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FINISHED data block (BSN 2, CS-1): 4d 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling cannot be scheduled in this TS 7 (first control TS 4) @@ -1784,6 +1814,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=10 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 0, CS-4): 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654292 TS 7 @@ -1797,6 +1828,7 @@ TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) downlink (V(A)==0 .. V(S)==1) - Restarting at BSN 0, because all blocks have been transmitted. - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-4): 07 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 @@ -2365,6 +2397,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654279 block=10 data=00 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 @@ -2384,6 +2417,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -2406,6 +2440,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654288 block=0 data=00 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 @@ -2425,6 +2460,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654292 block=1 data=00 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2447,6 +2483,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654296 block=2 data=00 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c @@ -2466,6 +2503,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654301 block=3 data=00 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b @@ -2488,6 +2526,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 6, CS-1): 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654305 block=4 data=00 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 @@ -2507,6 +2546,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654309 block=5 data=00 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 @@ -2526,6 +2566,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654314 block=6 data=00 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 @@ -2548,6 +2589,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654318 block=7 data=00 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 @@ -2567,6 +2609,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654322 block=8 data=00 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2589,6 +2632,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654327 block=9 data=00 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c @@ -2608,6 +2652,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654331 block=10 data=00 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b @@ -2630,6 +2675,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 13, CS-1): 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654335 block=11 data=00 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 @@ -2649,6 +2695,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654340 block=0 data=00 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 @@ -2668,6 +2715,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654344 block=1 data=00 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 @@ -2690,6 +2738,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654348 block=2 data=00 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 @@ -2709,6 +2758,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654353 block=3 data=00 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2731,6 +2781,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654357 block=4 data=00 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c @@ -2750,6 +2801,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654361 block=5 data=00 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b @@ -2772,6 +2824,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 20, CS-1): 16 35 45 54 20 32 38 4c 4c 43 20 50 41 43 4b 45 54 20 32 39 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because 20 blocks sent. TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW): Scheduling polling at FN 2654379 TS 7 @@ -2795,6 +2848,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 21, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) msg block (BSN 21, CS-1): 07 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654370 block=7 data=00 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 @@ -2814,6 +2868,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 22, CS-1): 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) msg block (BSN 22, CS-1): 07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654374 block=8 data=07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 @@ -2836,6 +2891,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 23, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) msg block (BSN 23, CS-1): 07 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654379 block=9 data=00 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 @@ -2855,6 +2911,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 24, CS-1): 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) msg block (BSN 24, CS-1): 07 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654383 block=10 data=00 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2877,6 +2934,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 25, CS-1): 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 25 BSN2 -1) - Copying data unit 0 (BSN 25) msg block (BSN 25, CS-1): 07 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654387 block=11 data=00 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c @@ -2896,6 +2954,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 26, CS-1): 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 26 BSN2 -1) - Copying data unit 0 (BSN 26) msg block (BSN 26, CS-1): 07 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654392 block=0 data=00 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b @@ -2918,6 +2977,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 27, CS-1): 16 35 45 54 20 33 38 4c 4c 43 20 50 41 43 4b 45 54 20 33 39 +- need_padding 0 spb_status 0 spb 0(BSN1 27 BSN2 -1) - Copying data unit 0 (BSN 27) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) @@ -3028,6 +3088,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654405 block=3 data=00 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 @@ -3047,6 +3108,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654409 block=4 data=00 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 @@ -3066,6 +3128,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (16) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654413 block=5 data=00 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 @@ -3085,6 +3148,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (14) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654418 block=6 data=00 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 @@ -3104,6 +3168,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654422 block=7 data=00 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -3123,6 +3188,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654426 block=8 data=00 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 @@ -3142,6 +3208,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654431 block=9 data=00 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b @@ -3161,6 +3228,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654435 block=10 data=00 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 @@ -3180,6 +3248,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654439 block=11 data=00 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 @@ -3199,6 +3268,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654444 block=0 data=00 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c @@ -3218,6 +3288,7 @@ Complete DL frame for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=21 TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 10, CS-1): 4d 43 20 50 41 43 4b 45 54 20 30 39 20 28 54 42 46 20 32 29 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654461 TS 7 @@ -3698,6 +3769,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 0, MCS-1): 14 15 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3711,6 +3783,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3721,6 +3794,7 @@ - Sending new block at BSN 2, CS=MCS-1 -- Chunk with length 490 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3731,6 +3805,7 @@ - Sending new block at BSN 3, CS=MCS-1 -- Chunk with length 468 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3741,6 +3816,7 @@ - Sending new block at BSN 4, CS=MCS-1 -- Chunk with length 446 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3751,6 +3827,7 @@ - Sending new block at BSN 5, CS=MCS-1 -- Chunk with length 424 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3761,6 +3838,7 @@ - Sending new block at BSN 6, CS=MCS-1 -- Chunk with length 402 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3771,6 +3849,7 @@ - Sending new block at BSN 7, CS=MCS-1 -- Chunk with length 380 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3781,6 +3860,7 @@ - Sending new block at BSN 8, CS=MCS-1 -- Chunk with length 358 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3791,6 +3871,7 @@ - Sending new block at BSN 9, CS=MCS-1 -- Chunk with length 336 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3801,6 +3882,7 @@ - Sending new block at BSN 10, CS=MCS-1 -- Chunk with length 314 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3811,6 +3893,7 @@ - Sending new block at BSN 11, CS=MCS-1 -- Chunk with length 292 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3821,6 +3904,7 @@ - Sending new block at BSN 12, CS=MCS-1 -- Chunk with length 270 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3831,6 +3915,7 @@ - Sending new block at BSN 13, CS=MCS-1 -- Chunk with length 248 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3841,6 +3926,7 @@ - Sending new block at BSN 14, CS=MCS-1 -- Chunk with length 226 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3851,6 +3937,7 @@ - Sending new block at BSN 15, CS=MCS-1 -- Chunk with length 204 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3861,6 +3948,7 @@ - Sending new block at BSN 16, CS=MCS-1 -- Chunk with length 182 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3871,6 +3959,7 @@ - Sending new block at BSN 17, CS=MCS-1 -- Chunk with length 160 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3881,6 +3970,7 @@ - Sending new block at BSN 18, CS=MCS-1 -- Chunk with length 138 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3891,6 +3981,7 @@ - Sending new block at BSN 19, CS=MCS-1 -- Chunk with length 116 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 19, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3901,6 +3992,7 @@ - Sending new block at BSN 20, CS=MCS-1 -- Chunk with length 94 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 20, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3911,6 +4003,7 @@ - Sending new block at BSN 21, CS=MCS-1 -- Chunk with length 72 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 21, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3921,6 +4014,7 @@ - Sending new block at BSN 22, CS=MCS-1 -- Chunk with length 50 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 22, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3931,6 +4025,7 @@ - Sending new block at BSN 23, CS=MCS-1 -- Chunk with length 28 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 23, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3946,6 +4041,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 24, MCS-1): 0c 1d 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4006,6 +4102,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=16 data block (BSN 0, MCS-2): 14 21 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4019,6 +4116,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4029,6 +4127,7 @@ - Sending new block at BSN 2, CS=MCS-2 -- Chunk with length 484 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4039,6 +4138,7 @@ - Sending new block at BSN 3, CS=MCS-2 -- Chunk with length 456 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4049,6 +4149,7 @@ - Sending new block at BSN 4, CS=MCS-2 -- Chunk with length 428 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4059,6 +4160,7 @@ - Sending new block at BSN 5, CS=MCS-2 -- Chunk with length 400 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4069,6 +4171,7 @@ - Sending new block at BSN 6, CS=MCS-2 -- Chunk with length 372 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4079,6 +4182,7 @@ - Sending new block at BSN 7, CS=MCS-2 -- Chunk with length 344 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4089,6 +4193,7 @@ - Sending new block at BSN 8, CS=MCS-2 -- Chunk with length 316 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4099,6 +4204,7 @@ - Sending new block at BSN 9, CS=MCS-2 -- Chunk with length 288 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4109,6 +4215,7 @@ - Sending new block at BSN 10, CS=MCS-2 -- Chunk with length 260 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4119,6 +4226,7 @@ - Sending new block at BSN 11, CS=MCS-2 -- Chunk with length 232 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4129,6 +4237,7 @@ - Sending new block at BSN 12, CS=MCS-2 -- Chunk with length 204 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4139,6 +4248,7 @@ - Sending new block at BSN 13, CS=MCS-2 -- Chunk with length 176 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4149,6 +4259,7 @@ - Sending new block at BSN 14, CS=MCS-2 -- Chunk with length 148 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4159,6 +4270,7 @@ - Sending new block at BSN 15, CS=MCS-2 -- Chunk with length 120 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4169,6 +4281,7 @@ - Sending new block at BSN 16, CS=MCS-2 -- Chunk with length 92 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4179,6 +4292,7 @@ - Sending new block at BSN 17, CS=MCS-2 -- Chunk with length 64 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4189,6 +4303,7 @@ - Sending new block at BSN 18, CS=MCS-2 -- Chunk with length 36 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4204,6 +4319,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=18 data block (BSN 19, MCS-2): 10 25 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4264,6 +4380,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=25 data block (BSN 0, MCS-3): 14 33 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4277,6 +4394,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4287,6 +4405,7 @@ - Sending new block at BSN 2, CS=MCS-3 -- Chunk with length 475 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4297,6 +4416,7 @@ - Sending new block at BSN 3, CS=MCS-3 -- Chunk with length 438 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4307,6 +4427,7 @@ - Sending new block at BSN 4, CS=MCS-3 -- Chunk with length 401 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4317,6 +4438,7 @@ - Sending new block at BSN 5, CS=MCS-3 -- Chunk with length 364 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4327,6 +4449,7 @@ - Sending new block at BSN 6, CS=MCS-3 -- Chunk with length 327 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4337,6 +4460,7 @@ - Sending new block at BSN 7, CS=MCS-3 -- Chunk with length 290 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4347,6 +4471,7 @@ - Sending new block at BSN 8, CS=MCS-3 -- Chunk with length 253 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4357,6 +4482,7 @@ - Sending new block at BSN 9, CS=MCS-3 -- Chunk with length 216 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4367,6 +4493,7 @@ - Sending new block at BSN 10, CS=MCS-3 -- Chunk with length 179 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4377,6 +4504,7 @@ - Sending new block at BSN 11, CS=MCS-3 -- Chunk with length 142 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4387,6 +4515,7 @@ - Sending new block at BSN 12, CS=MCS-3 -- Chunk with length 105 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4397,6 +4526,7 @@ - Sending new block at BSN 13, CS=MCS-3 -- Chunk with length 68 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4410,6 +4540,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-3): 3f 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4425,6 +4556,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=34 data block (BSN 15, MCS-3): 02 45 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4485,6 +4617,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=32 data block (BSN 0, MCS-4): 14 41 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4498,6 +4631,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4508,6 +4642,7 @@ - Sending new block at BSN 2, CS=MCS-4 -- Chunk with length 468 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4518,6 +4653,7 @@ - Sending new block at BSN 3, CS=MCS-4 -- Chunk with length 424 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4528,6 +4664,7 @@ - Sending new block at BSN 4, CS=MCS-4 -- Chunk with length 380 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4538,6 +4675,7 @@ - Sending new block at BSN 5, CS=MCS-4 -- Chunk with length 336 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4548,6 +4686,7 @@ - Sending new block at BSN 6, CS=MCS-4 -- Chunk with length 292 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4558,6 +4697,7 @@ - Sending new block at BSN 7, CS=MCS-4 -- Chunk with length 248 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4568,6 +4708,7 @@ - Sending new block at BSN 8, CS=MCS-4 -- Chunk with length 204 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4578,6 +4719,7 @@ - Sending new block at BSN 9, CS=MCS-4 -- Chunk with length 160 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4588,6 +4730,7 @@ - Sending new block at BSN 10, CS=MCS-4 -- Chunk with length 116 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4598,6 +4741,7 @@ - Sending new block at BSN 11, CS=MCS-4 -- Chunk with length 72 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4613,6 +4757,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 12, MCS-4): 38 1d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4673,6 +4818,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-5): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4686,6 +4832,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4696,6 +4843,7 @@ - Sending new block at BSN 2, CS=MCS-5 -- Chunk with length 456 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4706,6 +4854,7 @@ - Sending new block at BSN 3, CS=MCS-5 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4716,6 +4865,7 @@ - Sending new block at BSN 4, CS=MCS-5 -- Chunk with length 344 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4726,6 +4876,7 @@ - Sending new block at BSN 5, CS=MCS-5 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4736,6 +4887,7 @@ - Sending new block at BSN 6, CS=MCS-5 -- Chunk with length 232 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4746,6 +4898,7 @@ - Sending new block at BSN 7, CS=MCS-5 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4756,6 +4909,7 @@ - Sending new block at BSN 8, CS=MCS-5 -- Chunk with length 120 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4766,6 +4920,7 @@ - Sending new block at BSN 9, CS=MCS-5 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4781,6 +4936,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-5): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4841,6 +4997,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-6): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4854,6 +5011,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4864,6 +5022,7 @@ - Sending new block at BSN 2, CS=MCS-6 -- Chunk with length 438 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4874,6 +5033,7 @@ - Sending new block at BSN 3, CS=MCS-6 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4884,6 +5044,7 @@ - Sending new block at BSN 4, CS=MCS-6 -- Chunk with length 290 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4894,6 +5055,7 @@ - Sending new block at BSN 5, CS=MCS-6 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4904,6 +5066,7 @@ - Sending new block at BSN 6, CS=MCS-6 -- Chunk with length 142 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4917,6 +5080,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-6): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4932,6 +5096,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-6): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4993,6 +5158,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-7): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5002,12 +5168,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(7) last_mcs(5) demanded_mcs(7) cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-7 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5022,6 +5189,7 @@ - Sending new block at BSN 3, CS=MCS-7 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5036,6 +5204,7 @@ - Sending new block at BSN 5, CS=MCS-7 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5050,6 +5219,7 @@ - Sending new block at BSN 7, CS=MCS-7 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5064,6 +5234,7 @@ - Sending new block at BSN 9, CS=MCS-7 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 9) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5081,6 +5252,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-7): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5142,6 +5314,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=56 data block (BSN 0, MCS-8): 14 71 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5152,12 +5325,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(8) demanded_mcs(8) cs_trans(8) +- initial_cs_dl(8) last_mcs(8) demanded_mcs(8) cs_trans(8) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-8 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5172,6 +5346,7 @@ - Sending new block at BSN 3, CS=MCS-8 -- Chunk with length 376 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5186,6 +5361,7 @@ - Sending new block at BSN 5, CS=MCS-8 -- Chunk with length 240 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5200,6 +5376,7 @@ - Sending new block at BSN 7, CS=MCS-8 -- Chunk with length 104 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5217,6 +5394,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=30 data block (BSN 8, MCS-8): 48 3d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5279,6 +5457,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-9): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5288,12 +5467,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(9) last_mcs(6) demanded_mcs(9) cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-9 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5308,6 +5488,7 @@ - Sending new block at BSN 3, CS=MCS-9 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5322,6 +5503,7 @@ - Sending new block at BSN 5, CS=MCS-9 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5339,6 +5521,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-9): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5356,6 +5539,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-9): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5402,11 +5586,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(6) cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5450,11 +5636,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 96 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(1) demanded_mcs(1) cs_trans(1) +- initial_cs_dl(1) last_mcs(1) demanded_mcs(1) cs_trans(1) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 98 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5498,11 +5686,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-2): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 92 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(2) demanded_mcs(2) cs_trans(2) +- initial_cs_dl(2) last_mcs(2) demanded_mcs(2) cs_trans(2) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 94 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5546,6 +5736,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5557,6 +5748,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-5): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5564,10 +5756,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-5): 0f 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7) cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7) cs_trans(7) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-7): 07 00 00 02 c0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 @@ -5612,6 +5805,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5623,6 +5817,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-6): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5630,10 +5825,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-6): 0f 40 00 00 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9) cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9) cs_trans(9) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-9): 07 00 00 02 28 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 @@ -5686,6 +5882,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-7): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5694,13 +5891,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-7): 0f 00 00 02 a0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5) cs_trans(5) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5) cs_trans(5) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-5): 07 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5752,6 +5951,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-9): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5760,13 +5960,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-9): 0f 00 00 02 00 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6) cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6) cs_trans(6) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-6): 07 40 00 02 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5780,3 +5982,233 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-5 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(2) cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 d2 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(2) demanded_mcs(2) cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 f2 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-4 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (44) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-4): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-4): 07 00 00 80 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(4) demanded_mcs(1) cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 d6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(1) demanded_mcs(1) cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 f6 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(6) cs_trans(6) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 2 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..c38417d 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,9 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_egprs_spb_dl === +Testing retx for MCS 6 to reseg_mcs 3 +Testing retx for MCS 5 to reseg_mcs 2 +Testing retx for MCS 4 to reseg_mcs 1 +Testing retx for MCS 6 to reseg_mcs 3 +=== end test_tbf_egprs_spb_dl === -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 17 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Wed Aug 17 13:34:28 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Wed, 17 Aug 2016 13:34:28 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 17: (4 comments) https://gerrit.osmocom.org/#/c/655/15/src/pcu_vty.c File src/pcu_vty.c: Line 489: "dl arq-type (spb|arq2)", > I notice that 0 is for EGPRS_ARQ1 and 1 is for EGPRS_ARQ2. Done Line 490: EGPRS_STR "DL ARQ options\n" > ah, missed this one before: EGPRS_STR is only for "egprs", not for "dl". Hi Neels, I am not clear on this comment. Currently I get the out put like this in VTY. Osmo-PCU(config-pcu)# dl arq-type spb arq2 Osmo-PCU(config-pcu)# dl arq-type spb enable DL SPB(ARQ1) support arq2 enable DL ARQ2 support Can you please more clear on your comment. Line 491: "enable DL SPB(ARQ1) support\n" > is SPB == ARQ1? I'm not familiar with the topic, but if Done https://gerrit.osmocom.org/#/c/655/15/src/tbf_dl.cpp File src/tbf_dl.cpp: Line 1215: { > this now fits on one line. Done -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 17 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Wed Aug 17 13:34:56 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Wed, 17 Aug 2016 13:34:56 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 17: (1 comment) https://gerrit.osmocom.org/#/c/655/15/src/tbf_dl.cpp File src/tbf_dl.cpp: Line 632: unsigned int spb_status = get_egprs_dl_spb_status(index); > nice. Done -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 17 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Wed Aug 17 13:36:49 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Wed, 17 Aug 2016 13:36:49 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 17: (1 comment) https://gerrit.osmocom.org/#/c/655/17/src/pcu_vty.c File src/pcu_vty.c: Line 133: vty_out(vty, " dl arq-type %d%s", bts->dl_arq_type, edit here -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 17 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Wed Aug 17 13:37:43 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Wed, 17 Aug 2016 13:37:43 +0000 Subject: [PATCH] osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/655 to look at the new patch set (#18). Modify EGPRS DL TBF flow to support SPB Modify the EGPRS DL TBF flow to support Split block during Retx. This patch will also Upgrade the test suite with test cases to validate the EGPRS Downlink SPB for Retransmission Scenarios like MCS6->MCS3, MCS4->MCS1, MCS5->MCS2, MCS9->MCS3 MCS7->MCS2, MCS8->MCS3 have been simulated and Integration tested in NuRAN 1.0 hardware thoroughly. Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 --- M src/gprs_coding_scheme.h M src/pcu_main.cpp M src/pcu_vty.c M src/rlc.cpp M src/rlc.h M src/tbf.h M src/tbf_dl.cpp M tests/edge/EdgeTest.cpp M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 11 files changed, 956 insertions(+), 80 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/55/655/18 diff --git a/src/gprs_coding_scheme.h b/src/gprs_coding_scheme.h index 60a8e79..3b15372 100644 --- a/src/gprs_coding_scheme.h +++ b/src/gprs_coding_scheme.h @@ -113,7 +113,8 @@ static const char *modeName(Mode mode); static Scheme get_retx_mcs(const GprsCodingScheme mcs, - const GprsCodingScheme retx_mcs); + const GprsCodingScheme retx_mcs, + const unsigned arq_type); static enum Scheme egprs_mcs_retx_tbl[MAX_NUM_ARQ] [MAX_NUM_MCS][MAX_NUM_MCS]; @@ -232,8 +233,9 @@ } inline GprsCodingScheme::Scheme GprsCodingScheme::get_retx_mcs( const GprsCodingScheme mcs, - const GprsCodingScheme demanded_mcs) + const GprsCodingScheme demanded_mcs, + const unsigned arq_type) { - return egprs_mcs_retx_tbl[EGPRS_ARQ2][mcs.to_num() - 1] + return egprs_mcs_retx_tbl[arq_type][mcs.to_num() - 1] [demanded_mcs.to_num() - 1]; } diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2d86cda..e34d534 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -210,6 +210,12 @@ bts->dl_tbf_idle_msec = 2000; bts->llc_idle_ack_csec = 10; + /* + * By default resegmentation is supported in DL + * can also be configured through VTY + */ + bts->dl_arq_type = EGPRS_ARQ1; + msgb_set_talloc_ctx(tall_pcu_ctx); osmo_init_logging(&gprs_log_info); diff --git a/src/pcu_vty.c b/src/pcu_vty.c index 58fea99..f0f29a7 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -129,6 +129,10 @@ vty_out(vty, " window-size %d %d%s", bts->ws_base, bts->ws_pdch, VTY_NEWLINE); + if (bts->dl_arq_type) + vty_out(vty, " dl arq-type %s%s", "arq2", + VTY_NEWLINE); + if (bts->force_llc_lifetime == 0xffff) vty_out(vty, " queue lifetime infinite%s", VTY_NEWLINE); else if (bts->force_llc_lifetime) @@ -476,6 +480,23 @@ bts->max_mcs_dl = 0; bts->max_mcs_ul = 0; + + return CMD_SUCCESS; +} + +DEFUN(cfg_pcu_dl_arq_type, + cfg_pcu_dl_arq_cmd, + "dl arq-type (spb|arq2)", + EGPRS_STR "DL ARQ options\n" + "enable DL SPB(ARQ1) support\n" + "enable DL ARQ2 support") +{ + struct gprs_rlcmac_bts *bts = bts_main_data(); + + if (!strcmp(argv[0], "arq2")) + bts->dl_arq_type = 1; + else + bts->dl_arq_type = 0; return CMD_SUCCESS; } @@ -954,6 +975,7 @@ install_element(PCU_NODE, &cfg_pcu_no_cs_downgrade_thrsh_cmd); install_element(PCU_NODE, &cfg_pcu_cs_lqual_ranges_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_cmd); + install_element(PCU_NODE, &cfg_pcu_dl_arq_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_max_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_max_cmd); diff --git a/src/rlc.cpp b/src/rlc.cpp index 6770043..e69d1fc 100644 --- a/src/rlc.cpp +++ b/src/rlc.cpp @@ -285,7 +285,8 @@ } static void gprs_rlc_data_header_init(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding, unsigned int header_bits) + GprsCodingScheme cs, bool with_padding, unsigned int header_bits, + const unsigned int spb) { unsigned int i; unsigned int padding_bits = with_padding ? cs.optionalPaddingBits() : 0; @@ -300,7 +301,7 @@ for (i = 0; i < rlc->num_data_blocks; i++) { gprs_rlc_data_block_info_init(&rlc->block_info[i], cs, - with_padding); + with_padding, spb); rlc->data_offs_bits[i] = header_bits + padding_bits + @@ -310,21 +311,25 @@ } void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsDL()); + cs.numDataHeaderBitsDL(), spb); } void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding) { + /* + * last parameter is sent as 0 since common function used + * for both DL and UL + */ return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsUL()); + cs.numDataHeaderBitsUL(), 0); } void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { unsigned int data_len = cs.maxDataBlockBytes(); if (with_padding) @@ -336,7 +341,7 @@ rdbi->e = 1; rdbi->cv = 15; rdbi->pi = 0; - rdbi->spb = 0; + rdbi->spb = spb; } unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, @@ -411,8 +416,18 @@ enum egprs_puncturing_values gprs_get_punct_scheme( enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current) + const GprsCodingScheme &cs_current, + const enum egprs_rlcmac_dl_spb spb) { + + /* + * 10.4.8b of TS 44.060 + * If it is second segment of the block + * dont change the puncturing scheme + */ + if (spb == EGPRS_RLCMAC_DL_SEC_SEG) + return punct; + /* TS 44.060 9.3.2.1.1 */ if ((GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS9) && (GprsCodingScheme::Scheme(cs_current) == GprsCodingScheme::MCS6)) { diff --git a/src/rlc.h b/src/rlc.h index b1a1fba..b693418 100644 --- a/src/rlc.h +++ b/src/rlc.h @@ -213,18 +213,19 @@ }; void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding); void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, enum egprs_puncturing_values punct, enum egprs_puncturing_values punct2, int with_padding); void gprs_rlc_mcs_cps_decode(unsigned int cps, GprsCodingScheme cs, int *punct, int *punct2, int *with_padding); enum egprs_puncturing_values gprs_get_punct_scheme(enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current_trans); + const GprsCodingScheme &cs_current_trans, + const enum egprs_rlcmac_dl_spb spb); void gprs_update_punct_scheme(enum egprs_puncturing_values *punct, const GprsCodingScheme &cs); /* diff --git a/src/tbf.h b/src/tbf.h index 1bd7878..2a1bfe8 100644 --- a/src/tbf.h +++ b/src/tbf.h @@ -421,6 +421,11 @@ int analyse_errors(char *show_rbb, uint8_t ssn, ana_result *res); void schedule_next_frame(); + enum egprs_rlc_dl_reseg_bsn_state egprs_dl_get_data + (int bsn, uint8_t **block_data); + unsigned int get_egprs_dl_spb_status(int bsn); + enum egprs_rlcmac_dl_spb get_egprs_dl_spb(int bsn); + struct osmo_timer_list m_llc_timer; }; diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp index 07a747a..a24cc21 100644 --- a/src/tbf_dl.cpp +++ b/src/tbf_dl.cpp @@ -375,21 +375,28 @@ return -1; if (is_egprs_enabled()) { + /* Table 8.1.1.2 and Table 8.1.1.1 of 44.060 */ m_rlc.block(bsn)->cs_current_trans = - GprsCodingScheme::get_retx_mcs( - m_rlc.block(bsn)->cs_last, ms()->current_cs_dl()); + GprsCodingScheme::get_retx_mcs( + m_rlc.block(bsn)->cs_init, + ms()->current_cs_dl(), + bts->bts_data()->dl_arq_type); LOGP(DRLCMACDL, LOGL_DEBUG, - "- current_cs_dl(%d) demanded_mcs(%d) cs_trans(%d)\n", - m_rlc.block(bsn)->cs_last.to_num(), - ms()->current_cs_dl().to_num(), - m_rlc.block(bsn)->cs_current_trans.to_num()); + "- initial_cs_dl(%d) last_mcs(%d)" + " demanded_mcs(%d) cs_trans(%d)" + " arq_type(%d) bsn(%d)\n", + m_rlc.block(bsn)->cs_init.to_num(), + m_rlc.block(bsn)->cs_last.to_num(), + ms()->current_cs_dl().to_num(), + m_rlc.block(bsn)->cs_current_trans.to_num(), + bts->bts_data()->dl_arq_type, bsn); /* TODO: Need to remove this check when MCS-8 -> MCS-6 * transistion is handled. * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 */ - if (m_rlc.block(bsn)->cs_last == GprsCodingScheme::MCS8) + if (m_rlc.block(bsn)->cs_init == GprsCodingScheme::MCS8) m_rlc.block(bsn)->cs_current_trans = GprsCodingScheme::MCS8; } else @@ -523,6 +530,11 @@ data = rlc_data->prepare(block_data_len); rlc_data->cs_last = cs; rlc_data->cs_current_trans = cs; + + /* Initialise the variable related to DL SPB */ + rlc_data->spb_status.block_status_dl = EGPRS_RESEG_DL_DEFAULT; + rlc_data->cs_init = cs; + rlc_data->len = block_data_len; rdbi = &(rlc_data->block_info); @@ -616,7 +628,8 @@ unsigned num_bsns; enum egprs_puncturing_values punct[ARRAY_SIZE(rlc.block_info)]; bool need_padding = false; - + enum egprs_rlcmac_dl_spb spb = EGPRS_RLCMAC_DL_NO_RETX; + unsigned int spb_status = get_egprs_dl_spb_status(index); /* * TODO: This is an experimental work-around to put 2 BSN into * MSC-7 to MCS-9 encoded messages. It just sends the same BSN @@ -626,6 +639,7 @@ * the current limit. */ cs = m_rlc.block(index)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(index)->cs_init; bsns[0] = index; num_bsns = 1; @@ -634,7 +648,17 @@ num_bsns += 1; } - if (num_bsns == 1) { + /* + * if the intial mcs is 8 and retransmission mcs is either 6 or 3 + * we have to include the padding of 6 octets in first segment + */ + if ((GprsCodingScheme::Scheme(cs_init) == GprsCodingScheme::MCS8) && + (GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS6 || + GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS3)) { + if (spb_status == EGPRS_RESEG_DL_DEFAULT || + spb_status == EGPRS_RESEG_SECOND_SEG_SENT) + need_padding = true; + } else if (num_bsns == 1) { /* TODO: remove the conditional when MCS-6 padding isn't * failing to be decoded by MEs anymore */ /* TODO: support of MCS-8 -> MCS-6 transition should be @@ -646,7 +670,14 @@ cs.decToSingleBlock(&need_padding); } - gprs_rlc_data_info_init_dl(&rlc, cs, need_padding); + spb = get_egprs_dl_spb(index); + + LOGP(DRLCMACDL, LOGL_DEBUG, "- need_padding %d spb_status %d spb %d" + "(BSN1 %d BSN2 %d)\n", + need_padding, + spb_status, spb, index, index2); + + gprs_rlc_data_info_init_dl(&rlc, cs, need_padding, spb); rlc.usf = 7; /* will be set at scheduler */ rlc.pr = 0; /* FIXME: power reduction */ @@ -665,10 +696,9 @@ data_block_idx++) { int bsn; - GprsCodingScheme cs_enc; uint8_t *block_data; gprs_rlc_data_block_info *rdbi, *block_info; - enum egprs_puncturing_values punct_scheme; + enum egprs_rlc_dl_reseg_bsn_state reseg_status; /* Check if there are more blocks than BSNs */ if (data_block_idx < num_bsns) @@ -676,38 +706,43 @@ else bsn = bsns[0]; - cs_enc = m_rlc.block(bsn)->cs_current_trans; - /* get data and header from current block */ - block_data = m_rlc.block(bsn)->block; - /* Get current puncturing scheme from block */ - punct_scheme = gprs_get_punct_scheme( + + m_rlc.block(bsn)->next_ps = gprs_get_punct_scheme( m_rlc.block(bsn)->next_ps, - m_rlc.block(bsn)->cs_last, cs); + m_rlc.block(bsn)->cs_last, cs, spb); if (cs.isEgprs()) { - OSMO_ASSERT(punct_scheme >= EGPRS_PS_1); - OSMO_ASSERT(punct_scheme <= EGPRS_PS_3); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps >= EGPRS_PS_1); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps <= EGPRS_PS_3); } - punct[data_block_idx] = punct_scheme; + punct[data_block_idx] = m_rlc.block(bsn)->next_ps; rdbi = &rlc.block_info[data_block_idx]; block_info = &m_rlc.block(bsn)->block_info; - if(rdbi->data_len != m_rlc.block(bsn)->len) { - LOGP(DRLCMACDL, LOGL_ERROR, - "ERROR: Expected len = %d for %s instead of " - "%d in data unit %d (BSN %d, %s)\n", - rdbi->data_len, cs.name(), m_rlc.block(bsn)->len, - data_block_idx, bsn, cs_enc.name()); - OSMO_ASSERT(rdbi->data_len == m_rlc.block(bsn)->len); - } - - /* TODO: Need to handle 2 same bsns - * in header type 1 + /* + * get data and header from current block + * function returns the reseg status */ - gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, - cs); + reseg_status = egprs_dl_get_data(bsn, &block_data); + m_rlc.block(bsn)->spb_status.block_status_dl = reseg_status; + + /* + * If it is first segment of the split block set the state of + * bsn to nacked. If it is the first segment dont update the + * next ps value of bsn. since next segment also needs same cps + */ + if (spb == EGPRS_RLCMAC_DL_FIRST_SEG) + m_window.m_v_b.mark_nacked(bsn); + else { + /* + * TODO: Need to handle 2 same bsns + * in header type 1 + */ + gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, + cs); + } m_rlc.block(bsn)->cs_last = cs; rdbi->e = block_info->e; @@ -1169,3 +1204,118 @@ keep_time_frames = msecs_to_frames(bts_data()->dl_tbf_idle_msec); return frames_since_last_drain(fn) <= keep_time_frames; } + +/* + * This function returns the pointer to data which needs + * to be copied. Also updates the status of the block related to + * Split block handling in the RLC/MAC block. + */ +enum egprs_rlc_dl_reseg_bsn_state + gprs_rlcmac_dl_tbf::egprs_dl_get_data(int bsn, uint8_t **block_data) +{ + gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state *block_status_dl = + &rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + *block_data = &rlc_data->block[0]; + + /* + * Table 10.3a.0.1 of 44.060 + * MCS6,9: second segment starts at 74/2 = 37 + * MCS5,7: second segment starts at 56/2 = 28 + * MCS8: second segment starts at 31 + * MCS4: second segment starts at 44/2 = 22 + */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + if (*block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + switch (GprsCodingScheme::Scheme(cs_init)) { + case GprsCodingScheme::MCS6 : + case GprsCodingScheme::MCS9 : + *block_data = &rlc_data->block[37]; + break; + case GprsCodingScheme::MCS7 : + case GprsCodingScheme::MCS5 : + *block_data = &rlc_data->block[28]; + break; + case GprsCodingScheme::MCS8 : + *block_data = &rlc_data->block[31]; + break; + case GprsCodingScheme::MCS4 : + *block_data = &rlc_data->block[22]; + break; + default: + LOGP(DRLCMACDL, LOGL_ERROR, "Software error: " + "--%s hit invalid condition. headerType(%d) " + " blockstatus(%d) cs(%s) PLEASE FIX!\n", name(), + cs_current_trans.headerTypeData(), + *block_status_dl, cs_init.name()); + break; + + } + return EGPRS_RESEG_SECOND_SEG_SENT; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } + } + return EGPRS_RESEG_DL_DEFAULT; +} + +/* + * This function returns the status of split block + * for RLC/MAC block. + */ +unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_status(const int bsn) +{ + const gprs_rlc_data *rlc_data = m_rlc.block(bsn); + + return rlc_data->spb_status.block_status_dl; +} + +/* + * This function returns the spb value to be sent OTA + * for RLC/MAC block. + */ +enum egprs_rlcmac_dl_spb gprs_rlcmac_dl_tbf::get_egprs_dl_spb(const int bsn) +{ + struct gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state block_status_dl = + rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + + /* Table 10.4.8b.1 of 44.060 */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + /* + * if we are sending the second segment the spb should be 3 + * other wise it should be 2 + */ + if (block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + return EGPRS_RLCMAC_DL_SEC_SEG; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RLCMAC_DL_FIRST_SEG; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RLCMAC_DL_FIRST_SEG; + } + } + /* Non SPB cases 0 is reurned */ + return EGPRS_RLCMAC_DL_NO_RETX; +} diff --git a/tests/edge/EdgeTest.cpp b/tests/edge/EdgeTest.cpp index 807102c..9081d4d 100644 --- a/tests/edge/EdgeTest.cpp +++ b/tests/edge/EdgeTest.cpp @@ -517,7 +517,7 @@ /* TS 44.060, B.1 */ cs = GprsCodingScheme::CS4; - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -570,7 +570,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -592,7 +592,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -630,7 +630,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -669,7 +669,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -694,7 +694,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -719,7 +719,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -740,7 +740,7 @@ OSMO_ASSERT(data[0] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -777,7 +777,7 @@ cs = GprsCodingScheme::MCS4; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -835,7 +835,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -872,7 +872,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -923,7 +923,7 @@ OSMO_ASSERT(data[3] == 0); /* Block 3 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -967,7 +967,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -993,7 +993,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1020,7 +1020,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1074,7 +1074,7 @@ block_idx++) { struct gprs_rlc_data_info rlc; - gprs_rlc_data_info_init_dl(&rlc, cs, false); + gprs_rlc_data_info_init_dl(&rlc, cs, false, 0); memset(bits, pattern, sizeof(bits)); Decoding::rlc_copy_to_aligned_buffer( @@ -1118,12 +1118,14 @@ struct gprs_rlc_data_info rlc; printf("=== start %s ===\n", __func__); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::CS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::CS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 24); OSMO_ASSERT(rlc.block_info[0].data_len == 20); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::MCS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::MCS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 33); OSMO_ASSERT(rlc.block_info[0].data_len == 22); diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..5e45506 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -1814,6 +1814,203 @@ } +static void egprs_spb_to_normal_validation(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + uint16_t bsn1, bsn2, bsn3; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + struct gprs_rlc_dl_header_egprs_2 *egprs2; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + if (!(mcs == 6 && demanded_mcs == 3)) + return; + + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + bsn1 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) + || (egprs2->bsn1_lo); + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(bsn1 == 0); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + bsn2 = (egprs3->bsn1_hi << 9) || (egprs3->bsn1_mid << 1) || + (egprs3->bsn1_lo); + OSMO_ASSERT(bsn2 == bsn1); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Handle (MCS3, MCS3) -> MCS6 case */ + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + mcs)); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs2->cps == 0); + bsn3 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) || + (egprs2->bsn1_lo); + OSMO_ASSERT(bsn3 == bsn2); + + tbf_cleanup(dl_tbf); +} +static void establish_and_use_egprs_dl_tbf_for_spb(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + /* TODO: Need to support of MCS8 -> MCS6 ->MCS3 transistion + * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 + * dated 2016-02-07 23:45:40 (UTC) + */ + if (!(((mcs == 5) && (demanded_mcs == 2)) || + ((mcs == 6) && (demanded_mcs == 3)) || + ((mcs == 4) && (demanded_mcs == 1)))) + return; + + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + tbf_cleanup(dl_tbf); +} + static void establish_and_use_egprs_dl_tbf_for_retx(BTS *the_bts, int mcs, int demanded_mcs) { @@ -1972,6 +2169,9 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; + /* First parameter is current MCS, second one is demanded_mcs */ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 6); @@ -1981,6 +2181,38 @@ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 9); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 7, 5); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 9, 6); + + printf("=== end %s ===\n", __func__); +} + +static void test_tbf_egprs_spb_dl(void) +{ + BTS the_bts; + gprs_rlcmac_bts *bts; + uint8_t ts_no = 4; + int i, j; + + printf("=== start %s ===\n", __func__); + + bts = the_bts.bts_data(); + bts->cs_downgrade_threshold = 0; + setup_bts(&the_bts, ts_no); + bts->dl_tbf_idle_msec = 200; + bts->egprs_enabled = 1; + + /* ARQ I resegmentation support */ + bts->dl_arq_type = EGPRS_ARQ1; + + /* + * First parameter is current MCS, second one is demanded_mcs + * currently only MCS5->MCS2, MCS6->3, MCS4->MCS1 is tested in UT + * rest scenarios has been integration tested + */ + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 6, 3); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 5, 2); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 4, 1); + /* check MCS6->(MCS3+MCS3)->MCS6 case */ + egprs_spb_to_normal_validation(&the_bts, 6, 3); printf("=== end %s ===\n", __func__); } @@ -1999,6 +2231,8 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; for (i = 1; i <= 9; i++) establish_and_use_egprs_dl_tbf(&the_bts, i); @@ -2071,6 +2305,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_egprs_spb_dl(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..1ba4189 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -72,6 +72,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -81,6 +82,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -157,6 +159,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -166,6 +169,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -242,6 +246,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -251,6 +256,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -259,6 +265,7 @@ - Sending new block at BSN 2, CS=CS-1 -- Chunk with length 160 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=13 block=3 data=07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b @@ -267,6 +274,7 @@ - Sending new block at BSN 3, CS=CS-1 -- Chunk with length 140 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=17 block=4 data=07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @@ -275,6 +283,7 @@ - Sending new block at BSN 4, CS=CS-1 -- Chunk with length 120 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=21 block=5 data=07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 @@ -283,6 +292,7 @@ - Sending new block at BSN 5, CS=CS-1 -- Chunk with length 100 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=26 block=6 data=07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 @@ -291,6 +301,7 @@ - Sending new block at BSN 6, CS=CS-1 -- Chunk with length 80 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=30 block=7 data=07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b @@ -299,6 +310,7 @@ - Sending new block at BSN 7, CS=CS-1 -- Chunk with length 60 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=34 block=8 data=07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f @@ -307,6 +319,7 @@ - Sending new block at BSN 8, CS=CS-1 -- Chunk with length 40 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=39 block=9 data=07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 @@ -315,6 +328,7 @@ - Sending new block at BSN 9, CS=CS-1 -- Chunk with length 20 would exactly fit into space (20): add length header with LI=0, to make frame extend to next block, and we are done data block (BSN 9, CS-1): 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=43 block=10 data=07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 @@ -326,6 +340,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=47 block=11 data=07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 @@ -334,6 +349,7 @@ - Sending new block at BSN 11, CS=CS-1 -- Chunk with length 182 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=52 block=0 data=07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 @@ -342,6 +358,7 @@ - Sending new block at BSN 12, CS=CS-1 -- Chunk with length 162 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=56 block=1 data=07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 @@ -350,6 +367,7 @@ - Sending new block at BSN 13, CS=CS-1 -- Chunk with length 142 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 13, CS-1): 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=60 block=2 data=07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d @@ -358,6 +376,7 @@ - Sending new block at BSN 14, CS=CS-1 -- Chunk with length 122 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=65 block=3 data=07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 @@ -366,6 +385,7 @@ - Sending new block at BSN 15, CS=CS-1 -- Chunk with length 102 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=69 block=4 data=07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 @@ -374,6 +394,7 @@ - Sending new block at BSN 16, CS=CS-1 -- Chunk with length 82 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=73 block=5 data=07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 @@ -382,6 +403,7 @@ - Sending new block at BSN 17, CS=CS-1 -- Chunk with length 62 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=78 block=6 data=07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d @@ -390,6 +412,7 @@ - Sending new block at BSN 18, CS=CS-1 -- Chunk with length 42 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=82 block=7 data=07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 @@ -398,6 +421,7 @@ - Sending new block at BSN 19, CS=CS-1 -- Chunk with length 22 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=86 block=8 data=07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 @@ -411,6 +435,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=16 data block (BSN 20, CS-1): 0a 41 c6 c7 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -449,6 +474,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 data block (BSN 21, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -468,6 +494,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 22, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FINISHED) @@ -1481,6 +1508,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 0, CS-1): 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 MSG = 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 @@ -1491,6 +1519,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 1, CS-1): 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 MSG = 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 @@ -1501,6 +1530,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FINISHED data block (BSN 2, CS-1): 4d 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling cannot be scheduled in this TS 7 (first control TS 4) @@ -1784,6 +1814,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=10 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 0, CS-4): 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654292 TS 7 @@ -1797,6 +1828,7 @@ TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) downlink (V(A)==0 .. V(S)==1) - Restarting at BSN 0, because all blocks have been transmitted. - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-4): 07 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 @@ -2365,6 +2397,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654279 block=10 data=00 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 @@ -2384,6 +2417,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -2406,6 +2440,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654288 block=0 data=00 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 @@ -2425,6 +2460,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654292 block=1 data=00 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2447,6 +2483,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654296 block=2 data=00 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c @@ -2466,6 +2503,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654301 block=3 data=00 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b @@ -2488,6 +2526,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 6, CS-1): 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654305 block=4 data=00 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 @@ -2507,6 +2546,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654309 block=5 data=00 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 @@ -2526,6 +2566,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654314 block=6 data=00 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 @@ -2548,6 +2589,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654318 block=7 data=00 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 @@ -2567,6 +2609,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654322 block=8 data=00 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2589,6 +2632,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654327 block=9 data=00 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c @@ -2608,6 +2652,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654331 block=10 data=00 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b @@ -2630,6 +2675,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 13, CS-1): 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654335 block=11 data=00 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 @@ -2649,6 +2695,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654340 block=0 data=00 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 @@ -2668,6 +2715,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654344 block=1 data=00 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 @@ -2690,6 +2738,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654348 block=2 data=00 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 @@ -2709,6 +2758,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654353 block=3 data=00 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2731,6 +2781,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654357 block=4 data=00 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c @@ -2750,6 +2801,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654361 block=5 data=00 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b @@ -2772,6 +2824,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 20, CS-1): 16 35 45 54 20 32 38 4c 4c 43 20 50 41 43 4b 45 54 20 32 39 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because 20 blocks sent. TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW): Scheduling polling at FN 2654379 TS 7 @@ -2795,6 +2848,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 21, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) msg block (BSN 21, CS-1): 07 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654370 block=7 data=00 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 @@ -2814,6 +2868,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 22, CS-1): 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) msg block (BSN 22, CS-1): 07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654374 block=8 data=07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 @@ -2836,6 +2891,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 23, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) msg block (BSN 23, CS-1): 07 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654379 block=9 data=00 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 @@ -2855,6 +2911,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 24, CS-1): 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) msg block (BSN 24, CS-1): 07 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654383 block=10 data=00 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2877,6 +2934,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 25, CS-1): 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 25 BSN2 -1) - Copying data unit 0 (BSN 25) msg block (BSN 25, CS-1): 07 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654387 block=11 data=00 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c @@ -2896,6 +2954,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 26, CS-1): 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 26 BSN2 -1) - Copying data unit 0 (BSN 26) msg block (BSN 26, CS-1): 07 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654392 block=0 data=00 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b @@ -2918,6 +2977,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 27, CS-1): 16 35 45 54 20 33 38 4c 4c 43 20 50 41 43 4b 45 54 20 33 39 +- need_padding 0 spb_status 0 spb 0(BSN1 27 BSN2 -1) - Copying data unit 0 (BSN 27) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) @@ -3028,6 +3088,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654405 block=3 data=00 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 @@ -3047,6 +3108,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654409 block=4 data=00 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 @@ -3066,6 +3128,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (16) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654413 block=5 data=00 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 @@ -3085,6 +3148,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (14) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654418 block=6 data=00 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 @@ -3104,6 +3168,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654422 block=7 data=00 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -3123,6 +3188,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654426 block=8 data=00 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 @@ -3142,6 +3208,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654431 block=9 data=00 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b @@ -3161,6 +3228,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654435 block=10 data=00 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 @@ -3180,6 +3248,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654439 block=11 data=00 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 @@ -3199,6 +3268,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654444 block=0 data=00 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c @@ -3218,6 +3288,7 @@ Complete DL frame for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=21 TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 10, CS-1): 4d 43 20 50 41 43 4b 45 54 20 30 39 20 28 54 42 46 20 32 29 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654461 TS 7 @@ -3698,6 +3769,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 0, MCS-1): 14 15 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3711,6 +3783,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3721,6 +3794,7 @@ - Sending new block at BSN 2, CS=MCS-1 -- Chunk with length 490 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3731,6 +3805,7 @@ - Sending new block at BSN 3, CS=MCS-1 -- Chunk with length 468 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3741,6 +3816,7 @@ - Sending new block at BSN 4, CS=MCS-1 -- Chunk with length 446 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3751,6 +3827,7 @@ - Sending new block at BSN 5, CS=MCS-1 -- Chunk with length 424 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3761,6 +3838,7 @@ - Sending new block at BSN 6, CS=MCS-1 -- Chunk with length 402 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3771,6 +3849,7 @@ - Sending new block at BSN 7, CS=MCS-1 -- Chunk with length 380 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3781,6 +3860,7 @@ - Sending new block at BSN 8, CS=MCS-1 -- Chunk with length 358 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3791,6 +3871,7 @@ - Sending new block at BSN 9, CS=MCS-1 -- Chunk with length 336 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3801,6 +3882,7 @@ - Sending new block at BSN 10, CS=MCS-1 -- Chunk with length 314 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3811,6 +3893,7 @@ - Sending new block at BSN 11, CS=MCS-1 -- Chunk with length 292 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3821,6 +3904,7 @@ - Sending new block at BSN 12, CS=MCS-1 -- Chunk with length 270 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3831,6 +3915,7 @@ - Sending new block at BSN 13, CS=MCS-1 -- Chunk with length 248 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3841,6 +3926,7 @@ - Sending new block at BSN 14, CS=MCS-1 -- Chunk with length 226 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3851,6 +3937,7 @@ - Sending new block at BSN 15, CS=MCS-1 -- Chunk with length 204 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3861,6 +3948,7 @@ - Sending new block at BSN 16, CS=MCS-1 -- Chunk with length 182 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3871,6 +3959,7 @@ - Sending new block at BSN 17, CS=MCS-1 -- Chunk with length 160 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3881,6 +3970,7 @@ - Sending new block at BSN 18, CS=MCS-1 -- Chunk with length 138 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3891,6 +3981,7 @@ - Sending new block at BSN 19, CS=MCS-1 -- Chunk with length 116 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 19, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3901,6 +3992,7 @@ - Sending new block at BSN 20, CS=MCS-1 -- Chunk with length 94 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 20, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3911,6 +4003,7 @@ - Sending new block at BSN 21, CS=MCS-1 -- Chunk with length 72 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 21, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3921,6 +4014,7 @@ - Sending new block at BSN 22, CS=MCS-1 -- Chunk with length 50 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 22, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3931,6 +4025,7 @@ - Sending new block at BSN 23, CS=MCS-1 -- Chunk with length 28 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 23, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3946,6 +4041,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 24, MCS-1): 0c 1d 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4006,6 +4102,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=16 data block (BSN 0, MCS-2): 14 21 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4019,6 +4116,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4029,6 +4127,7 @@ - Sending new block at BSN 2, CS=MCS-2 -- Chunk with length 484 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4039,6 +4138,7 @@ - Sending new block at BSN 3, CS=MCS-2 -- Chunk with length 456 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4049,6 +4149,7 @@ - Sending new block at BSN 4, CS=MCS-2 -- Chunk with length 428 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4059,6 +4160,7 @@ - Sending new block at BSN 5, CS=MCS-2 -- Chunk with length 400 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4069,6 +4171,7 @@ - Sending new block at BSN 6, CS=MCS-2 -- Chunk with length 372 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4079,6 +4182,7 @@ - Sending new block at BSN 7, CS=MCS-2 -- Chunk with length 344 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4089,6 +4193,7 @@ - Sending new block at BSN 8, CS=MCS-2 -- Chunk with length 316 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4099,6 +4204,7 @@ - Sending new block at BSN 9, CS=MCS-2 -- Chunk with length 288 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4109,6 +4215,7 @@ - Sending new block at BSN 10, CS=MCS-2 -- Chunk with length 260 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4119,6 +4226,7 @@ - Sending new block at BSN 11, CS=MCS-2 -- Chunk with length 232 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4129,6 +4237,7 @@ - Sending new block at BSN 12, CS=MCS-2 -- Chunk with length 204 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4139,6 +4248,7 @@ - Sending new block at BSN 13, CS=MCS-2 -- Chunk with length 176 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4149,6 +4259,7 @@ - Sending new block at BSN 14, CS=MCS-2 -- Chunk with length 148 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4159,6 +4270,7 @@ - Sending new block at BSN 15, CS=MCS-2 -- Chunk with length 120 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4169,6 +4281,7 @@ - Sending new block at BSN 16, CS=MCS-2 -- Chunk with length 92 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4179,6 +4292,7 @@ - Sending new block at BSN 17, CS=MCS-2 -- Chunk with length 64 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4189,6 +4303,7 @@ - Sending new block at BSN 18, CS=MCS-2 -- Chunk with length 36 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4204,6 +4319,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=18 data block (BSN 19, MCS-2): 10 25 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4264,6 +4380,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=25 data block (BSN 0, MCS-3): 14 33 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4277,6 +4394,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4287,6 +4405,7 @@ - Sending new block at BSN 2, CS=MCS-3 -- Chunk with length 475 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4297,6 +4416,7 @@ - Sending new block at BSN 3, CS=MCS-3 -- Chunk with length 438 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4307,6 +4427,7 @@ - Sending new block at BSN 4, CS=MCS-3 -- Chunk with length 401 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4317,6 +4438,7 @@ - Sending new block at BSN 5, CS=MCS-3 -- Chunk with length 364 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4327,6 +4449,7 @@ - Sending new block at BSN 6, CS=MCS-3 -- Chunk with length 327 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4337,6 +4460,7 @@ - Sending new block at BSN 7, CS=MCS-3 -- Chunk with length 290 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4347,6 +4471,7 @@ - Sending new block at BSN 8, CS=MCS-3 -- Chunk with length 253 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4357,6 +4482,7 @@ - Sending new block at BSN 9, CS=MCS-3 -- Chunk with length 216 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4367,6 +4493,7 @@ - Sending new block at BSN 10, CS=MCS-3 -- Chunk with length 179 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4377,6 +4504,7 @@ - Sending new block at BSN 11, CS=MCS-3 -- Chunk with length 142 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4387,6 +4515,7 @@ - Sending new block at BSN 12, CS=MCS-3 -- Chunk with length 105 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4397,6 +4526,7 @@ - Sending new block at BSN 13, CS=MCS-3 -- Chunk with length 68 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4410,6 +4540,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-3): 3f 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4425,6 +4556,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=34 data block (BSN 15, MCS-3): 02 45 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4485,6 +4617,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=32 data block (BSN 0, MCS-4): 14 41 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4498,6 +4631,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4508,6 +4642,7 @@ - Sending new block at BSN 2, CS=MCS-4 -- Chunk with length 468 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4518,6 +4653,7 @@ - Sending new block at BSN 3, CS=MCS-4 -- Chunk with length 424 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4528,6 +4664,7 @@ - Sending new block at BSN 4, CS=MCS-4 -- Chunk with length 380 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4538,6 +4675,7 @@ - Sending new block at BSN 5, CS=MCS-4 -- Chunk with length 336 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4548,6 +4686,7 @@ - Sending new block at BSN 6, CS=MCS-4 -- Chunk with length 292 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4558,6 +4697,7 @@ - Sending new block at BSN 7, CS=MCS-4 -- Chunk with length 248 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4568,6 +4708,7 @@ - Sending new block at BSN 8, CS=MCS-4 -- Chunk with length 204 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4578,6 +4719,7 @@ - Sending new block at BSN 9, CS=MCS-4 -- Chunk with length 160 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4588,6 +4730,7 @@ - Sending new block at BSN 10, CS=MCS-4 -- Chunk with length 116 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4598,6 +4741,7 @@ - Sending new block at BSN 11, CS=MCS-4 -- Chunk with length 72 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4613,6 +4757,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 12, MCS-4): 38 1d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4673,6 +4818,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-5): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4686,6 +4832,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4696,6 +4843,7 @@ - Sending new block at BSN 2, CS=MCS-5 -- Chunk with length 456 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4706,6 +4854,7 @@ - Sending new block at BSN 3, CS=MCS-5 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4716,6 +4865,7 @@ - Sending new block at BSN 4, CS=MCS-5 -- Chunk with length 344 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4726,6 +4876,7 @@ - Sending new block at BSN 5, CS=MCS-5 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4736,6 +4887,7 @@ - Sending new block at BSN 6, CS=MCS-5 -- Chunk with length 232 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4746,6 +4898,7 @@ - Sending new block at BSN 7, CS=MCS-5 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4756,6 +4909,7 @@ - Sending new block at BSN 8, CS=MCS-5 -- Chunk with length 120 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4766,6 +4920,7 @@ - Sending new block at BSN 9, CS=MCS-5 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4781,6 +4936,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-5): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4841,6 +4997,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-6): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4854,6 +5011,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4864,6 +5022,7 @@ - Sending new block at BSN 2, CS=MCS-6 -- Chunk with length 438 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4874,6 +5033,7 @@ - Sending new block at BSN 3, CS=MCS-6 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4884,6 +5044,7 @@ - Sending new block at BSN 4, CS=MCS-6 -- Chunk with length 290 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4894,6 +5055,7 @@ - Sending new block at BSN 5, CS=MCS-6 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4904,6 +5066,7 @@ - Sending new block at BSN 6, CS=MCS-6 -- Chunk with length 142 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4917,6 +5080,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-6): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4932,6 +5096,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-6): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4993,6 +5158,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-7): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5002,12 +5168,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(7) last_mcs(5) demanded_mcs(7) cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-7 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5022,6 +5189,7 @@ - Sending new block at BSN 3, CS=MCS-7 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5036,6 +5204,7 @@ - Sending new block at BSN 5, CS=MCS-7 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5050,6 +5219,7 @@ - Sending new block at BSN 7, CS=MCS-7 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5064,6 +5234,7 @@ - Sending new block at BSN 9, CS=MCS-7 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 9) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5081,6 +5252,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-7): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5142,6 +5314,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=56 data block (BSN 0, MCS-8): 14 71 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5152,12 +5325,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(8) demanded_mcs(8) cs_trans(8) +- initial_cs_dl(8) last_mcs(8) demanded_mcs(8) cs_trans(8) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-8 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5172,6 +5346,7 @@ - Sending new block at BSN 3, CS=MCS-8 -- Chunk with length 376 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5186,6 +5361,7 @@ - Sending new block at BSN 5, CS=MCS-8 -- Chunk with length 240 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5200,6 +5376,7 @@ - Sending new block at BSN 7, CS=MCS-8 -- Chunk with length 104 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5217,6 +5394,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=30 data block (BSN 8, MCS-8): 48 3d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5279,6 +5457,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-9): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5288,12 +5467,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(9) last_mcs(6) demanded_mcs(9) cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-9 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5308,6 +5488,7 @@ - Sending new block at BSN 3, CS=MCS-9 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5322,6 +5503,7 @@ - Sending new block at BSN 5, CS=MCS-9 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5339,6 +5521,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-9): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5356,6 +5539,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-9): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5402,11 +5586,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(6) cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5450,11 +5636,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 96 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(1) demanded_mcs(1) cs_trans(1) +- initial_cs_dl(1) last_mcs(1) demanded_mcs(1) cs_trans(1) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 98 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5498,11 +5686,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-2): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 92 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(2) demanded_mcs(2) cs_trans(2) +- initial_cs_dl(2) last_mcs(2) demanded_mcs(2) cs_trans(2) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 94 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5546,6 +5736,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5557,6 +5748,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-5): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5564,10 +5756,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-5): 0f 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7) cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7) cs_trans(7) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-7): 07 00 00 02 c0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 @@ -5612,6 +5805,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5623,6 +5817,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-6): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5630,10 +5825,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-6): 0f 40 00 00 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9) cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9) cs_trans(9) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-9): 07 00 00 02 28 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 @@ -5686,6 +5882,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-7): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5694,13 +5891,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-7): 0f 00 00 02 a0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5) cs_trans(5) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5) cs_trans(5) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-5): 07 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5752,6 +5951,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-9): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5760,13 +5960,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-9): 0f 00 00 02 00 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6) cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6) cs_trans(6) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-6): 07 40 00 02 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5780,3 +5982,233 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-5 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(2) cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 d2 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(2) demanded_mcs(2) cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 f2 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-4 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (44) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-4): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-4): 07 00 00 80 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(4) demanded_mcs(1) cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 d6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(1) demanded_mcs(1) cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 f6 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(6) cs_trans(6) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 2 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..c38417d 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,9 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_egprs_spb_dl === +Testing retx for MCS 6 to reseg_mcs 3 +Testing retx for MCS 5 to reseg_mcs 2 +Testing retx for MCS 4 to reseg_mcs 1 +Testing retx for MCS 6 to reseg_mcs 3 +=== end test_tbf_egprs_spb_dl === -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 18 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Wed Aug 17 13:38:48 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Wed, 17 Aug 2016 13:38:48 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 18: (1 comment) https://gerrit.osmocom.org/#/c/655/18/src/pcu_vty.c File src/pcu_vty.c: Line 495: remove tab -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 18 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Wed Aug 17 13:39:43 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Wed, 17 Aug 2016 13:39:43 +0000 Subject: [PATCH] osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/655 to look at the new patch set (#19). Modify EGPRS DL TBF flow to support SPB Modify the EGPRS DL TBF flow to support Split block during Retx. This patch will also Upgrade the test suite with test cases to validate the EGPRS Downlink SPB for Retransmission Scenarios like MCS6->MCS3, MCS4->MCS1, MCS5->MCS2, MCS9->MCS3 MCS7->MCS2, MCS8->MCS3 have been simulated and Integration tested in NuRAN 1.0 hardware thoroughly. Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 --- M src/gprs_coding_scheme.h M src/pcu_main.cpp M src/pcu_vty.c M src/rlc.cpp M src/rlc.h M src/tbf.h M src/tbf_dl.cpp M tests/edge/EdgeTest.cpp M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 11 files changed, 956 insertions(+), 80 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/55/655/19 diff --git a/src/gprs_coding_scheme.h b/src/gprs_coding_scheme.h index 60a8e79..3b15372 100644 --- a/src/gprs_coding_scheme.h +++ b/src/gprs_coding_scheme.h @@ -113,7 +113,8 @@ static const char *modeName(Mode mode); static Scheme get_retx_mcs(const GprsCodingScheme mcs, - const GprsCodingScheme retx_mcs); + const GprsCodingScheme retx_mcs, + const unsigned arq_type); static enum Scheme egprs_mcs_retx_tbl[MAX_NUM_ARQ] [MAX_NUM_MCS][MAX_NUM_MCS]; @@ -232,8 +233,9 @@ } inline GprsCodingScheme::Scheme GprsCodingScheme::get_retx_mcs( const GprsCodingScheme mcs, - const GprsCodingScheme demanded_mcs) + const GprsCodingScheme demanded_mcs, + const unsigned arq_type) { - return egprs_mcs_retx_tbl[EGPRS_ARQ2][mcs.to_num() - 1] + return egprs_mcs_retx_tbl[arq_type][mcs.to_num() - 1] [demanded_mcs.to_num() - 1]; } diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2d86cda..e34d534 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -210,6 +210,12 @@ bts->dl_tbf_idle_msec = 2000; bts->llc_idle_ack_csec = 10; + /* + * By default resegmentation is supported in DL + * can also be configured through VTY + */ + bts->dl_arq_type = EGPRS_ARQ1; + msgb_set_talloc_ctx(tall_pcu_ctx); osmo_init_logging(&gprs_log_info); diff --git a/src/pcu_vty.c b/src/pcu_vty.c index 58fea99..ecb1f7b 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -129,6 +129,10 @@ vty_out(vty, " window-size %d %d%s", bts->ws_base, bts->ws_pdch, VTY_NEWLINE); + if (bts->dl_arq_type) + vty_out(vty, " dl arq-type %s%s", "arq2", + VTY_NEWLINE); + if (bts->force_llc_lifetime == 0xffff) vty_out(vty, " queue lifetime infinite%s", VTY_NEWLINE); else if (bts->force_llc_lifetime) @@ -476,6 +480,23 @@ bts->max_mcs_dl = 0; bts->max_mcs_ul = 0; + + return CMD_SUCCESS; +} + +DEFUN(cfg_pcu_dl_arq_type, + cfg_pcu_dl_arq_cmd, + "dl arq-type (spb|arq2)", + EGPRS_STR "DL ARQ options\n" + "enable DL SPB(ARQ1) support\n" + "enable DL ARQ2 support") +{ + struct gprs_rlcmac_bts *bts = bts_main_data(); + + if (!strcmp(argv[0], "arq2")) + bts->dl_arq_type = 1; + else + bts->dl_arq_type = 0; return CMD_SUCCESS; } @@ -954,6 +975,7 @@ install_element(PCU_NODE, &cfg_pcu_no_cs_downgrade_thrsh_cmd); install_element(PCU_NODE, &cfg_pcu_cs_lqual_ranges_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_cmd); + install_element(PCU_NODE, &cfg_pcu_dl_arq_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_max_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_max_cmd); diff --git a/src/rlc.cpp b/src/rlc.cpp index 6770043..e69d1fc 100644 --- a/src/rlc.cpp +++ b/src/rlc.cpp @@ -285,7 +285,8 @@ } static void gprs_rlc_data_header_init(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding, unsigned int header_bits) + GprsCodingScheme cs, bool with_padding, unsigned int header_bits, + const unsigned int spb) { unsigned int i; unsigned int padding_bits = with_padding ? cs.optionalPaddingBits() : 0; @@ -300,7 +301,7 @@ for (i = 0; i < rlc->num_data_blocks; i++) { gprs_rlc_data_block_info_init(&rlc->block_info[i], cs, - with_padding); + with_padding, spb); rlc->data_offs_bits[i] = header_bits + padding_bits + @@ -310,21 +311,25 @@ } void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsDL()); + cs.numDataHeaderBitsDL(), spb); } void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding) { + /* + * last parameter is sent as 0 since common function used + * for both DL and UL + */ return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsUL()); + cs.numDataHeaderBitsUL(), 0); } void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { unsigned int data_len = cs.maxDataBlockBytes(); if (with_padding) @@ -336,7 +341,7 @@ rdbi->e = 1; rdbi->cv = 15; rdbi->pi = 0; - rdbi->spb = 0; + rdbi->spb = spb; } unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, @@ -411,8 +416,18 @@ enum egprs_puncturing_values gprs_get_punct_scheme( enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current) + const GprsCodingScheme &cs_current, + const enum egprs_rlcmac_dl_spb spb) { + + /* + * 10.4.8b of TS 44.060 + * If it is second segment of the block + * dont change the puncturing scheme + */ + if (spb == EGPRS_RLCMAC_DL_SEC_SEG) + return punct; + /* TS 44.060 9.3.2.1.1 */ if ((GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS9) && (GprsCodingScheme::Scheme(cs_current) == GprsCodingScheme::MCS6)) { diff --git a/src/rlc.h b/src/rlc.h index b1a1fba..b693418 100644 --- a/src/rlc.h +++ b/src/rlc.h @@ -213,18 +213,19 @@ }; void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding); void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, enum egprs_puncturing_values punct, enum egprs_puncturing_values punct2, int with_padding); void gprs_rlc_mcs_cps_decode(unsigned int cps, GprsCodingScheme cs, int *punct, int *punct2, int *with_padding); enum egprs_puncturing_values gprs_get_punct_scheme(enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current_trans); + const GprsCodingScheme &cs_current_trans, + const enum egprs_rlcmac_dl_spb spb); void gprs_update_punct_scheme(enum egprs_puncturing_values *punct, const GprsCodingScheme &cs); /* diff --git a/src/tbf.h b/src/tbf.h index 1bd7878..2a1bfe8 100644 --- a/src/tbf.h +++ b/src/tbf.h @@ -421,6 +421,11 @@ int analyse_errors(char *show_rbb, uint8_t ssn, ana_result *res); void schedule_next_frame(); + enum egprs_rlc_dl_reseg_bsn_state egprs_dl_get_data + (int bsn, uint8_t **block_data); + unsigned int get_egprs_dl_spb_status(int bsn); + enum egprs_rlcmac_dl_spb get_egprs_dl_spb(int bsn); + struct osmo_timer_list m_llc_timer; }; diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp index 07a747a..a24cc21 100644 --- a/src/tbf_dl.cpp +++ b/src/tbf_dl.cpp @@ -375,21 +375,28 @@ return -1; if (is_egprs_enabled()) { + /* Table 8.1.1.2 and Table 8.1.1.1 of 44.060 */ m_rlc.block(bsn)->cs_current_trans = - GprsCodingScheme::get_retx_mcs( - m_rlc.block(bsn)->cs_last, ms()->current_cs_dl()); + GprsCodingScheme::get_retx_mcs( + m_rlc.block(bsn)->cs_init, + ms()->current_cs_dl(), + bts->bts_data()->dl_arq_type); LOGP(DRLCMACDL, LOGL_DEBUG, - "- current_cs_dl(%d) demanded_mcs(%d) cs_trans(%d)\n", - m_rlc.block(bsn)->cs_last.to_num(), - ms()->current_cs_dl().to_num(), - m_rlc.block(bsn)->cs_current_trans.to_num()); + "- initial_cs_dl(%d) last_mcs(%d)" + " demanded_mcs(%d) cs_trans(%d)" + " arq_type(%d) bsn(%d)\n", + m_rlc.block(bsn)->cs_init.to_num(), + m_rlc.block(bsn)->cs_last.to_num(), + ms()->current_cs_dl().to_num(), + m_rlc.block(bsn)->cs_current_trans.to_num(), + bts->bts_data()->dl_arq_type, bsn); /* TODO: Need to remove this check when MCS-8 -> MCS-6 * transistion is handled. * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 */ - if (m_rlc.block(bsn)->cs_last == GprsCodingScheme::MCS8) + if (m_rlc.block(bsn)->cs_init == GprsCodingScheme::MCS8) m_rlc.block(bsn)->cs_current_trans = GprsCodingScheme::MCS8; } else @@ -523,6 +530,11 @@ data = rlc_data->prepare(block_data_len); rlc_data->cs_last = cs; rlc_data->cs_current_trans = cs; + + /* Initialise the variable related to DL SPB */ + rlc_data->spb_status.block_status_dl = EGPRS_RESEG_DL_DEFAULT; + rlc_data->cs_init = cs; + rlc_data->len = block_data_len; rdbi = &(rlc_data->block_info); @@ -616,7 +628,8 @@ unsigned num_bsns; enum egprs_puncturing_values punct[ARRAY_SIZE(rlc.block_info)]; bool need_padding = false; - + enum egprs_rlcmac_dl_spb spb = EGPRS_RLCMAC_DL_NO_RETX; + unsigned int spb_status = get_egprs_dl_spb_status(index); /* * TODO: This is an experimental work-around to put 2 BSN into * MSC-7 to MCS-9 encoded messages. It just sends the same BSN @@ -626,6 +639,7 @@ * the current limit. */ cs = m_rlc.block(index)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(index)->cs_init; bsns[0] = index; num_bsns = 1; @@ -634,7 +648,17 @@ num_bsns += 1; } - if (num_bsns == 1) { + /* + * if the intial mcs is 8 and retransmission mcs is either 6 or 3 + * we have to include the padding of 6 octets in first segment + */ + if ((GprsCodingScheme::Scheme(cs_init) == GprsCodingScheme::MCS8) && + (GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS6 || + GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS3)) { + if (spb_status == EGPRS_RESEG_DL_DEFAULT || + spb_status == EGPRS_RESEG_SECOND_SEG_SENT) + need_padding = true; + } else if (num_bsns == 1) { /* TODO: remove the conditional when MCS-6 padding isn't * failing to be decoded by MEs anymore */ /* TODO: support of MCS-8 -> MCS-6 transition should be @@ -646,7 +670,14 @@ cs.decToSingleBlock(&need_padding); } - gprs_rlc_data_info_init_dl(&rlc, cs, need_padding); + spb = get_egprs_dl_spb(index); + + LOGP(DRLCMACDL, LOGL_DEBUG, "- need_padding %d spb_status %d spb %d" + "(BSN1 %d BSN2 %d)\n", + need_padding, + spb_status, spb, index, index2); + + gprs_rlc_data_info_init_dl(&rlc, cs, need_padding, spb); rlc.usf = 7; /* will be set at scheduler */ rlc.pr = 0; /* FIXME: power reduction */ @@ -665,10 +696,9 @@ data_block_idx++) { int bsn; - GprsCodingScheme cs_enc; uint8_t *block_data; gprs_rlc_data_block_info *rdbi, *block_info; - enum egprs_puncturing_values punct_scheme; + enum egprs_rlc_dl_reseg_bsn_state reseg_status; /* Check if there are more blocks than BSNs */ if (data_block_idx < num_bsns) @@ -676,38 +706,43 @@ else bsn = bsns[0]; - cs_enc = m_rlc.block(bsn)->cs_current_trans; - /* get data and header from current block */ - block_data = m_rlc.block(bsn)->block; - /* Get current puncturing scheme from block */ - punct_scheme = gprs_get_punct_scheme( + + m_rlc.block(bsn)->next_ps = gprs_get_punct_scheme( m_rlc.block(bsn)->next_ps, - m_rlc.block(bsn)->cs_last, cs); + m_rlc.block(bsn)->cs_last, cs, spb); if (cs.isEgprs()) { - OSMO_ASSERT(punct_scheme >= EGPRS_PS_1); - OSMO_ASSERT(punct_scheme <= EGPRS_PS_3); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps >= EGPRS_PS_1); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps <= EGPRS_PS_3); } - punct[data_block_idx] = punct_scheme; + punct[data_block_idx] = m_rlc.block(bsn)->next_ps; rdbi = &rlc.block_info[data_block_idx]; block_info = &m_rlc.block(bsn)->block_info; - if(rdbi->data_len != m_rlc.block(bsn)->len) { - LOGP(DRLCMACDL, LOGL_ERROR, - "ERROR: Expected len = %d for %s instead of " - "%d in data unit %d (BSN %d, %s)\n", - rdbi->data_len, cs.name(), m_rlc.block(bsn)->len, - data_block_idx, bsn, cs_enc.name()); - OSMO_ASSERT(rdbi->data_len == m_rlc.block(bsn)->len); - } - - /* TODO: Need to handle 2 same bsns - * in header type 1 + /* + * get data and header from current block + * function returns the reseg status */ - gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, - cs); + reseg_status = egprs_dl_get_data(bsn, &block_data); + m_rlc.block(bsn)->spb_status.block_status_dl = reseg_status; + + /* + * If it is first segment of the split block set the state of + * bsn to nacked. If it is the first segment dont update the + * next ps value of bsn. since next segment also needs same cps + */ + if (spb == EGPRS_RLCMAC_DL_FIRST_SEG) + m_window.m_v_b.mark_nacked(bsn); + else { + /* + * TODO: Need to handle 2 same bsns + * in header type 1 + */ + gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, + cs); + } m_rlc.block(bsn)->cs_last = cs; rdbi->e = block_info->e; @@ -1169,3 +1204,118 @@ keep_time_frames = msecs_to_frames(bts_data()->dl_tbf_idle_msec); return frames_since_last_drain(fn) <= keep_time_frames; } + +/* + * This function returns the pointer to data which needs + * to be copied. Also updates the status of the block related to + * Split block handling in the RLC/MAC block. + */ +enum egprs_rlc_dl_reseg_bsn_state + gprs_rlcmac_dl_tbf::egprs_dl_get_data(int bsn, uint8_t **block_data) +{ + gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state *block_status_dl = + &rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + *block_data = &rlc_data->block[0]; + + /* + * Table 10.3a.0.1 of 44.060 + * MCS6,9: second segment starts at 74/2 = 37 + * MCS5,7: second segment starts at 56/2 = 28 + * MCS8: second segment starts at 31 + * MCS4: second segment starts at 44/2 = 22 + */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + if (*block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + switch (GprsCodingScheme::Scheme(cs_init)) { + case GprsCodingScheme::MCS6 : + case GprsCodingScheme::MCS9 : + *block_data = &rlc_data->block[37]; + break; + case GprsCodingScheme::MCS7 : + case GprsCodingScheme::MCS5 : + *block_data = &rlc_data->block[28]; + break; + case GprsCodingScheme::MCS8 : + *block_data = &rlc_data->block[31]; + break; + case GprsCodingScheme::MCS4 : + *block_data = &rlc_data->block[22]; + break; + default: + LOGP(DRLCMACDL, LOGL_ERROR, "Software error: " + "--%s hit invalid condition. headerType(%d) " + " blockstatus(%d) cs(%s) PLEASE FIX!\n", name(), + cs_current_trans.headerTypeData(), + *block_status_dl, cs_init.name()); + break; + + } + return EGPRS_RESEG_SECOND_SEG_SENT; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } + } + return EGPRS_RESEG_DL_DEFAULT; +} + +/* + * This function returns the status of split block + * for RLC/MAC block. + */ +unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_status(const int bsn) +{ + const gprs_rlc_data *rlc_data = m_rlc.block(bsn); + + return rlc_data->spb_status.block_status_dl; +} + +/* + * This function returns the spb value to be sent OTA + * for RLC/MAC block. + */ +enum egprs_rlcmac_dl_spb gprs_rlcmac_dl_tbf::get_egprs_dl_spb(const int bsn) +{ + struct gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state block_status_dl = + rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + + /* Table 10.4.8b.1 of 44.060 */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + /* + * if we are sending the second segment the spb should be 3 + * other wise it should be 2 + */ + if (block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + return EGPRS_RLCMAC_DL_SEC_SEG; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RLCMAC_DL_FIRST_SEG; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RLCMAC_DL_FIRST_SEG; + } + } + /* Non SPB cases 0 is reurned */ + return EGPRS_RLCMAC_DL_NO_RETX; +} diff --git a/tests/edge/EdgeTest.cpp b/tests/edge/EdgeTest.cpp index 807102c..9081d4d 100644 --- a/tests/edge/EdgeTest.cpp +++ b/tests/edge/EdgeTest.cpp @@ -517,7 +517,7 @@ /* TS 44.060, B.1 */ cs = GprsCodingScheme::CS4; - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -570,7 +570,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -592,7 +592,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -630,7 +630,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -669,7 +669,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -694,7 +694,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -719,7 +719,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -740,7 +740,7 @@ OSMO_ASSERT(data[0] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -777,7 +777,7 @@ cs = GprsCodingScheme::MCS4; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -835,7 +835,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -872,7 +872,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -923,7 +923,7 @@ OSMO_ASSERT(data[3] == 0); /* Block 3 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -967,7 +967,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -993,7 +993,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1020,7 +1020,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1074,7 +1074,7 @@ block_idx++) { struct gprs_rlc_data_info rlc; - gprs_rlc_data_info_init_dl(&rlc, cs, false); + gprs_rlc_data_info_init_dl(&rlc, cs, false, 0); memset(bits, pattern, sizeof(bits)); Decoding::rlc_copy_to_aligned_buffer( @@ -1118,12 +1118,14 @@ struct gprs_rlc_data_info rlc; printf("=== start %s ===\n", __func__); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::CS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::CS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 24); OSMO_ASSERT(rlc.block_info[0].data_len == 20); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::MCS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::MCS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 33); OSMO_ASSERT(rlc.block_info[0].data_len == 22); diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..5e45506 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -1814,6 +1814,203 @@ } +static void egprs_spb_to_normal_validation(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + uint16_t bsn1, bsn2, bsn3; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + struct gprs_rlc_dl_header_egprs_2 *egprs2; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + if (!(mcs == 6 && demanded_mcs == 3)) + return; + + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + bsn1 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) + || (egprs2->bsn1_lo); + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(bsn1 == 0); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + bsn2 = (egprs3->bsn1_hi << 9) || (egprs3->bsn1_mid << 1) || + (egprs3->bsn1_lo); + OSMO_ASSERT(bsn2 == bsn1); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Handle (MCS3, MCS3) -> MCS6 case */ + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + mcs)); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs2->cps == 0); + bsn3 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) || + (egprs2->bsn1_lo); + OSMO_ASSERT(bsn3 == bsn2); + + tbf_cleanup(dl_tbf); +} +static void establish_and_use_egprs_dl_tbf_for_spb(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + /* TODO: Need to support of MCS8 -> MCS6 ->MCS3 transistion + * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 + * dated 2016-02-07 23:45:40 (UTC) + */ + if (!(((mcs == 5) && (demanded_mcs == 2)) || + ((mcs == 6) && (demanded_mcs == 3)) || + ((mcs == 4) && (demanded_mcs == 1)))) + return; + + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + tbf_cleanup(dl_tbf); +} + static void establish_and_use_egprs_dl_tbf_for_retx(BTS *the_bts, int mcs, int demanded_mcs) { @@ -1972,6 +2169,9 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; + /* First parameter is current MCS, second one is demanded_mcs */ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 6); @@ -1981,6 +2181,38 @@ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 9); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 7, 5); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 9, 6); + + printf("=== end %s ===\n", __func__); +} + +static void test_tbf_egprs_spb_dl(void) +{ + BTS the_bts; + gprs_rlcmac_bts *bts; + uint8_t ts_no = 4; + int i, j; + + printf("=== start %s ===\n", __func__); + + bts = the_bts.bts_data(); + bts->cs_downgrade_threshold = 0; + setup_bts(&the_bts, ts_no); + bts->dl_tbf_idle_msec = 200; + bts->egprs_enabled = 1; + + /* ARQ I resegmentation support */ + bts->dl_arq_type = EGPRS_ARQ1; + + /* + * First parameter is current MCS, second one is demanded_mcs + * currently only MCS5->MCS2, MCS6->3, MCS4->MCS1 is tested in UT + * rest scenarios has been integration tested + */ + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 6, 3); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 5, 2); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 4, 1); + /* check MCS6->(MCS3+MCS3)->MCS6 case */ + egprs_spb_to_normal_validation(&the_bts, 6, 3); printf("=== end %s ===\n", __func__); } @@ -1999,6 +2231,8 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; for (i = 1; i <= 9; i++) establish_and_use_egprs_dl_tbf(&the_bts, i); @@ -2071,6 +2305,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_egprs_spb_dl(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..1ba4189 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -72,6 +72,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -81,6 +82,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -157,6 +159,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -166,6 +169,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -242,6 +246,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -251,6 +256,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -259,6 +265,7 @@ - Sending new block at BSN 2, CS=CS-1 -- Chunk with length 160 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=13 block=3 data=07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b @@ -267,6 +274,7 @@ - Sending new block at BSN 3, CS=CS-1 -- Chunk with length 140 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=17 block=4 data=07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @@ -275,6 +283,7 @@ - Sending new block at BSN 4, CS=CS-1 -- Chunk with length 120 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=21 block=5 data=07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 @@ -283,6 +292,7 @@ - Sending new block at BSN 5, CS=CS-1 -- Chunk with length 100 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=26 block=6 data=07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 @@ -291,6 +301,7 @@ - Sending new block at BSN 6, CS=CS-1 -- Chunk with length 80 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=30 block=7 data=07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b @@ -299,6 +310,7 @@ - Sending new block at BSN 7, CS=CS-1 -- Chunk with length 60 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=34 block=8 data=07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f @@ -307,6 +319,7 @@ - Sending new block at BSN 8, CS=CS-1 -- Chunk with length 40 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=39 block=9 data=07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 @@ -315,6 +328,7 @@ - Sending new block at BSN 9, CS=CS-1 -- Chunk with length 20 would exactly fit into space (20): add length header with LI=0, to make frame extend to next block, and we are done data block (BSN 9, CS-1): 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=43 block=10 data=07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 @@ -326,6 +340,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=47 block=11 data=07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 @@ -334,6 +349,7 @@ - Sending new block at BSN 11, CS=CS-1 -- Chunk with length 182 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=52 block=0 data=07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 @@ -342,6 +358,7 @@ - Sending new block at BSN 12, CS=CS-1 -- Chunk with length 162 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=56 block=1 data=07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 @@ -350,6 +367,7 @@ - Sending new block at BSN 13, CS=CS-1 -- Chunk with length 142 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 13, CS-1): 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=60 block=2 data=07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d @@ -358,6 +376,7 @@ - Sending new block at BSN 14, CS=CS-1 -- Chunk with length 122 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=65 block=3 data=07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 @@ -366,6 +385,7 @@ - Sending new block at BSN 15, CS=CS-1 -- Chunk with length 102 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=69 block=4 data=07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 @@ -374,6 +394,7 @@ - Sending new block at BSN 16, CS=CS-1 -- Chunk with length 82 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=73 block=5 data=07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 @@ -382,6 +403,7 @@ - Sending new block at BSN 17, CS=CS-1 -- Chunk with length 62 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=78 block=6 data=07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d @@ -390,6 +412,7 @@ - Sending new block at BSN 18, CS=CS-1 -- Chunk with length 42 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=82 block=7 data=07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 @@ -398,6 +421,7 @@ - Sending new block at BSN 19, CS=CS-1 -- Chunk with length 22 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=86 block=8 data=07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 @@ -411,6 +435,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=16 data block (BSN 20, CS-1): 0a 41 c6 c7 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -449,6 +474,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 data block (BSN 21, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -468,6 +494,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 22, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FINISHED) @@ -1481,6 +1508,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 0, CS-1): 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 MSG = 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 @@ -1491,6 +1519,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 1, CS-1): 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 MSG = 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 @@ -1501,6 +1530,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FINISHED data block (BSN 2, CS-1): 4d 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling cannot be scheduled in this TS 7 (first control TS 4) @@ -1784,6 +1814,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=10 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 0, CS-4): 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654292 TS 7 @@ -1797,6 +1828,7 @@ TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) downlink (V(A)==0 .. V(S)==1) - Restarting at BSN 0, because all blocks have been transmitted. - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-4): 07 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 @@ -2365,6 +2397,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654279 block=10 data=00 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 @@ -2384,6 +2417,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -2406,6 +2440,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654288 block=0 data=00 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 @@ -2425,6 +2460,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654292 block=1 data=00 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2447,6 +2483,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654296 block=2 data=00 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c @@ -2466,6 +2503,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654301 block=3 data=00 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b @@ -2488,6 +2526,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 6, CS-1): 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654305 block=4 data=00 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 @@ -2507,6 +2546,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654309 block=5 data=00 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 @@ -2526,6 +2566,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654314 block=6 data=00 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 @@ -2548,6 +2589,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654318 block=7 data=00 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 @@ -2567,6 +2609,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654322 block=8 data=00 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2589,6 +2632,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654327 block=9 data=00 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c @@ -2608,6 +2652,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654331 block=10 data=00 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b @@ -2630,6 +2675,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 13, CS-1): 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654335 block=11 data=00 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 @@ -2649,6 +2695,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654340 block=0 data=00 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 @@ -2668,6 +2715,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654344 block=1 data=00 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 @@ -2690,6 +2738,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654348 block=2 data=00 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 @@ -2709,6 +2758,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654353 block=3 data=00 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2731,6 +2781,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654357 block=4 data=00 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c @@ -2750,6 +2801,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654361 block=5 data=00 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b @@ -2772,6 +2824,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 20, CS-1): 16 35 45 54 20 32 38 4c 4c 43 20 50 41 43 4b 45 54 20 32 39 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because 20 blocks sent. TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW): Scheduling polling at FN 2654379 TS 7 @@ -2795,6 +2848,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 21, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) msg block (BSN 21, CS-1): 07 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654370 block=7 data=00 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 @@ -2814,6 +2868,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 22, CS-1): 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) msg block (BSN 22, CS-1): 07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654374 block=8 data=07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 @@ -2836,6 +2891,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 23, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) msg block (BSN 23, CS-1): 07 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654379 block=9 data=00 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 @@ -2855,6 +2911,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 24, CS-1): 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) msg block (BSN 24, CS-1): 07 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654383 block=10 data=00 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2877,6 +2934,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 25, CS-1): 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 25 BSN2 -1) - Copying data unit 0 (BSN 25) msg block (BSN 25, CS-1): 07 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654387 block=11 data=00 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c @@ -2896,6 +2954,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 26, CS-1): 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 26 BSN2 -1) - Copying data unit 0 (BSN 26) msg block (BSN 26, CS-1): 07 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654392 block=0 data=00 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b @@ -2918,6 +2977,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 27, CS-1): 16 35 45 54 20 33 38 4c 4c 43 20 50 41 43 4b 45 54 20 33 39 +- need_padding 0 spb_status 0 spb 0(BSN1 27 BSN2 -1) - Copying data unit 0 (BSN 27) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) @@ -3028,6 +3088,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654405 block=3 data=00 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 @@ -3047,6 +3108,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654409 block=4 data=00 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 @@ -3066,6 +3128,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (16) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654413 block=5 data=00 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 @@ -3085,6 +3148,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (14) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654418 block=6 data=00 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 @@ -3104,6 +3168,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654422 block=7 data=00 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -3123,6 +3188,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654426 block=8 data=00 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 @@ -3142,6 +3208,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654431 block=9 data=00 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b @@ -3161,6 +3228,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654435 block=10 data=00 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 @@ -3180,6 +3248,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654439 block=11 data=00 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 @@ -3199,6 +3268,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654444 block=0 data=00 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c @@ -3218,6 +3288,7 @@ Complete DL frame for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=21 TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 10, CS-1): 4d 43 20 50 41 43 4b 45 54 20 30 39 20 28 54 42 46 20 32 29 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654461 TS 7 @@ -3698,6 +3769,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 0, MCS-1): 14 15 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3711,6 +3783,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3721,6 +3794,7 @@ - Sending new block at BSN 2, CS=MCS-1 -- Chunk with length 490 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3731,6 +3805,7 @@ - Sending new block at BSN 3, CS=MCS-1 -- Chunk with length 468 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3741,6 +3816,7 @@ - Sending new block at BSN 4, CS=MCS-1 -- Chunk with length 446 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3751,6 +3827,7 @@ - Sending new block at BSN 5, CS=MCS-1 -- Chunk with length 424 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3761,6 +3838,7 @@ - Sending new block at BSN 6, CS=MCS-1 -- Chunk with length 402 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3771,6 +3849,7 @@ - Sending new block at BSN 7, CS=MCS-1 -- Chunk with length 380 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3781,6 +3860,7 @@ - Sending new block at BSN 8, CS=MCS-1 -- Chunk with length 358 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3791,6 +3871,7 @@ - Sending new block at BSN 9, CS=MCS-1 -- Chunk with length 336 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3801,6 +3882,7 @@ - Sending new block at BSN 10, CS=MCS-1 -- Chunk with length 314 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3811,6 +3893,7 @@ - Sending new block at BSN 11, CS=MCS-1 -- Chunk with length 292 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3821,6 +3904,7 @@ - Sending new block at BSN 12, CS=MCS-1 -- Chunk with length 270 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3831,6 +3915,7 @@ - Sending new block at BSN 13, CS=MCS-1 -- Chunk with length 248 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3841,6 +3926,7 @@ - Sending new block at BSN 14, CS=MCS-1 -- Chunk with length 226 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3851,6 +3937,7 @@ - Sending new block at BSN 15, CS=MCS-1 -- Chunk with length 204 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3861,6 +3948,7 @@ - Sending new block at BSN 16, CS=MCS-1 -- Chunk with length 182 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3871,6 +3959,7 @@ - Sending new block at BSN 17, CS=MCS-1 -- Chunk with length 160 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3881,6 +3970,7 @@ - Sending new block at BSN 18, CS=MCS-1 -- Chunk with length 138 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3891,6 +3981,7 @@ - Sending new block at BSN 19, CS=MCS-1 -- Chunk with length 116 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 19, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3901,6 +3992,7 @@ - Sending new block at BSN 20, CS=MCS-1 -- Chunk with length 94 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 20, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3911,6 +4003,7 @@ - Sending new block at BSN 21, CS=MCS-1 -- Chunk with length 72 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 21, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3921,6 +4014,7 @@ - Sending new block at BSN 22, CS=MCS-1 -- Chunk with length 50 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 22, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3931,6 +4025,7 @@ - Sending new block at BSN 23, CS=MCS-1 -- Chunk with length 28 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 23, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3946,6 +4041,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 24, MCS-1): 0c 1d 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4006,6 +4102,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=16 data block (BSN 0, MCS-2): 14 21 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4019,6 +4116,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4029,6 +4127,7 @@ - Sending new block at BSN 2, CS=MCS-2 -- Chunk with length 484 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4039,6 +4138,7 @@ - Sending new block at BSN 3, CS=MCS-2 -- Chunk with length 456 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4049,6 +4149,7 @@ - Sending new block at BSN 4, CS=MCS-2 -- Chunk with length 428 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4059,6 +4160,7 @@ - Sending new block at BSN 5, CS=MCS-2 -- Chunk with length 400 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4069,6 +4171,7 @@ - Sending new block at BSN 6, CS=MCS-2 -- Chunk with length 372 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4079,6 +4182,7 @@ - Sending new block at BSN 7, CS=MCS-2 -- Chunk with length 344 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4089,6 +4193,7 @@ - Sending new block at BSN 8, CS=MCS-2 -- Chunk with length 316 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4099,6 +4204,7 @@ - Sending new block at BSN 9, CS=MCS-2 -- Chunk with length 288 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4109,6 +4215,7 @@ - Sending new block at BSN 10, CS=MCS-2 -- Chunk with length 260 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4119,6 +4226,7 @@ - Sending new block at BSN 11, CS=MCS-2 -- Chunk with length 232 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4129,6 +4237,7 @@ - Sending new block at BSN 12, CS=MCS-2 -- Chunk with length 204 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4139,6 +4248,7 @@ - Sending new block at BSN 13, CS=MCS-2 -- Chunk with length 176 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4149,6 +4259,7 @@ - Sending new block at BSN 14, CS=MCS-2 -- Chunk with length 148 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4159,6 +4270,7 @@ - Sending new block at BSN 15, CS=MCS-2 -- Chunk with length 120 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4169,6 +4281,7 @@ - Sending new block at BSN 16, CS=MCS-2 -- Chunk with length 92 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4179,6 +4292,7 @@ - Sending new block at BSN 17, CS=MCS-2 -- Chunk with length 64 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4189,6 +4303,7 @@ - Sending new block at BSN 18, CS=MCS-2 -- Chunk with length 36 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4204,6 +4319,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=18 data block (BSN 19, MCS-2): 10 25 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4264,6 +4380,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=25 data block (BSN 0, MCS-3): 14 33 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4277,6 +4394,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4287,6 +4405,7 @@ - Sending new block at BSN 2, CS=MCS-3 -- Chunk with length 475 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4297,6 +4416,7 @@ - Sending new block at BSN 3, CS=MCS-3 -- Chunk with length 438 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4307,6 +4427,7 @@ - Sending new block at BSN 4, CS=MCS-3 -- Chunk with length 401 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4317,6 +4438,7 @@ - Sending new block at BSN 5, CS=MCS-3 -- Chunk with length 364 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4327,6 +4449,7 @@ - Sending new block at BSN 6, CS=MCS-3 -- Chunk with length 327 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4337,6 +4460,7 @@ - Sending new block at BSN 7, CS=MCS-3 -- Chunk with length 290 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4347,6 +4471,7 @@ - Sending new block at BSN 8, CS=MCS-3 -- Chunk with length 253 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4357,6 +4482,7 @@ - Sending new block at BSN 9, CS=MCS-3 -- Chunk with length 216 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4367,6 +4493,7 @@ - Sending new block at BSN 10, CS=MCS-3 -- Chunk with length 179 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4377,6 +4504,7 @@ - Sending new block at BSN 11, CS=MCS-3 -- Chunk with length 142 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4387,6 +4515,7 @@ - Sending new block at BSN 12, CS=MCS-3 -- Chunk with length 105 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4397,6 +4526,7 @@ - Sending new block at BSN 13, CS=MCS-3 -- Chunk with length 68 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4410,6 +4540,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-3): 3f 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4425,6 +4556,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=34 data block (BSN 15, MCS-3): 02 45 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4485,6 +4617,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=32 data block (BSN 0, MCS-4): 14 41 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4498,6 +4631,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4508,6 +4642,7 @@ - Sending new block at BSN 2, CS=MCS-4 -- Chunk with length 468 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4518,6 +4653,7 @@ - Sending new block at BSN 3, CS=MCS-4 -- Chunk with length 424 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4528,6 +4664,7 @@ - Sending new block at BSN 4, CS=MCS-4 -- Chunk with length 380 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4538,6 +4675,7 @@ - Sending new block at BSN 5, CS=MCS-4 -- Chunk with length 336 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4548,6 +4686,7 @@ - Sending new block at BSN 6, CS=MCS-4 -- Chunk with length 292 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4558,6 +4697,7 @@ - Sending new block at BSN 7, CS=MCS-4 -- Chunk with length 248 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4568,6 +4708,7 @@ - Sending new block at BSN 8, CS=MCS-4 -- Chunk with length 204 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4578,6 +4719,7 @@ - Sending new block at BSN 9, CS=MCS-4 -- Chunk with length 160 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4588,6 +4730,7 @@ - Sending new block at BSN 10, CS=MCS-4 -- Chunk with length 116 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4598,6 +4741,7 @@ - Sending new block at BSN 11, CS=MCS-4 -- Chunk with length 72 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4613,6 +4757,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 12, MCS-4): 38 1d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4673,6 +4818,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-5): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4686,6 +4832,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4696,6 +4843,7 @@ - Sending new block at BSN 2, CS=MCS-5 -- Chunk with length 456 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4706,6 +4854,7 @@ - Sending new block at BSN 3, CS=MCS-5 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4716,6 +4865,7 @@ - Sending new block at BSN 4, CS=MCS-5 -- Chunk with length 344 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4726,6 +4876,7 @@ - Sending new block at BSN 5, CS=MCS-5 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4736,6 +4887,7 @@ - Sending new block at BSN 6, CS=MCS-5 -- Chunk with length 232 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4746,6 +4898,7 @@ - Sending new block at BSN 7, CS=MCS-5 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4756,6 +4909,7 @@ - Sending new block at BSN 8, CS=MCS-5 -- Chunk with length 120 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4766,6 +4920,7 @@ - Sending new block at BSN 9, CS=MCS-5 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4781,6 +4936,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-5): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4841,6 +4997,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-6): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4854,6 +5011,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4864,6 +5022,7 @@ - Sending new block at BSN 2, CS=MCS-6 -- Chunk with length 438 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4874,6 +5033,7 @@ - Sending new block at BSN 3, CS=MCS-6 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4884,6 +5044,7 @@ - Sending new block at BSN 4, CS=MCS-6 -- Chunk with length 290 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4894,6 +5055,7 @@ - Sending new block at BSN 5, CS=MCS-6 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4904,6 +5066,7 @@ - Sending new block at BSN 6, CS=MCS-6 -- Chunk with length 142 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4917,6 +5080,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-6): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4932,6 +5096,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-6): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4993,6 +5158,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-7): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5002,12 +5168,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(7) last_mcs(5) demanded_mcs(7) cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-7 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5022,6 +5189,7 @@ - Sending new block at BSN 3, CS=MCS-7 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5036,6 +5204,7 @@ - Sending new block at BSN 5, CS=MCS-7 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5050,6 +5219,7 @@ - Sending new block at BSN 7, CS=MCS-7 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5064,6 +5234,7 @@ - Sending new block at BSN 9, CS=MCS-7 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 9) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5081,6 +5252,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-7): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5142,6 +5314,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=56 data block (BSN 0, MCS-8): 14 71 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5152,12 +5325,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(8) demanded_mcs(8) cs_trans(8) +- initial_cs_dl(8) last_mcs(8) demanded_mcs(8) cs_trans(8) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-8 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5172,6 +5346,7 @@ - Sending new block at BSN 3, CS=MCS-8 -- Chunk with length 376 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5186,6 +5361,7 @@ - Sending new block at BSN 5, CS=MCS-8 -- Chunk with length 240 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5200,6 +5376,7 @@ - Sending new block at BSN 7, CS=MCS-8 -- Chunk with length 104 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5217,6 +5394,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=30 data block (BSN 8, MCS-8): 48 3d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5279,6 +5457,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-9): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5288,12 +5467,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(9) last_mcs(6) demanded_mcs(9) cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-9 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5308,6 +5488,7 @@ - Sending new block at BSN 3, CS=MCS-9 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5322,6 +5503,7 @@ - Sending new block at BSN 5, CS=MCS-9 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5339,6 +5521,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-9): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5356,6 +5539,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-9): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5402,11 +5586,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(6) cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5450,11 +5636,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 96 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(1) demanded_mcs(1) cs_trans(1) +- initial_cs_dl(1) last_mcs(1) demanded_mcs(1) cs_trans(1) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 98 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5498,11 +5686,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-2): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 92 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(2) demanded_mcs(2) cs_trans(2) +- initial_cs_dl(2) last_mcs(2) demanded_mcs(2) cs_trans(2) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 94 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5546,6 +5736,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5557,6 +5748,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-5): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5564,10 +5756,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-5): 0f 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7) cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7) cs_trans(7) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-7): 07 00 00 02 c0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 @@ -5612,6 +5805,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5623,6 +5817,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-6): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5630,10 +5825,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-6): 0f 40 00 00 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9) cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9) cs_trans(9) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-9): 07 00 00 02 28 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 @@ -5686,6 +5882,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-7): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5694,13 +5891,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-7): 0f 00 00 02 a0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5) cs_trans(5) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5) cs_trans(5) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-5): 07 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5752,6 +5951,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-9): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5760,13 +5960,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-9): 0f 00 00 02 00 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6) cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6) cs_trans(6) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-6): 07 40 00 02 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5780,3 +5982,233 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-5 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(2) cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 d2 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(2) demanded_mcs(2) cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 f2 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-4 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (44) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-4): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-4): 07 00 00 80 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(4) demanded_mcs(1) cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 d6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(1) demanded_mcs(1) cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 f6 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(6) cs_trans(6) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 2 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..c38417d 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,9 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_egprs_spb_dl === +Testing retx for MCS 6 to reseg_mcs 3 +Testing retx for MCS 5 to reseg_mcs 2 +Testing retx for MCS 4 to reseg_mcs 1 +Testing retx for MCS 6 to reseg_mcs 3 +=== end test_tbf_egprs_spb_dl === -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 19 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Wed Aug 17 13:54:50 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Wed, 17 Aug 2016 13:54:50 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 19: (1 comment) https://gerrit.osmocom.org/#/c/655/19/src/pcu_vty.c File src/pcu_vty.c: Line 493: { fix here -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 19 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Wed Aug 17 13:56:34 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Wed, 17 Aug 2016 13:56:34 +0000 Subject: [PATCH] osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/655 to look at the new patch set (#20). Modify EGPRS DL TBF flow to support SPB Modify the EGPRS DL TBF flow to support Split block during Retx. This patch will also Upgrade the test suite with test cases to validate the EGPRS Downlink SPB for Retransmission Scenarios like MCS6->MCS3, MCS4->MCS1, MCS5->MCS2, MCS9->MCS3 MCS7->MCS2, MCS8->MCS3 have been simulated and Integration tested in NuRAN 1.0 hardware thoroughly. Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 --- M src/gprs_coding_scheme.h M src/pcu_main.cpp M src/pcu_vty.c M src/rlc.cpp M src/rlc.h M src/tbf.h M src/tbf_dl.cpp M tests/edge/EdgeTest.cpp M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 11 files changed, 958 insertions(+), 80 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/55/655/20 diff --git a/src/gprs_coding_scheme.h b/src/gprs_coding_scheme.h index 60a8e79..3b15372 100644 --- a/src/gprs_coding_scheme.h +++ b/src/gprs_coding_scheme.h @@ -113,7 +113,8 @@ static const char *modeName(Mode mode); static Scheme get_retx_mcs(const GprsCodingScheme mcs, - const GprsCodingScheme retx_mcs); + const GprsCodingScheme retx_mcs, + const unsigned arq_type); static enum Scheme egprs_mcs_retx_tbl[MAX_NUM_ARQ] [MAX_NUM_MCS][MAX_NUM_MCS]; @@ -232,8 +233,9 @@ } inline GprsCodingScheme::Scheme GprsCodingScheme::get_retx_mcs( const GprsCodingScheme mcs, - const GprsCodingScheme demanded_mcs) + const GprsCodingScheme demanded_mcs, + const unsigned arq_type) { - return egprs_mcs_retx_tbl[EGPRS_ARQ2][mcs.to_num() - 1] + return egprs_mcs_retx_tbl[arq_type][mcs.to_num() - 1] [demanded_mcs.to_num() - 1]; } diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2d86cda..e34d534 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -210,6 +210,12 @@ bts->dl_tbf_idle_msec = 2000; bts->llc_idle_ack_csec = 10; + /* + * By default resegmentation is supported in DL + * can also be configured through VTY + */ + bts->dl_arq_type = EGPRS_ARQ1; + msgb_set_talloc_ctx(tall_pcu_ctx); osmo_init_logging(&gprs_log_info); diff --git a/src/pcu_vty.c b/src/pcu_vty.c index 58fea99..8cc8bec 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -129,6 +129,10 @@ vty_out(vty, " window-size %d %d%s", bts->ws_base, bts->ws_pdch, VTY_NEWLINE); + if (bts->dl_arq_type) + vty_out(vty, " dl arq-type %s%s", "arq2", + VTY_NEWLINE); + if (bts->force_llc_lifetime == 0xffff) vty_out(vty, " queue lifetime infinite%s", VTY_NEWLINE); else if (bts->force_llc_lifetime) @@ -476,6 +480,25 @@ bts->max_mcs_dl = 0; bts->max_mcs_ul = 0; + + return CMD_SUCCESS; +} + +#define DL_STR "DL (EGPRS)\n" + +DEFUN(cfg_pcu_dl_arq_type, + cfg_pcu_dl_arq_cmd, + "dl arq-type (spb|arq2)", + DL_STR "ARQ options\n" + "enable DL SPB(ARQ1) support\n" + "enable DL ARQ2 support") +{ + struct gprs_rlcmac_bts *bts = bts_main_data(); + + if (!strcmp(argv[0], "arq2")) + bts->dl_arq_type = 1; + else + bts->dl_arq_type = 0; return CMD_SUCCESS; } @@ -954,6 +977,7 @@ install_element(PCU_NODE, &cfg_pcu_no_cs_downgrade_thrsh_cmd); install_element(PCU_NODE, &cfg_pcu_cs_lqual_ranges_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_cmd); + install_element(PCU_NODE, &cfg_pcu_dl_arq_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_max_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_max_cmd); diff --git a/src/rlc.cpp b/src/rlc.cpp index 6770043..e69d1fc 100644 --- a/src/rlc.cpp +++ b/src/rlc.cpp @@ -285,7 +285,8 @@ } static void gprs_rlc_data_header_init(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding, unsigned int header_bits) + GprsCodingScheme cs, bool with_padding, unsigned int header_bits, + const unsigned int spb) { unsigned int i; unsigned int padding_bits = with_padding ? cs.optionalPaddingBits() : 0; @@ -300,7 +301,7 @@ for (i = 0; i < rlc->num_data_blocks; i++) { gprs_rlc_data_block_info_init(&rlc->block_info[i], cs, - with_padding); + with_padding, spb); rlc->data_offs_bits[i] = header_bits + padding_bits + @@ -310,21 +311,25 @@ } void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsDL()); + cs.numDataHeaderBitsDL(), spb); } void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding) { + /* + * last parameter is sent as 0 since common function used + * for both DL and UL + */ return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsUL()); + cs.numDataHeaderBitsUL(), 0); } void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { unsigned int data_len = cs.maxDataBlockBytes(); if (with_padding) @@ -336,7 +341,7 @@ rdbi->e = 1; rdbi->cv = 15; rdbi->pi = 0; - rdbi->spb = 0; + rdbi->spb = spb; } unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, @@ -411,8 +416,18 @@ enum egprs_puncturing_values gprs_get_punct_scheme( enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current) + const GprsCodingScheme &cs_current, + const enum egprs_rlcmac_dl_spb spb) { + + /* + * 10.4.8b of TS 44.060 + * If it is second segment of the block + * dont change the puncturing scheme + */ + if (spb == EGPRS_RLCMAC_DL_SEC_SEG) + return punct; + /* TS 44.060 9.3.2.1.1 */ if ((GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS9) && (GprsCodingScheme::Scheme(cs_current) == GprsCodingScheme::MCS6)) { diff --git a/src/rlc.h b/src/rlc.h index b1a1fba..b693418 100644 --- a/src/rlc.h +++ b/src/rlc.h @@ -213,18 +213,19 @@ }; void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding); void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, enum egprs_puncturing_values punct, enum egprs_puncturing_values punct2, int with_padding); void gprs_rlc_mcs_cps_decode(unsigned int cps, GprsCodingScheme cs, int *punct, int *punct2, int *with_padding); enum egprs_puncturing_values gprs_get_punct_scheme(enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current_trans); + const GprsCodingScheme &cs_current_trans, + const enum egprs_rlcmac_dl_spb spb); void gprs_update_punct_scheme(enum egprs_puncturing_values *punct, const GprsCodingScheme &cs); /* diff --git a/src/tbf.h b/src/tbf.h index 1bd7878..2a1bfe8 100644 --- a/src/tbf.h +++ b/src/tbf.h @@ -421,6 +421,11 @@ int analyse_errors(char *show_rbb, uint8_t ssn, ana_result *res); void schedule_next_frame(); + enum egprs_rlc_dl_reseg_bsn_state egprs_dl_get_data + (int bsn, uint8_t **block_data); + unsigned int get_egprs_dl_spb_status(int bsn); + enum egprs_rlcmac_dl_spb get_egprs_dl_spb(int bsn); + struct osmo_timer_list m_llc_timer; }; diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp index 07a747a..a24cc21 100644 --- a/src/tbf_dl.cpp +++ b/src/tbf_dl.cpp @@ -375,21 +375,28 @@ return -1; if (is_egprs_enabled()) { + /* Table 8.1.1.2 and Table 8.1.1.1 of 44.060 */ m_rlc.block(bsn)->cs_current_trans = - GprsCodingScheme::get_retx_mcs( - m_rlc.block(bsn)->cs_last, ms()->current_cs_dl()); + GprsCodingScheme::get_retx_mcs( + m_rlc.block(bsn)->cs_init, + ms()->current_cs_dl(), + bts->bts_data()->dl_arq_type); LOGP(DRLCMACDL, LOGL_DEBUG, - "- current_cs_dl(%d) demanded_mcs(%d) cs_trans(%d)\n", - m_rlc.block(bsn)->cs_last.to_num(), - ms()->current_cs_dl().to_num(), - m_rlc.block(bsn)->cs_current_trans.to_num()); + "- initial_cs_dl(%d) last_mcs(%d)" + " demanded_mcs(%d) cs_trans(%d)" + " arq_type(%d) bsn(%d)\n", + m_rlc.block(bsn)->cs_init.to_num(), + m_rlc.block(bsn)->cs_last.to_num(), + ms()->current_cs_dl().to_num(), + m_rlc.block(bsn)->cs_current_trans.to_num(), + bts->bts_data()->dl_arq_type, bsn); /* TODO: Need to remove this check when MCS-8 -> MCS-6 * transistion is handled. * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 */ - if (m_rlc.block(bsn)->cs_last == GprsCodingScheme::MCS8) + if (m_rlc.block(bsn)->cs_init == GprsCodingScheme::MCS8) m_rlc.block(bsn)->cs_current_trans = GprsCodingScheme::MCS8; } else @@ -523,6 +530,11 @@ data = rlc_data->prepare(block_data_len); rlc_data->cs_last = cs; rlc_data->cs_current_trans = cs; + + /* Initialise the variable related to DL SPB */ + rlc_data->spb_status.block_status_dl = EGPRS_RESEG_DL_DEFAULT; + rlc_data->cs_init = cs; + rlc_data->len = block_data_len; rdbi = &(rlc_data->block_info); @@ -616,7 +628,8 @@ unsigned num_bsns; enum egprs_puncturing_values punct[ARRAY_SIZE(rlc.block_info)]; bool need_padding = false; - + enum egprs_rlcmac_dl_spb spb = EGPRS_RLCMAC_DL_NO_RETX; + unsigned int spb_status = get_egprs_dl_spb_status(index); /* * TODO: This is an experimental work-around to put 2 BSN into * MSC-7 to MCS-9 encoded messages. It just sends the same BSN @@ -626,6 +639,7 @@ * the current limit. */ cs = m_rlc.block(index)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(index)->cs_init; bsns[0] = index; num_bsns = 1; @@ -634,7 +648,17 @@ num_bsns += 1; } - if (num_bsns == 1) { + /* + * if the intial mcs is 8 and retransmission mcs is either 6 or 3 + * we have to include the padding of 6 octets in first segment + */ + if ((GprsCodingScheme::Scheme(cs_init) == GprsCodingScheme::MCS8) && + (GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS6 || + GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS3)) { + if (spb_status == EGPRS_RESEG_DL_DEFAULT || + spb_status == EGPRS_RESEG_SECOND_SEG_SENT) + need_padding = true; + } else if (num_bsns == 1) { /* TODO: remove the conditional when MCS-6 padding isn't * failing to be decoded by MEs anymore */ /* TODO: support of MCS-8 -> MCS-6 transition should be @@ -646,7 +670,14 @@ cs.decToSingleBlock(&need_padding); } - gprs_rlc_data_info_init_dl(&rlc, cs, need_padding); + spb = get_egprs_dl_spb(index); + + LOGP(DRLCMACDL, LOGL_DEBUG, "- need_padding %d spb_status %d spb %d" + "(BSN1 %d BSN2 %d)\n", + need_padding, + spb_status, spb, index, index2); + + gprs_rlc_data_info_init_dl(&rlc, cs, need_padding, spb); rlc.usf = 7; /* will be set at scheduler */ rlc.pr = 0; /* FIXME: power reduction */ @@ -665,10 +696,9 @@ data_block_idx++) { int bsn; - GprsCodingScheme cs_enc; uint8_t *block_data; gprs_rlc_data_block_info *rdbi, *block_info; - enum egprs_puncturing_values punct_scheme; + enum egprs_rlc_dl_reseg_bsn_state reseg_status; /* Check if there are more blocks than BSNs */ if (data_block_idx < num_bsns) @@ -676,38 +706,43 @@ else bsn = bsns[0]; - cs_enc = m_rlc.block(bsn)->cs_current_trans; - /* get data and header from current block */ - block_data = m_rlc.block(bsn)->block; - /* Get current puncturing scheme from block */ - punct_scheme = gprs_get_punct_scheme( + + m_rlc.block(bsn)->next_ps = gprs_get_punct_scheme( m_rlc.block(bsn)->next_ps, - m_rlc.block(bsn)->cs_last, cs); + m_rlc.block(bsn)->cs_last, cs, spb); if (cs.isEgprs()) { - OSMO_ASSERT(punct_scheme >= EGPRS_PS_1); - OSMO_ASSERT(punct_scheme <= EGPRS_PS_3); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps >= EGPRS_PS_1); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps <= EGPRS_PS_3); } - punct[data_block_idx] = punct_scheme; + punct[data_block_idx] = m_rlc.block(bsn)->next_ps; rdbi = &rlc.block_info[data_block_idx]; block_info = &m_rlc.block(bsn)->block_info; - if(rdbi->data_len != m_rlc.block(bsn)->len) { - LOGP(DRLCMACDL, LOGL_ERROR, - "ERROR: Expected len = %d for %s instead of " - "%d in data unit %d (BSN %d, %s)\n", - rdbi->data_len, cs.name(), m_rlc.block(bsn)->len, - data_block_idx, bsn, cs_enc.name()); - OSMO_ASSERT(rdbi->data_len == m_rlc.block(bsn)->len); - } - - /* TODO: Need to handle 2 same bsns - * in header type 1 + /* + * get data and header from current block + * function returns the reseg status */ - gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, - cs); + reseg_status = egprs_dl_get_data(bsn, &block_data); + m_rlc.block(bsn)->spb_status.block_status_dl = reseg_status; + + /* + * If it is first segment of the split block set the state of + * bsn to nacked. If it is the first segment dont update the + * next ps value of bsn. since next segment also needs same cps + */ + if (spb == EGPRS_RLCMAC_DL_FIRST_SEG) + m_window.m_v_b.mark_nacked(bsn); + else { + /* + * TODO: Need to handle 2 same bsns + * in header type 1 + */ + gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, + cs); + } m_rlc.block(bsn)->cs_last = cs; rdbi->e = block_info->e; @@ -1169,3 +1204,118 @@ keep_time_frames = msecs_to_frames(bts_data()->dl_tbf_idle_msec); return frames_since_last_drain(fn) <= keep_time_frames; } + +/* + * This function returns the pointer to data which needs + * to be copied. Also updates the status of the block related to + * Split block handling in the RLC/MAC block. + */ +enum egprs_rlc_dl_reseg_bsn_state + gprs_rlcmac_dl_tbf::egprs_dl_get_data(int bsn, uint8_t **block_data) +{ + gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state *block_status_dl = + &rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + *block_data = &rlc_data->block[0]; + + /* + * Table 10.3a.0.1 of 44.060 + * MCS6,9: second segment starts at 74/2 = 37 + * MCS5,7: second segment starts at 56/2 = 28 + * MCS8: second segment starts at 31 + * MCS4: second segment starts at 44/2 = 22 + */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + if (*block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + switch (GprsCodingScheme::Scheme(cs_init)) { + case GprsCodingScheme::MCS6 : + case GprsCodingScheme::MCS9 : + *block_data = &rlc_data->block[37]; + break; + case GprsCodingScheme::MCS7 : + case GprsCodingScheme::MCS5 : + *block_data = &rlc_data->block[28]; + break; + case GprsCodingScheme::MCS8 : + *block_data = &rlc_data->block[31]; + break; + case GprsCodingScheme::MCS4 : + *block_data = &rlc_data->block[22]; + break; + default: + LOGP(DRLCMACDL, LOGL_ERROR, "Software error: " + "--%s hit invalid condition. headerType(%d) " + " blockstatus(%d) cs(%s) PLEASE FIX!\n", name(), + cs_current_trans.headerTypeData(), + *block_status_dl, cs_init.name()); + break; + + } + return EGPRS_RESEG_SECOND_SEG_SENT; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } + } + return EGPRS_RESEG_DL_DEFAULT; +} + +/* + * This function returns the status of split block + * for RLC/MAC block. + */ +unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_status(const int bsn) +{ + const gprs_rlc_data *rlc_data = m_rlc.block(bsn); + + return rlc_data->spb_status.block_status_dl; +} + +/* + * This function returns the spb value to be sent OTA + * for RLC/MAC block. + */ +enum egprs_rlcmac_dl_spb gprs_rlcmac_dl_tbf::get_egprs_dl_spb(const int bsn) +{ + struct gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state block_status_dl = + rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + + /* Table 10.4.8b.1 of 44.060 */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + /* + * if we are sending the second segment the spb should be 3 + * other wise it should be 2 + */ + if (block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + return EGPRS_RLCMAC_DL_SEC_SEG; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RLCMAC_DL_FIRST_SEG; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RLCMAC_DL_FIRST_SEG; + } + } + /* Non SPB cases 0 is reurned */ + return EGPRS_RLCMAC_DL_NO_RETX; +} diff --git a/tests/edge/EdgeTest.cpp b/tests/edge/EdgeTest.cpp index 807102c..9081d4d 100644 --- a/tests/edge/EdgeTest.cpp +++ b/tests/edge/EdgeTest.cpp @@ -517,7 +517,7 @@ /* TS 44.060, B.1 */ cs = GprsCodingScheme::CS4; - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -570,7 +570,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -592,7 +592,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -630,7 +630,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -669,7 +669,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -694,7 +694,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -719,7 +719,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -740,7 +740,7 @@ OSMO_ASSERT(data[0] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -777,7 +777,7 @@ cs = GprsCodingScheme::MCS4; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -835,7 +835,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -872,7 +872,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -923,7 +923,7 @@ OSMO_ASSERT(data[3] == 0); /* Block 3 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -967,7 +967,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -993,7 +993,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1020,7 +1020,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1074,7 +1074,7 @@ block_idx++) { struct gprs_rlc_data_info rlc; - gprs_rlc_data_info_init_dl(&rlc, cs, false); + gprs_rlc_data_info_init_dl(&rlc, cs, false, 0); memset(bits, pattern, sizeof(bits)); Decoding::rlc_copy_to_aligned_buffer( @@ -1118,12 +1118,14 @@ struct gprs_rlc_data_info rlc; printf("=== start %s ===\n", __func__); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::CS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::CS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 24); OSMO_ASSERT(rlc.block_info[0].data_len == 20); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::MCS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::MCS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 33); OSMO_ASSERT(rlc.block_info[0].data_len == 22); diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..5e45506 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -1814,6 +1814,203 @@ } +static void egprs_spb_to_normal_validation(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + uint16_t bsn1, bsn2, bsn3; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + struct gprs_rlc_dl_header_egprs_2 *egprs2; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + if (!(mcs == 6 && demanded_mcs == 3)) + return; + + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + bsn1 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) + || (egprs2->bsn1_lo); + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(bsn1 == 0); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + bsn2 = (egprs3->bsn1_hi << 9) || (egprs3->bsn1_mid << 1) || + (egprs3->bsn1_lo); + OSMO_ASSERT(bsn2 == bsn1); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Handle (MCS3, MCS3) -> MCS6 case */ + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + mcs)); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs2->cps == 0); + bsn3 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) || + (egprs2->bsn1_lo); + OSMO_ASSERT(bsn3 == bsn2); + + tbf_cleanup(dl_tbf); +} +static void establish_and_use_egprs_dl_tbf_for_spb(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + /* TODO: Need to support of MCS8 -> MCS6 ->MCS3 transistion + * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 + * dated 2016-02-07 23:45:40 (UTC) + */ + if (!(((mcs == 5) && (demanded_mcs == 2)) || + ((mcs == 6) && (demanded_mcs == 3)) || + ((mcs == 4) && (demanded_mcs == 1)))) + return; + + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + tbf_cleanup(dl_tbf); +} + static void establish_and_use_egprs_dl_tbf_for_retx(BTS *the_bts, int mcs, int demanded_mcs) { @@ -1972,6 +2169,9 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; + /* First parameter is current MCS, second one is demanded_mcs */ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 6); @@ -1981,6 +2181,38 @@ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 9); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 7, 5); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 9, 6); + + printf("=== end %s ===\n", __func__); +} + +static void test_tbf_egprs_spb_dl(void) +{ + BTS the_bts; + gprs_rlcmac_bts *bts; + uint8_t ts_no = 4; + int i, j; + + printf("=== start %s ===\n", __func__); + + bts = the_bts.bts_data(); + bts->cs_downgrade_threshold = 0; + setup_bts(&the_bts, ts_no); + bts->dl_tbf_idle_msec = 200; + bts->egprs_enabled = 1; + + /* ARQ I resegmentation support */ + bts->dl_arq_type = EGPRS_ARQ1; + + /* + * First parameter is current MCS, second one is demanded_mcs + * currently only MCS5->MCS2, MCS6->3, MCS4->MCS1 is tested in UT + * rest scenarios has been integration tested + */ + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 6, 3); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 5, 2); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 4, 1); + /* check MCS6->(MCS3+MCS3)->MCS6 case */ + egprs_spb_to_normal_validation(&the_bts, 6, 3); printf("=== end %s ===\n", __func__); } @@ -1999,6 +2231,8 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; for (i = 1; i <= 9; i++) establish_and_use_egprs_dl_tbf(&the_bts, i); @@ -2071,6 +2305,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_egprs_spb_dl(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..1ba4189 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -72,6 +72,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -81,6 +82,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -157,6 +159,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -166,6 +169,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -242,6 +246,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -251,6 +256,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -259,6 +265,7 @@ - Sending new block at BSN 2, CS=CS-1 -- Chunk with length 160 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=13 block=3 data=07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b @@ -267,6 +274,7 @@ - Sending new block at BSN 3, CS=CS-1 -- Chunk with length 140 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=17 block=4 data=07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @@ -275,6 +283,7 @@ - Sending new block at BSN 4, CS=CS-1 -- Chunk with length 120 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=21 block=5 data=07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 @@ -283,6 +292,7 @@ - Sending new block at BSN 5, CS=CS-1 -- Chunk with length 100 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=26 block=6 data=07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 @@ -291,6 +301,7 @@ - Sending new block at BSN 6, CS=CS-1 -- Chunk with length 80 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=30 block=7 data=07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b @@ -299,6 +310,7 @@ - Sending new block at BSN 7, CS=CS-1 -- Chunk with length 60 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=34 block=8 data=07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f @@ -307,6 +319,7 @@ - Sending new block at BSN 8, CS=CS-1 -- Chunk with length 40 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=39 block=9 data=07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 @@ -315,6 +328,7 @@ - Sending new block at BSN 9, CS=CS-1 -- Chunk with length 20 would exactly fit into space (20): add length header with LI=0, to make frame extend to next block, and we are done data block (BSN 9, CS-1): 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=43 block=10 data=07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 @@ -326,6 +340,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=47 block=11 data=07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 @@ -334,6 +349,7 @@ - Sending new block at BSN 11, CS=CS-1 -- Chunk with length 182 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=52 block=0 data=07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 @@ -342,6 +358,7 @@ - Sending new block at BSN 12, CS=CS-1 -- Chunk with length 162 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=56 block=1 data=07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 @@ -350,6 +367,7 @@ - Sending new block at BSN 13, CS=CS-1 -- Chunk with length 142 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 13, CS-1): 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=60 block=2 data=07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d @@ -358,6 +376,7 @@ - Sending new block at BSN 14, CS=CS-1 -- Chunk with length 122 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=65 block=3 data=07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 @@ -366,6 +385,7 @@ - Sending new block at BSN 15, CS=CS-1 -- Chunk with length 102 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=69 block=4 data=07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 @@ -374,6 +394,7 @@ - Sending new block at BSN 16, CS=CS-1 -- Chunk with length 82 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=73 block=5 data=07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 @@ -382,6 +403,7 @@ - Sending new block at BSN 17, CS=CS-1 -- Chunk with length 62 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=78 block=6 data=07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d @@ -390,6 +412,7 @@ - Sending new block at BSN 18, CS=CS-1 -- Chunk with length 42 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=82 block=7 data=07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 @@ -398,6 +421,7 @@ - Sending new block at BSN 19, CS=CS-1 -- Chunk with length 22 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=86 block=8 data=07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 @@ -411,6 +435,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=16 data block (BSN 20, CS-1): 0a 41 c6 c7 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -449,6 +474,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 data block (BSN 21, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -468,6 +494,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 22, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FINISHED) @@ -1481,6 +1508,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 0, CS-1): 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 MSG = 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 @@ -1491,6 +1519,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 1, CS-1): 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 MSG = 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 @@ -1501,6 +1530,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FINISHED data block (BSN 2, CS-1): 4d 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling cannot be scheduled in this TS 7 (first control TS 4) @@ -1784,6 +1814,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=10 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 0, CS-4): 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654292 TS 7 @@ -1797,6 +1828,7 @@ TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) downlink (V(A)==0 .. V(S)==1) - Restarting at BSN 0, because all blocks have been transmitted. - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-4): 07 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 @@ -2365,6 +2397,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654279 block=10 data=00 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 @@ -2384,6 +2417,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -2406,6 +2440,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654288 block=0 data=00 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 @@ -2425,6 +2460,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654292 block=1 data=00 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2447,6 +2483,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654296 block=2 data=00 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c @@ -2466,6 +2503,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654301 block=3 data=00 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b @@ -2488,6 +2526,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 6, CS-1): 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654305 block=4 data=00 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 @@ -2507,6 +2546,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654309 block=5 data=00 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 @@ -2526,6 +2566,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654314 block=6 data=00 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 @@ -2548,6 +2589,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654318 block=7 data=00 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 @@ -2567,6 +2609,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654322 block=8 data=00 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2589,6 +2632,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654327 block=9 data=00 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c @@ -2608,6 +2652,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654331 block=10 data=00 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b @@ -2630,6 +2675,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 13, CS-1): 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654335 block=11 data=00 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 @@ -2649,6 +2695,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654340 block=0 data=00 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 @@ -2668,6 +2715,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654344 block=1 data=00 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 @@ -2690,6 +2738,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654348 block=2 data=00 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 @@ -2709,6 +2758,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654353 block=3 data=00 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2731,6 +2781,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654357 block=4 data=00 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c @@ -2750,6 +2801,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654361 block=5 data=00 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b @@ -2772,6 +2824,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 20, CS-1): 16 35 45 54 20 32 38 4c 4c 43 20 50 41 43 4b 45 54 20 32 39 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because 20 blocks sent. TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW): Scheduling polling at FN 2654379 TS 7 @@ -2795,6 +2848,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 21, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) msg block (BSN 21, CS-1): 07 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654370 block=7 data=00 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 @@ -2814,6 +2868,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 22, CS-1): 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) msg block (BSN 22, CS-1): 07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654374 block=8 data=07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 @@ -2836,6 +2891,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 23, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) msg block (BSN 23, CS-1): 07 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654379 block=9 data=00 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 @@ -2855,6 +2911,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 24, CS-1): 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) msg block (BSN 24, CS-1): 07 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654383 block=10 data=00 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2877,6 +2934,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 25, CS-1): 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 25 BSN2 -1) - Copying data unit 0 (BSN 25) msg block (BSN 25, CS-1): 07 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654387 block=11 data=00 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c @@ -2896,6 +2954,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 26, CS-1): 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 26 BSN2 -1) - Copying data unit 0 (BSN 26) msg block (BSN 26, CS-1): 07 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654392 block=0 data=00 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b @@ -2918,6 +2977,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 27, CS-1): 16 35 45 54 20 33 38 4c 4c 43 20 50 41 43 4b 45 54 20 33 39 +- need_padding 0 spb_status 0 spb 0(BSN1 27 BSN2 -1) - Copying data unit 0 (BSN 27) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) @@ -3028,6 +3088,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654405 block=3 data=00 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 @@ -3047,6 +3108,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654409 block=4 data=00 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 @@ -3066,6 +3128,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (16) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654413 block=5 data=00 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 @@ -3085,6 +3148,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (14) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654418 block=6 data=00 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 @@ -3104,6 +3168,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654422 block=7 data=00 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -3123,6 +3188,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654426 block=8 data=00 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 @@ -3142,6 +3208,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654431 block=9 data=00 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b @@ -3161,6 +3228,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654435 block=10 data=00 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 @@ -3180,6 +3248,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654439 block=11 data=00 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 @@ -3199,6 +3268,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654444 block=0 data=00 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c @@ -3218,6 +3288,7 @@ Complete DL frame for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=21 TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 10, CS-1): 4d 43 20 50 41 43 4b 45 54 20 30 39 20 28 54 42 46 20 32 29 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654461 TS 7 @@ -3698,6 +3769,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 0, MCS-1): 14 15 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3711,6 +3783,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3721,6 +3794,7 @@ - Sending new block at BSN 2, CS=MCS-1 -- Chunk with length 490 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3731,6 +3805,7 @@ - Sending new block at BSN 3, CS=MCS-1 -- Chunk with length 468 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3741,6 +3816,7 @@ - Sending new block at BSN 4, CS=MCS-1 -- Chunk with length 446 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3751,6 +3827,7 @@ - Sending new block at BSN 5, CS=MCS-1 -- Chunk with length 424 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3761,6 +3838,7 @@ - Sending new block at BSN 6, CS=MCS-1 -- Chunk with length 402 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3771,6 +3849,7 @@ - Sending new block at BSN 7, CS=MCS-1 -- Chunk with length 380 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3781,6 +3860,7 @@ - Sending new block at BSN 8, CS=MCS-1 -- Chunk with length 358 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3791,6 +3871,7 @@ - Sending new block at BSN 9, CS=MCS-1 -- Chunk with length 336 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3801,6 +3882,7 @@ - Sending new block at BSN 10, CS=MCS-1 -- Chunk with length 314 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3811,6 +3893,7 @@ - Sending new block at BSN 11, CS=MCS-1 -- Chunk with length 292 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3821,6 +3904,7 @@ - Sending new block at BSN 12, CS=MCS-1 -- Chunk with length 270 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3831,6 +3915,7 @@ - Sending new block at BSN 13, CS=MCS-1 -- Chunk with length 248 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3841,6 +3926,7 @@ - Sending new block at BSN 14, CS=MCS-1 -- Chunk with length 226 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3851,6 +3937,7 @@ - Sending new block at BSN 15, CS=MCS-1 -- Chunk with length 204 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3861,6 +3948,7 @@ - Sending new block at BSN 16, CS=MCS-1 -- Chunk with length 182 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3871,6 +3959,7 @@ - Sending new block at BSN 17, CS=MCS-1 -- Chunk with length 160 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3881,6 +3970,7 @@ - Sending new block at BSN 18, CS=MCS-1 -- Chunk with length 138 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3891,6 +3981,7 @@ - Sending new block at BSN 19, CS=MCS-1 -- Chunk with length 116 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 19, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3901,6 +3992,7 @@ - Sending new block at BSN 20, CS=MCS-1 -- Chunk with length 94 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 20, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3911,6 +4003,7 @@ - Sending new block at BSN 21, CS=MCS-1 -- Chunk with length 72 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 21, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3921,6 +4014,7 @@ - Sending new block at BSN 22, CS=MCS-1 -- Chunk with length 50 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 22, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3931,6 +4025,7 @@ - Sending new block at BSN 23, CS=MCS-1 -- Chunk with length 28 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 23, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3946,6 +4041,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 24, MCS-1): 0c 1d 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4006,6 +4102,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=16 data block (BSN 0, MCS-2): 14 21 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4019,6 +4116,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4029,6 +4127,7 @@ - Sending new block at BSN 2, CS=MCS-2 -- Chunk with length 484 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4039,6 +4138,7 @@ - Sending new block at BSN 3, CS=MCS-2 -- Chunk with length 456 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4049,6 +4149,7 @@ - Sending new block at BSN 4, CS=MCS-2 -- Chunk with length 428 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4059,6 +4160,7 @@ - Sending new block at BSN 5, CS=MCS-2 -- Chunk with length 400 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4069,6 +4171,7 @@ - Sending new block at BSN 6, CS=MCS-2 -- Chunk with length 372 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4079,6 +4182,7 @@ - Sending new block at BSN 7, CS=MCS-2 -- Chunk with length 344 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4089,6 +4193,7 @@ - Sending new block at BSN 8, CS=MCS-2 -- Chunk with length 316 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4099,6 +4204,7 @@ - Sending new block at BSN 9, CS=MCS-2 -- Chunk with length 288 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4109,6 +4215,7 @@ - Sending new block at BSN 10, CS=MCS-2 -- Chunk with length 260 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4119,6 +4226,7 @@ - Sending new block at BSN 11, CS=MCS-2 -- Chunk with length 232 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4129,6 +4237,7 @@ - Sending new block at BSN 12, CS=MCS-2 -- Chunk with length 204 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4139,6 +4248,7 @@ - Sending new block at BSN 13, CS=MCS-2 -- Chunk with length 176 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4149,6 +4259,7 @@ - Sending new block at BSN 14, CS=MCS-2 -- Chunk with length 148 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4159,6 +4270,7 @@ - Sending new block at BSN 15, CS=MCS-2 -- Chunk with length 120 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4169,6 +4281,7 @@ - Sending new block at BSN 16, CS=MCS-2 -- Chunk with length 92 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4179,6 +4292,7 @@ - Sending new block at BSN 17, CS=MCS-2 -- Chunk with length 64 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4189,6 +4303,7 @@ - Sending new block at BSN 18, CS=MCS-2 -- Chunk with length 36 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4204,6 +4319,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=18 data block (BSN 19, MCS-2): 10 25 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4264,6 +4380,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=25 data block (BSN 0, MCS-3): 14 33 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4277,6 +4394,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4287,6 +4405,7 @@ - Sending new block at BSN 2, CS=MCS-3 -- Chunk with length 475 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4297,6 +4416,7 @@ - Sending new block at BSN 3, CS=MCS-3 -- Chunk with length 438 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4307,6 +4427,7 @@ - Sending new block at BSN 4, CS=MCS-3 -- Chunk with length 401 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4317,6 +4438,7 @@ - Sending new block at BSN 5, CS=MCS-3 -- Chunk with length 364 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4327,6 +4449,7 @@ - Sending new block at BSN 6, CS=MCS-3 -- Chunk with length 327 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4337,6 +4460,7 @@ - Sending new block at BSN 7, CS=MCS-3 -- Chunk with length 290 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4347,6 +4471,7 @@ - Sending new block at BSN 8, CS=MCS-3 -- Chunk with length 253 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4357,6 +4482,7 @@ - Sending new block at BSN 9, CS=MCS-3 -- Chunk with length 216 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4367,6 +4493,7 @@ - Sending new block at BSN 10, CS=MCS-3 -- Chunk with length 179 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4377,6 +4504,7 @@ - Sending new block at BSN 11, CS=MCS-3 -- Chunk with length 142 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4387,6 +4515,7 @@ - Sending new block at BSN 12, CS=MCS-3 -- Chunk with length 105 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4397,6 +4526,7 @@ - Sending new block at BSN 13, CS=MCS-3 -- Chunk with length 68 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4410,6 +4540,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-3): 3f 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4425,6 +4556,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=34 data block (BSN 15, MCS-3): 02 45 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4485,6 +4617,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=32 data block (BSN 0, MCS-4): 14 41 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4498,6 +4631,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4508,6 +4642,7 @@ - Sending new block at BSN 2, CS=MCS-4 -- Chunk with length 468 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4518,6 +4653,7 @@ - Sending new block at BSN 3, CS=MCS-4 -- Chunk with length 424 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4528,6 +4664,7 @@ - Sending new block at BSN 4, CS=MCS-4 -- Chunk with length 380 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4538,6 +4675,7 @@ - Sending new block at BSN 5, CS=MCS-4 -- Chunk with length 336 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4548,6 +4686,7 @@ - Sending new block at BSN 6, CS=MCS-4 -- Chunk with length 292 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4558,6 +4697,7 @@ - Sending new block at BSN 7, CS=MCS-4 -- Chunk with length 248 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4568,6 +4708,7 @@ - Sending new block at BSN 8, CS=MCS-4 -- Chunk with length 204 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4578,6 +4719,7 @@ - Sending new block at BSN 9, CS=MCS-4 -- Chunk with length 160 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4588,6 +4730,7 @@ - Sending new block at BSN 10, CS=MCS-4 -- Chunk with length 116 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4598,6 +4741,7 @@ - Sending new block at BSN 11, CS=MCS-4 -- Chunk with length 72 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4613,6 +4757,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 12, MCS-4): 38 1d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4673,6 +4818,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-5): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4686,6 +4832,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4696,6 +4843,7 @@ - Sending new block at BSN 2, CS=MCS-5 -- Chunk with length 456 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4706,6 +4854,7 @@ - Sending new block at BSN 3, CS=MCS-5 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4716,6 +4865,7 @@ - Sending new block at BSN 4, CS=MCS-5 -- Chunk with length 344 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4726,6 +4876,7 @@ - Sending new block at BSN 5, CS=MCS-5 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4736,6 +4887,7 @@ - Sending new block at BSN 6, CS=MCS-5 -- Chunk with length 232 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4746,6 +4898,7 @@ - Sending new block at BSN 7, CS=MCS-5 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4756,6 +4909,7 @@ - Sending new block at BSN 8, CS=MCS-5 -- Chunk with length 120 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4766,6 +4920,7 @@ - Sending new block at BSN 9, CS=MCS-5 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4781,6 +4936,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-5): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4841,6 +4997,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-6): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4854,6 +5011,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4864,6 +5022,7 @@ - Sending new block at BSN 2, CS=MCS-6 -- Chunk with length 438 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4874,6 +5033,7 @@ - Sending new block at BSN 3, CS=MCS-6 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4884,6 +5044,7 @@ - Sending new block at BSN 4, CS=MCS-6 -- Chunk with length 290 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4894,6 +5055,7 @@ - Sending new block at BSN 5, CS=MCS-6 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4904,6 +5066,7 @@ - Sending new block at BSN 6, CS=MCS-6 -- Chunk with length 142 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4917,6 +5080,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-6): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4932,6 +5096,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-6): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4993,6 +5158,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-7): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5002,12 +5168,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(7) last_mcs(5) demanded_mcs(7) cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-7 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5022,6 +5189,7 @@ - Sending new block at BSN 3, CS=MCS-7 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5036,6 +5204,7 @@ - Sending new block at BSN 5, CS=MCS-7 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5050,6 +5219,7 @@ - Sending new block at BSN 7, CS=MCS-7 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5064,6 +5234,7 @@ - Sending new block at BSN 9, CS=MCS-7 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 9) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5081,6 +5252,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-7): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5142,6 +5314,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=56 data block (BSN 0, MCS-8): 14 71 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5152,12 +5325,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(8) demanded_mcs(8) cs_trans(8) +- initial_cs_dl(8) last_mcs(8) demanded_mcs(8) cs_trans(8) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-8 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5172,6 +5346,7 @@ - Sending new block at BSN 3, CS=MCS-8 -- Chunk with length 376 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5186,6 +5361,7 @@ - Sending new block at BSN 5, CS=MCS-8 -- Chunk with length 240 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5200,6 +5376,7 @@ - Sending new block at BSN 7, CS=MCS-8 -- Chunk with length 104 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5217,6 +5394,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=30 data block (BSN 8, MCS-8): 48 3d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5279,6 +5457,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-9): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5288,12 +5467,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(9) last_mcs(6) demanded_mcs(9) cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-9 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5308,6 +5488,7 @@ - Sending new block at BSN 3, CS=MCS-9 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5322,6 +5503,7 @@ - Sending new block at BSN 5, CS=MCS-9 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5339,6 +5521,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-9): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5356,6 +5539,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-9): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5402,11 +5586,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(6) cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5450,11 +5636,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 96 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(1) demanded_mcs(1) cs_trans(1) +- initial_cs_dl(1) last_mcs(1) demanded_mcs(1) cs_trans(1) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 98 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5498,11 +5686,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-2): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 92 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(2) demanded_mcs(2) cs_trans(2) +- initial_cs_dl(2) last_mcs(2) demanded_mcs(2) cs_trans(2) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 94 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5546,6 +5736,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5557,6 +5748,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-5): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5564,10 +5756,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-5): 0f 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7) cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7) cs_trans(7) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-7): 07 00 00 02 c0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 @@ -5612,6 +5805,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5623,6 +5817,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-6): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5630,10 +5825,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-6): 0f 40 00 00 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9) cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9) cs_trans(9) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-9): 07 00 00 02 28 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 @@ -5686,6 +5882,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-7): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5694,13 +5891,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-7): 0f 00 00 02 a0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5) cs_trans(5) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5) cs_trans(5) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-5): 07 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5752,6 +5951,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-9): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5760,13 +5960,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-9): 0f 00 00 02 00 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6) cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6) cs_trans(6) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-6): 07 40 00 02 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5780,3 +5982,233 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-5 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(2) cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 d2 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(2) demanded_mcs(2) cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 f2 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-4 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (44) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-4): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-4): 07 00 00 80 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(4) demanded_mcs(1) cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 d6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(1) demanded_mcs(1) cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 f6 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(6) cs_trans(6) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 2 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..c38417d 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,9 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_egprs_spb_dl === +Testing retx for MCS 6 to reseg_mcs 3 +Testing retx for MCS 5 to reseg_mcs 2 +Testing retx for MCS 4 to reseg_mcs 1 +Testing retx for MCS 6 to reseg_mcs 3 +=== end test_tbf_egprs_spb_dl === -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 20 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Wed Aug 17 13:58:37 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Wed, 17 Aug 2016 13:58:37 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 20: (1 comment) https://gerrit.osmocom.org/#/c/655/15/src/pcu_vty.c File src/pcu_vty.c: Line 490: cfg_pcu_dl_arq_cmd, > Hi Neels, Anyways I have modified the patch as per my understanding. please review the latest code. -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 20 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Wed Aug 17 14:28:46 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Wed, 17 Aug 2016 14:28:46 +0000 Subject: [PATCH] openbsc[master]: Adding compression control In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/642 to look at the new patch set (#16). Adding compression control In this commit two modules were added: gprs_sndcp_comp.h/c: This part handles the creation and destruction of conpression entites. It handles the allocation and freeing of the memory and offers functions to query compression parameters (i.e. which compression entity should be used if a packet from NSAPI x has to be compressed?) gprs_sndcp_pcomp.c/h: This is the code that performs the actual header compression. It takes care that the packets are compressed/decompressed with the right modes etc. It works, but is not yet ready for merging. Both files depend on each other so that they only can be merged both at the same time. Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 --- M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_sndcp_comp.h A openbsc/include/openbsc/gprs_sndcp_pcomp.h M openbsc/include/openbsc/sgsn.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_sndcp_comp.c A openbsc/src/gprs/gprs_sndcp_pcomp.c M openbsc/src/gprs/sgsn_vty.c M openbsc/tests/sgsn/Makefile.am 9 files changed, 844 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/42/642/16 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index f402fea..88a7e2c 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,7 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ - slhc.h + slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_sndcp_comp.h b/openbsc/include/openbsc/gprs_sndcp_comp.h new file mode 100644 index 0000000..e2d79ab --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_comp.h @@ -0,0 +1,85 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_SNDCP_COMP_H +#define _GPRS_SNDCP_COMP_H + +#include +#include +#include + +/* Header / Data compression entity */ +struct gprs_sndcp_comp { + struct llist_head list; + + /* Serves as an ID in case we want to delete this entity later */ + int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + + /* Specifies to which NSAPIs the compression entity is assigned */ + int nsapi_len; /* Number of applicable NSAPIs (default 0) */ + int nsapi[11]; /* Applicable NSAPIs (default 0) */ + + /* Assigned pcomp values */ + int comp_len; /* Number of contained PCOMP / DCOMP values */ + int comp[16]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */ + + /* Algorithm parameters */ + int algo; /* Algorithm type (see gprs_sndcp_xid.h) */ + int compclass; /* See gprs_sndcp_xid.h/c */ + void *state; /* Algorithm status and parameters */ +}; + +/* Free a list with compression entities */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities); + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, int entity); + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_entities_add(const void *ctx, struct + llist_head + *comp_entities, const struct + gprs_sndcp_comp_field + *comp_field); + +/* Find compression entity by its entity number */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_entity(const struct llist_head + *comp_entities, int entity); + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head + *comp_entities, int comp); + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head + *comp_entities, int nsapi); + +/* Find a comp_index for a given pcomp/dcomp value */ +int gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp + *comp_entity, int comp); + +/* Find a pcomp/dcomp value for a given comp_index */ +int gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp + *comp_entity, int comp_index); + +#endif diff --git a/openbsc/include/openbsc/gprs_sndcp_pcomp.h b/openbsc/include/openbsc/gprs_sndcp_pcomp.h new file mode 100644 index 0000000..2444260 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_pcomp.h @@ -0,0 +1,47 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_SNDCP_pcomp_H +#define _GPRS_SNDCP_pcomp_H + +#include +#include +#include + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field); + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity); + +/* Expand packet header */ +int gprs_sndcp_pcomp_expand(uint8_t *data_o, uint8_t *data_i, int len, + int pcomp, const struct llist_head *comp_entities); + +/* Compress packet header */ +int gprs_sndcp_pcomp_compress(uint8_t *data_o, uint8_t *data_i, int len, + int *pcomp, + const struct llist_head *comp_entities, + int nsapi); + +#endif diff --git a/openbsc/include/openbsc/sgsn.h b/openbsc/include/openbsc/sgsn.h index 59126fe..2366d7a 100644 --- a/openbsc/include/openbsc/sgsn.h +++ b/openbsc/include/openbsc/sgsn.h @@ -88,6 +88,12 @@ int dynamic_lookup; + /* RFC1144 TCP/IP Header compression */ + struct { + int enabled; + int s01; + } pcomp_rfc1144; + struct oap_config oap; }; diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 245636b..2910c02 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -27,7 +27,7 @@ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ - slhc.c + slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/gprs_sndcp_comp.c b/openbsc/src/gprs/gprs_sndcp_comp.c new file mode 100644 index 0000000..da8ab40 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_comp.c @@ -0,0 +1,337 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +/* Create a new compression entity from a XID-Field */ +static struct gprs_sndcp_comp *gprs_sndcp_comp_create(const void + *ctx, const struct + gprs_sndcp_comp_field + *comp_field) +{ + OSMO_ASSERT(comp_field); + + struct gprs_sndcp_comp *comp_entity; + comp_entity = talloc_zero(ctx, struct gprs_sndcp_comp); + + /* Copy relevant information from the SNDCP-XID field */ + comp_entity->entity = comp_field->entity; + comp_entity->comp_len = comp_field->comp_len; + memcpy(comp_entity->comp, comp_field->comp, + comp_field->comp_len * sizeof(int)); + + if (comp_field->rfc1144_params) { + comp_entity->nsapi_len = comp_field->rfc1144_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc1144_params->nsapi, + comp_entity->nsapi_len * sizeof(int)); + } else if (comp_field->rfc2507_params) { + comp_entity->nsapi_len = comp_field->rfc2507_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc2507_params->nsapi, + comp_entity->nsapi_len * sizeof(int)); + } else if (comp_field->rohc_params) { + comp_entity->nsapi_len = comp_field->rohc_params->nsapi_len; + memcpy(comp_entity->nsapi, comp_field->rohc_params->nsapi, + comp_entity->nsapi_len * sizeof(int)); + } else if (comp_field->v42bis_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + comp_entity->nsapi_len * sizeof(int)); + } else if (comp_field->v44_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + comp_entity->nsapi_len * sizeof(int)); + } else { + /* The caller is expected to check carefully if the all + * data fields required for compression entity creation + * are present. Otherwise we blow an assertion here */ + OSMO_ASSERT(NULL); + } + comp_entity->algo = comp_field->algo; + + /* Check if an NSAPI is selected, if not, it does not make sense + * to create the compression entity, since the caller should + * have checked the presence of the NSAPI, we blow an assertion + * in case of missing NSAPIs */ + OSMO_ASSERT(comp_entity->nsapi_len > 0) + + /* Determine of which class our compression entity will be + * (Protocol or Data compresson ?) */ + comp_entity->compclass = gprs_sndcp_get_compression_class(comp_field); + OSMO_ASSERT(comp_entity->compclass != -1); + + /* Create an algorithm specific compression context */ + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + if (gprs_sndcp_pcomp_init(ctx, comp_entity, comp_field) != 0) { + talloc_free(comp_entity); + comp_entity = NULL; + } + } else { + LOGP(DSNDCP, LOGL_ERROR, + "We don't support data compression yet!\n"); + talloc_free(comp_entity); + return NULL; + } + + /* Display info message */ + if (comp_entity == NULL) { + LOGP(DSNDCP, LOGL_ERROR, + "Header compression entity (%i) creation failed!\n", + comp_entity->entity); + return NULL; + } + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "New header compression entity (%i) created.\n", + comp_entity->entity); + } else { + LOGP(DSNDCP, LOGL_INFO, + "New data compression entity (%i) created.\n", + comp_entity->entity); + } + + return comp_entity; +} + +/* Free a list with compression entities */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities) +{ + struct llist_head *ce, *ce2; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + /* Free compression entity */ + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %i ...\n", + comp_entity->entity); + gprs_sndcp_pcomp_term(comp_entity); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %i ...\n", + comp_entity->entity); + } + } + + llist_for_each_safe(ce, ce2, comp_entities) { + llist_del(ce); + talloc_free(ce); + } + +} + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, int entity) +{ + struct gprs_sndcp_comp *comp_entity; + struct gprs_sndcp_comp *comp_entity_to_delete = NULL; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) + comp_entity_to_delete = comp_entity; + } + + if (comp_entity_to_delete) { + if (comp_entity_to_delete->compclass == + SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %i ...\n", + comp_entity_to_delete->entity); + gprs_sndcp_pcomp_term(comp_entity_to_delete); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %i ...\n", + comp_entity_to_delete->entity); + } + + /* Delete compression entity */ + llist_del(&comp_entity_to_delete->list); + talloc_free(comp_entity_to_delete); + } + +} + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_entities_add(const void *ctx, struct + llist_head + *comp_entities, const struct + gprs_sndcp_comp_field + *comp_field) +{ + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(comp_entities); + OSMO_ASSERT(comp_field); + + /* Just to be sure, if the entity is already in + * the list it will be deleted now */ + gprs_sndcp_comp_delete(comp_entities, comp_field->entity); + + /* Create and add a new entity to the list */ + comp_entity = gprs_sndcp_comp_create(ctx, comp_field); + + if (comp_entity) { + llist_add(&comp_entity->list, comp_entities); + return comp_entity; + } + + return NULL; +} + +/* Find compression entity by its entity number */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_entity(const struct + llist_head + *comp_entities, int entity) +{ + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) + return comp_entity; + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given entity number %i.\n", + entity); + return NULL; +} + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct + llist_head + *comp_entities, int comp) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return comp_entity; + } + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given pcomp/dcomp value %i.\n", + comp); + return NULL; +} + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct + llist_head + *comp_entities, int nsapi) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->nsapi_len; i++) { + if (comp_entity->nsapi[i] == nsapi) + return comp_entity; + } + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given nsapi value %i\n", + nsapi); + return NULL; + +} + +/* Find a comp_index for a given pcomp/dcomp value */ +int gprs_sndcp_comp_get_idx(const struct + gprs_sndcp_comp + *comp_entity, int comp) +{ + int i; + + OSMO_ASSERT(comp_entity); + + /* A pcomp/dcomp field set to zero always disables + * all sort of compression and is assigned fix. So we + * just return zero in this case */ + if (comp == 0) + return 0; + + /* Look in the pcomp/dcomp list for the index */ + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return i + 1; + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching comp_index for given pcomp/dcomp value %i\n", + comp); + return 0; + +} + +/* Find a pcomp/dcomp value for a given comp_index */ +int gprs_sndcp_comp_get_comp(const struct + gprs_sndcp_comp + *comp_entity, int comp_index) +{ + OSMO_ASSERT(comp_entity); + + /* A comp_index of zero translates to zero right away. */ + if (comp_index == 0) + return 0; + + if (comp_index > comp_entity->comp_len) { + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching pcomp/dcomp value for given comp_index value %i.\n", + comp_index); + return 0; + } + + /* Look in the pcomp/dcomp list for the comp_index */ + return comp_entity->comp[comp_index - 1]; + +} diff --git a/openbsc/src/gprs/gprs_sndcp_pcomp.c b/openbsc/src/gprs/gprs_sndcp_pcomp.c new file mode 100644 index 0000000..41f6c6a --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_pcomp.c @@ -0,0 +1,334 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG_RFC1144 1 + +/* Show details of the RFC1144 compressed packet header */ +static void debug_rfc1144_header(uint8_t *header) +{ +#if DEBUG_RFC1144 == 1 + + int t,c,i,p,s,a,w,u = 0; + t = (header[0] >> 7) & 1; + c = (header[0] >> 6) & 1; + i = (header[0] >> 5) & 1; + p = (header[0] >> 4) & 1; + s = (header[0] >> 3) & 1; + a = (header[0] >> 2) & 1; + w = (header[0] >> 1) & 1; + u = header[0] & 1; + + DEBUGP(DSNDCP,"rfc1144 header:\n"); + DEBUGP(DSNDCP," Tag bit = %d\n",t); + DEBUGP(DSNDCP," C = %d\n",c); + DEBUGP(DSNDCP," I = %d\n",i); + DEBUGP(DSNDCP," P = %d\n",p); + DEBUGP(DSNDCP," S = %d\n",s); + DEBUGP(DSNDCP," A = %d\n",a); + DEBUGP(DSNDCP," W = %d\n",w); + DEBUGP(DSNDCP," U = %d\n",u); + + header++; + if(c) { + DEBUGP(DSNDCP," Connection number (C) = %d\n",*header); + header++; + } + + DEBUGP(DSNDCP," TCP Checksum = %02x%02x\n",header[0],header[1]); + header+=2; + + if(s && w && u) { + DEBUGP(DSNDCP," Special case I (SPECIAL_I) => short header\n"); + return; + } else if(s && a && w && u) { + DEBUGP(DSNDCP," Special case D (SPECIAL_D) => short header\n"); + return; + } + + if(u) { + DEBUGP(DSNDCP," Urgent Pointer (U) = %02x\n",*header); + header++; + } + if(w) { + DEBUGP(DSNDCP," Delta Window (W) = %02x\n",*header); + header++; + } + if(a) { + DEBUGP(DSNDCP," Delta Ack (A) = %02x\n",*header); + header++; + } + if(s) { + DEBUGP(DSNDCP," Delta Sequence (S) = %02x\n",*header); + header++; + } + if(i) { + DEBUGP(DSNDCP," Delta IP ID (I) = %02x\n",*header); + header++; + } + + /* FIXME: Header values will be usually fit in 8 bits, implement + * implement variable length decoding for values larger then 8 bit */ +#endif +} + + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a new header compression + * entity is created by gprs_sndcp.c */ + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + comp_entity->state = + slhc_init(ctx, comp_field->rfc1144_params->s01 + 1, + comp_field->rfc1144_params->s01 + 1); + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression initalized.\n"); + return 0; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a header compression + * entity is deleted by gprs_sndcp.c */ + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + if (comp_entity->state) { + slhc_free((struct slcompress *)comp_entity->state); + comp_entity->state = NULL; + } + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression terminated.\n"); + return; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Compress a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_compress(int *pcomp_index, uint8_t *data_o, + uint8_t *data_i, int len, + struct slcompress *comp) +{ + uint8_t *comp_ptr; /* Not used */ + int compr_len; + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Run compressor */ + compr_len = slhc_compress(comp, data_i, len, data_o, &comp_ptr, 0); + + /* Generate pcomp_index */ + if (data_o[0] & SL_TYPE_COMPRESSED_TCP) { + *pcomp_index = 2; + data_o[0] &= ~SL_TYPE_COMPRESSED_TCP; + debug_rfc1144_header(data_o); + } else if ((data_o[0] & SL_TYPE_UNCOMPRESSED_TCP) == + SL_TYPE_UNCOMPRESSED_TCP) { + *pcomp_index = 1; + data_o[0] &= 0x4F; + } else + *pcomp_index = 0; + + return compr_len; +} + +/* Expand a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_expand(uint8_t *data_o, uint8_t *data_i, + int len, int pcomp_index, + struct slcompress *comp) +{ + int data_decompressed_len; + int type = -1; + + /* Note: this function should never be called with pcomp_index=0, + * since this condition is already filtered + * out by gprs_sndcp_pcomp_expand() */ + + /* Determine the data type by the PCOMP index */ + switch (pcomp_index) { + case 1: + type = SL_TYPE_UNCOMPRESSED_TCP; + break; + case 2: + type = SL_TYPE_COMPRESSED_TCP; + break; + } + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Restore the original version nibble on + * marked uncompressed packets */ + if (type == SL_TYPE_UNCOMPRESSED_TCP) { + + /* Just in case the phone tags uncompressed tcp-datas + * (normally this is handled by pcomp so there is + * no need for tagging the datas) */ + data_o[0] &= 0x4F; + data_decompressed_len = slhc_remember(comp, data_o, len); + return data_decompressed_len; + } + + /* Uncompress compressed packets */ + else if (type == SL_TYPE_COMPRESSED_TCP) { + data_decompressed_len = slhc_uncompress(comp, data_o, len); + return data_decompressed_len; + } + + /* Regular or unknown packets will not be touched */ + return len; +} + +/* Expand packet header */ +int gprs_sndcp_pcomp_expand(uint8_t *data_o, uint8_t *data_i, int len, + int pcomp, const struct llist_head *comp_entities) +{ + int rc; + int pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data_o); + OSMO_ASSERT(data_i); + OSMO_ASSERT(comp_entities); + + /* Skip on pcomp=0 */ + if (pcomp == 0) { + memcpy(data_o,data_i,len); + return len; + } + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_comp(comp_entities, pcomp); + + /* Skip compression if no suitable compression entity can be found */ + if (comp_entity == NULL) { + memcpy(data_o,data_i,len); + return len; + } + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION); + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144); + + /* Find pcomp_index */ + pcomp_index = gprs_sndcp_comp_get_idx(comp_entity, pcomp); + + /* Run decompression algo */ + rc = gprs_sndcp_pcomp_rfc1144_expand(data_o, data_i, len, pcomp_index, + comp_entity->state); + slhc_i_status(comp_entity->state); + slhc_o_status(comp_entity->state); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header expansion done, old length=%i, new length=%i\n", + len, rc); + + return rc; +} + +/* Compress packet header */ +int gprs_sndcp_pcomp_compress(uint8_t *data_o, uint8_t *data_i, int len, + int *pcomp, + const struct llist_head *comp_entities, int nsapi) +{ + int rc; + int pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data_o); + OSMO_ASSERT(data_i); + OSMO_ASSERT(pcomp); + OSMO_ASSERT(comp_entities); + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_nsapi(comp_entities, nsapi); + + /* Skip compression if no suitable compression entity can be found */ + if (!comp_entity) { + *pcomp = 0; + memcpy(data_o,data_i,len); + return len; + } + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION); + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144); + + /* Run compression algo */ + rc = gprs_sndcp_pcomp_rfc1144_compress(&pcomp_index, data_o, data_i, + len, comp_entity->state); + slhc_i_status(comp_entity->state); + slhc_o_status(comp_entity->state); + + /* Find pcomp value */ + *pcomp = gprs_sndcp_comp_get_comp(comp_entity, pcomp_index); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header compression done, old length=%i, new length=%i\n", + len, rc); + return rc; +} diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c index e6dc68d..1b67092 100644 --- a/openbsc/src/gprs/sgsn_vty.c +++ b/openbsc/src/gprs/sgsn_vty.c @@ -269,6 +269,13 @@ vty_out(vty, " timer t3395 %d%s", g_cfg->timers.T3395, VTY_NEWLINE); vty_out(vty, " timer t3397 %d%s", g_cfg->timers.T3397, VTY_NEWLINE); + if (g_cfg->pcomp_rfc1144.enabled) { + vty_out(vty, " compression rfc1144 slots %d%s", + g_cfg->pcomp_rfc1144.s01+1, VTY_NEWLINE); + } else { + vty_out(vty, " no compression rfc1144%s", VTY_NEWLINE); + } + return CMD_SUCCESS; } @@ -1074,6 +1081,27 @@ return CMD_SUCCESS; } +DEFUN(cfg_no_comp_rfc1144, cfg_no_comp_rfc1144_cmd, + "no compression rfc1144", + NO_STR "compression\n" + "disable rfc1144 TCP/IP header compression\n") +{ + g_cfg->pcomp_rfc1144.enabled = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_comp_rfc1144, cfg_comp_rfc1144_cmd, + "compression rfc1144 slots <1-256>", + "Configure compression\n" + "RFC1144 Header compresion scheme\n" + "Number of compression state slots\n" + "number\n") +{ + g_cfg->pcomp_rfc1144.enabled = 1; + g_cfg->pcomp_rfc1144.s01 = atoi(argv[0]) - 1; + return CMD_SUCCESS; +} + int sgsn_vty_init(void) { install_element_ve(&show_sgsn_cmd); @@ -1128,6 +1156,9 @@ install_element(SGSN_NODE, &cfg_sgsn_T3395_cmd); install_element(SGSN_NODE, &cfg_sgsn_T3397_cmd); + install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd); + install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd); + return 0; } diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 3e66978..1804280 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -33,6 +33,8 @@ $(top_builddir)/src/gprs/gprs_llc_xid.o \ $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ $(top_builddir)/src/gprs/slhc.o \ + $(top_builddir)/src/gprs/gprs_sndcp_comp.o \ + $(top_builddir)/src/gprs/gprs_sndcp_pcomp.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ -- To view, visit https://gerrit.osmocom.org/642 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 Gerrit-PatchSet: 16 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Wed Aug 17 14:28:46 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Wed, 17 Aug 2016 14:28:46 +0000 Subject: [PATCH] openbsc[master]: V42BIS integration and unit test In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/644 to look at the new patch set (#21). V42BIS integration and unit test The previously committed SPANDSP v42bis implementation has been edited to function outside the SPANDSP library. Debug printf statements were changed into DEBUGP statements. Als removed the assembely code in top_bit(). Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d --- M openbsc/.gitignore M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/debug.h M openbsc/include/openbsc/v42bis.h R openbsc/include/openbsc/v42bis_private.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/sgsn_main.c M openbsc/src/gprs/v42bis.c M openbsc/tests/Makefile.am M openbsc/tests/testsuite.at A openbsc/tests/v42bis/Makefile.am A openbsc/tests/v42bis/v42bis_test.c A openbsc/tests/v42bis/v42bis_test.ok 14 files changed, 252 insertions(+), 24 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/44/644/21 diff --git a/openbsc/.gitignore b/openbsc/.gitignore index e75b9eb..6fbd463 100644 --- a/openbsc/.gitignore +++ b/openbsc/.gitignore @@ -84,6 +84,7 @@ tests/xid/xid_test tests/sndcp_xid/sndcp_xid_test tests/slhc/slhc_test +tests/v42bis/v42bis_test tests/atconfig tests/atlocal diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 18980b0..1df14fe 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -232,6 +232,7 @@ tests/xid/Makefile tests/sndcp_xid/Makefile tests/slhc/Makefile + tests/v42bis/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 88a7e2c..bc56d0d 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,7 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ - slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h + slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h v42bis.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 90ddca5..ca3d4ad 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -37,6 +37,7 @@ DGTPHUB, DRANAP, DSUA, + DV42BIS, Debug_LastEntry, }; diff --git a/openbsc/include/openbsc/v42bis.h b/openbsc/include/openbsc/v42bis.h index f13e5c5..1025296 100644 --- a/openbsc/include/openbsc/v42bis.h +++ b/openbsc/include/openbsc/v42bis.h @@ -33,9 +33,13 @@ \section v42bis_page_sec_2 How does it work? */ +#include + #if !defined(_SPANDSP_V42BIS_H_) #define _SPANDSP_V42BIS_H_ +#define SPAN_DECLARE(x) x + #define V42BIS_MAX_BITS 12 #define V42BIS_MAX_CODEWORDS 4096 /* 2^V42BIS_MAX_BITS */ #define V42BIS_TABLE_SIZE 5021 /* This should be a prime >(2^V42BIS_MAX_BITS) */ diff --git a/openbsc/include/openbsc/private_v42bis.h b/openbsc/include/openbsc/v42bis_private.h similarity index 100% rename from openbsc/include/openbsc/private_v42bis.h rename to openbsc/include/openbsc/v42bis_private.h diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 2910c02..f479d56 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -27,7 +27,7 @@ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ - slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c + slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c v42bis.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c index 894ce84..44a8921 100644 --- a/openbsc/src/gprs/sgsn_main.c +++ b/openbsc/src/gprs/sgsn_main.c @@ -297,6 +297,11 @@ .description = "RFC1144 TCP/IP Header compression (SLHC)", .enabled = 1, .loglevel = LOGL_DEBUG, }, + [DV42BIS] = { + .name = "DV42BIS", + .description = "V42.bis data compression (SNDCP)", + .enabled = 1, .loglevel = LOGL_DEBUG, + } }; static const struct log_info gprs_log_info = { diff --git a/openbsc/src/gprs/v42bis.c b/openbsc/src/gprs/v42bis.c index 6d38916..de9c2af 100644 --- a/openbsc/src/gprs/v42bis.c +++ b/openbsc/src/gprs/v42bis.c @@ -31,9 +31,8 @@ /*! \file */ -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif +#define FALSE 0 +#define TRUE 1 #include #include @@ -44,13 +43,10 @@ #include #include -#include "spandsp/telephony.h" -#include "spandsp/logging.h" -#include "spandsp/bit_operations.h" -#include "spandsp/v42bis.h" +#include +#include +#include -#include "spandsp/private/logging.h" -#include "spandsp/private/v42bis.h" /* Fixed parameters from the spec. */ #define V42BIS_N3 8 /* Character size (bits) */ @@ -310,7 +306,7 @@ { if (ss->transparent) { - printf("Going compressed\n"); + DEBUGP(DV42BIS,"Going compressed\n"); /* 7.8.1 Transition to compressed mode */ /* Switch out of transparent now, between codes. We need to send the octet which did not match, just before switching. */ @@ -332,7 +328,7 @@ { if (!ss->transparent) { - printf("Going transparent\n"); + DEBUGP(DV42BIS,"Going transparent\n"); /* 7.8.2 Transition to transparent mode */ /* Switch into transparent now, between codes, and the unmatched octet should go out in transparent mode, just below */ @@ -401,7 +397,7 @@ { if (s->compress.dict[i].parent_code != 0xFFFF) { - printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); + DEBUGP(DV42BIS,"Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); } } return 0; @@ -454,13 +450,13 @@ ss->escaped = FALSE; if (code == V42BIS_ECM) { - printf("Hit V42BIS_ECM\n"); + DEBUGP(DV42BIS,"Hit V42BIS_ECM\n"); ss->transparent = FALSE; code_len = ss->v42bis_parm_c2; } else if (code == V42BIS_EID) { - printf("Hit V42BIS_EID\n"); + DEBUGP(DV42BIS,"Hit V42BIS_EID\n"); ss->output_buf[ss->output_octet_count++] = ss->escape_code - 1; if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) { @@ -470,11 +466,11 @@ } else if (code == V42BIS_RESET) { - printf("Hit V42BIS_RESET\n"); + DEBUGP(DV42BIS,"Hit V42BIS_RESET\n"); } else { - printf("Hit V42BIS_???? - %" PRIu32 "\n", code); + DEBUGP(DV42BIS,"Hit V42BIS_???? - %" PRIu32 "\n", code); } } else if (code == ss->escape_code) @@ -500,17 +496,17 @@ switch (new_code) { case V42BIS_ETM: - printf("Hit V42BIS_ETM\n"); + DEBUGP(DV42BIS,"Hit V42BIS_ETM\n"); ss->transparent = TRUE; code_len = 8; break; case V42BIS_FLUSH: - printf("Hit V42BIS_FLUSH\n"); + DEBUGP(DV42BIS,"Hit V42BIS_FLUSH\n"); v42bis_decompress_flush(s); break; case V42BIS_STEPUP: /* We need to increase the codeword size */ - printf("Hit V42BIS_STEPUP\n"); + DEBUGP(DV42BIS,"Hit V42BIS_STEPUP\n"); if (ss->v42bis_parm_c3 >= s->v42bis_parm_n2) { /* Invalid condition */ @@ -547,7 +543,7 @@ /* Trace back through the octets which form the string, and output them. */ while (code >= V42BIS_N5) { -if (code > 4095) {printf("Code is 0x%" PRIu32 "\n", code); exit(2);} +if (code > 4095) {DEBUGP(DV42BIS,"Code is 0x%" PRIu32 "\n", code); exit(2);} *string-- = ss->dict[code].node_octet; code = ss->dict[code].parent_code; } @@ -631,7 +627,7 @@ { if (s->decompress.dict[i].parent_code != 0xFFFF) { - printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); + DEBUGP(DV42BIS,"Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); } } return 0; diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index d5aa356..7acebc0 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid slhc +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid slhc v42bis if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index 5f37b8e..f18b734 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -141,3 +141,9 @@ cat $abs_srcdir/slhc/slhc_test.ok > expout AT_CHECK([$abs_top_builddir/tests/slhc/slhc_test], [], [expout], [ignore]) AT_CLEANUP + +AT_SETUP([v42bis]) +AT_KEYWORDS([v42bis]) +cat $abs_srcdir/v42bis/v42bis_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/v42bis/v42bis_test], [], [expout], [ignore]) +AT_CLEANUP diff --git a/openbsc/tests/v42bis/Makefile.am b/openbsc/tests/v42bis/Makefile.am new file mode 100644 index 0000000..9001c0f --- /dev/null +++ b/openbsc/tests/v42bis/Makefile.am @@ -0,0 +1,21 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) + +EXTRA_DIST = v42bis_test.ok + +noinst_PROGRAMS = v42bis_test + +v42bis_test_SOURCES = v42bis_test.c + +v42bis_test_LDADD = \ + $(top_builddir)/src/gprs/v42bis.o \ + $(top_builddir)/src/libcommon/libcommon.a \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOGB_LIBS) \ + $(LIBCARES_LIBS) \ + $(LIBCRYPTO_LIBS) \ + -lgtp -lrt -lm + + diff --git a/openbsc/tests/v42bis/v42bis_test.c b/openbsc/tests/v42bis/v42bis_test.c new file mode 100644 index 0000000..aad94e3 --- /dev/null +++ b/openbsc/tests/v42bis/v42bis_test.c @@ -0,0 +1,189 @@ +/* Test v42bis Compression/Decompression */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#define BLOCK_SIZE 100 +#define MAX_BLOCK_SIZE 2048 + +/* A struct to capture the output data of compressor and decompressor */ +struct v42bis_output_buffer_t { + uint8_t *buf; + uint8_t *buf_pointer; + int len; +}; + +/* A simple testpattern generator */ +static void gen_test_pattern(uint8_t *data, int len) +{ + int i; + for (i = 0; i < len; i++) + data[i] = i & 0xF0; +} + +/* Handler to capture the output data from the compressor */ +void tx_v42bis_frame_handler(void *user_data, const uint8_t *pkt, int len) +{ + struct v42bis_output_buffer_t *output_buffer = + (struct v42bis_output_buffer_t *)user_data; + memcpy(output_buffer->buf_pointer, pkt, len); + output_buffer->buf_pointer += len; + output_buffer->len += len; + return; +} + +/* Handler to capture the output data from the decompressor */ +void tx_v42bis_data_handler(void *user_data, const uint8_t *buf, int len) +{ + /* stub */ + return; +} + +/* Handler to capture the output data from the compressor */ +void rx_v42bis_frame_handler(void *user_data, const uint8_t *pkt, int len) +{ + /* stub */ + return; +} + +/* Handler to capture the output data from the decompressor */ +void rx_v42bis_data_handler(void *user_data, const uint8_t *buf, int len) +{ + struct v42bis_output_buffer_t *output_buffer = + (struct v42bis_output_buffer_t *)user_data; + memcpy(output_buffer->buf_pointer, buf, len); + output_buffer->buf_pointer += len; + output_buffer->len += len; + return; +} + +/* Test V42.bis compression and decompression */ +static void test_v42bis(const void *ctx) +{ + v42bis_state_t *tx_state; + v42bis_state_t *rx_state; + + uint8_t uncompressed_original[BLOCK_SIZE]; + uint8_t compressed[BLOCK_SIZE]; + uint8_t uncompressed[BLOCK_SIZE]; + + int rc; + struct v42bis_output_buffer_t compressed_data; + struct v42bis_output_buffer_t uncompressed_data; + + /* Initalize */ + tx_state = + v42bis_init(NULL, 3, MAX_BLOCK_SIZE, 6, &tx_v42bis_frame_handler, + NULL, MAX_BLOCK_SIZE, &tx_v42bis_data_handler, NULL, + MAX_BLOCK_SIZE); + OSMO_ASSERT(tx_state); + rx_state = + v42bis_init(NULL, 3, MAX_BLOCK_SIZE, 6, &rx_v42bis_frame_handler, + NULL, MAX_BLOCK_SIZE, &rx_v42bis_data_handler, NULL, + MAX_BLOCK_SIZE); + OSMO_ASSERT(rx_state); + v42bis_compression_control(tx_state, V42BIS_COMPRESSION_MODE_ALWAYS); + v42bis_compression_control(rx_state, V42BIS_COMPRESSION_MODE_ALWAYS); + + /* Generate test pattern for input */ + gen_test_pattern(uncompressed_original, sizeof(uncompressed_original)); + + /* Run compressor */ + compressed_data.buf = compressed; + compressed_data.buf_pointer = compressed; + compressed_data.len = 0; + tx_state->compress.user_data = (&compressed_data); + rc = v42bis_compress(tx_state, uncompressed_original, + sizeof(uncompressed_original)); + OSMO_ASSERT(rc == 0); + rc = v42bis_compress_flush(tx_state); + OSMO_ASSERT(rc == 0); + + /* Decompress again */ + uncompressed_data.buf = uncompressed; + uncompressed_data.buf_pointer = uncompressed; + uncompressed_data.len = 0; + rx_state->decompress.user_data = (&uncompressed_data); + rc = v42bis_decompress(rx_state, compressed_data.buf, + compressed_data.len); + OSMO_ASSERT(rc == 0); + rc = v42bis_decompress_flush(rx_state); + OSMO_ASSERT(rc == 0); + + /* Check results */ + printf("uncompressed_original= %s\n", + osmo_hexdump_nospc(uncompressed_original, + sizeof(uncompressed_original))); + printf("uncompressed= %s\n", + osmo_hexdump_nospc(uncompressed_data.buf, + uncompressed_data.len)); + printf("compressed= %s\n", + osmo_hexdump_nospc(compressed_data.buf, compressed_data.len)); + rc = memcmp(uncompressed, uncompressed_original, BLOCK_SIZE); + OSMO_ASSERT(rc == 0); +} + +static struct log_info_cat gprs_categories[] = { + [DV42BIS] = { + .name = "DV42BIS", + .description = "V42.bis data compression (SNDCP)", + .enabled = 1,.loglevel = LOGL_DEBUG, + } +}; + +static struct log_info info = { + .cat = gprs_categories, + .num_cat = ARRAY_SIZE(gprs_categories), +}; + +int main(int argc, char **argv) +{ + void *v42bis_ctx; + + osmo_init_logging(&info); + + v42bis_ctx = talloc_named_const(NULL, 0, "v42bis_ctx"); + + test_v42bis(v42bis_ctx); + printf("Done\n"); + + talloc_report_full(v42bis_ctx, stderr); + OSMO_ASSERT(talloc_total_blocks(v42bis_ctx) == 1); + return 0; +} + +/* stubs */ +struct osmo_prim_hdr; +int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) +{ + abort(); +} diff --git a/openbsc/tests/v42bis/v42bis_test.ok b/openbsc/tests/v42bis/v42bis_test.ok new file mode 100644 index 0000000..16c8612 --- /dev/null +++ b/openbsc/tests/v42bis/v42bis_test.ok @@ -0,0 +1,4 @@ +uncompressed_original= 00000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060 +uncompressed= 00000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060 +compressed= 0180e0703824120a1309c1e0f0884424462385c2e190c868cc670f87c4221112190e27138a4522a5329c5e2f188c464c6638d804 +Done -- To view, visit https://gerrit.osmocom.org/644 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d Gerrit-PatchSet: 21 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Thu Aug 18 01:26:41 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 18 Aug 2016 01:26:41 +0000 Subject: [PATCH] osmo-iuh[master]: hnbgw: add copyright to vty_info Message-ID: Review at https://gerrit.osmocom.org/705 hnbgw: add copyright to vty_info Change-Id: I702b606837199ab64c3590546900d4d30357b919 --- M src/hnbgw.c 1 file changed, 10 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/05/705/1 diff --git a/src/hnbgw.c b/src/hnbgw.c index 8608903..4211da9 100644 --- a/src/hnbgw.c +++ b/src/hnbgw.c @@ -56,6 +56,14 @@ #include "hnbgw_cn.h" #include "context_map.h" +static const char * const osmo_hnbgw_copyright = + "OsmoHNBGW - Osmocom Home Node B Gateway implementation\r\n" + "Copyright (C) 2016 by sysmocom s.f.m.c. GmbH \r\n" + "Contributions by Daniel Willmann, Harald Welte, Neels Hofmeyr\r\n" + "License AGPLv3+: GNU AGPL version 3 or later \r\n" + "This is free software: you are free to change and redistribute it.\r\n" + "There is NO WARRANTY, to the extent permitted by law.\r\n"; + static void *tall_hnb_ctx; void *talloc_asn1_ctx; @@ -397,7 +405,9 @@ if (rc < 0) exit(1); + vty_info.copyright = osmo_hnbgw_copyright; vty_init(&vty_info); + hnbgw_vty_init(); /* NOTE: if we add a config file, read the config before -- To view, visit https://gerrit.osmocom.org/705 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I702b606837199ab64c3590546900d4d30357b919 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Thu Aug 18 01:26:41 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 18 Aug 2016 01:26:41 +0000 Subject: [PATCH] osmo-iuh[master]: hnbgw: add cmdline arg parsing with default options Message-ID: Review at https://gerrit.osmocom.org/706 hnbgw: add cmdline arg parsing with default options Default options taken from osmo-nitb: -h --help This text. -d option --debug=DHNBAP:DSUA:DRUA:DRANAP:DMAIN Enable debugging. -D --daemonize Fork the process into a background daemon. -s --disable-color -T --timestamp Prefix every log line with a timestamp. -V --version Print the version of OsmoHNBGW. -e --log-level number Set a global loglevel. Change-Id: I931cee01c605c1b507c16041ada226cf963ea433 --- M src/hnbgw.c 1 file changed, 81 insertions(+), 3 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/06/706/1 diff --git a/src/hnbgw.c b/src/hnbgw.c index 4211da9..ff5fafe 100644 --- a/src/hnbgw.c +++ b/src/hnbgw.c @@ -326,8 +326,6 @@ .version = "0", }; -static int daemonize = 0; - static void vty_dump_hnb_info(struct vty *vty, struct hnb_context *hnb) { struct hnbgw_context_map *map; @@ -388,6 +386,83 @@ logging_vty_add_cmds(&hnbgw_log_info); } + +static struct { + int daemonize; +} hnbgw_cmdline_config = { + 0 +}; + +static void print_usage() +{ + printf("Usage: osmo-hnbgw\n"); +} + +static void print_help() +{ + printf(" -h --help This text.\n"); + printf(" -d option --debug=DHNBAP:DSUA:DRUA:DRANAP:DMAIN Enable debugging.\n"); + printf(" -D --daemonize Fork the process into a background daemon.\n"); + printf(" -s --disable-color\n"); + printf(" -T --timestamp Prefix every log line with a timestamp.\n"); + printf(" -V --version Print the version of OsmoHNBGW.\n"); + printf(" -e --log-level number Set a global loglevel.\n"); +} + +static void handle_options(int argc, char **argv) +{ + while (1) { + int option_index = 0, c; + static struct option long_options[] = { + {"help", 0, 0, 'h'}, + {"debug", 1, 0, 'd'}, + {"daemonize", 0, 0, 'D'}, + {"disable-color", 0, 0, 's'}, + {"timestamp", 0, 0, 'T'}, + {"version", 0, 0, 'V' }, + {"log-level", 1, 0, 'e'}, + {0, 0, 0, 0} + }; + + c = getopt_long(argc, argv, "hd:DsTVe:", + long_options, &option_index); + if (c == -1) + break; + + switch (c) { + case 'h': + print_usage(); + print_help(); + exit(0); + case 's': + log_set_use_color(osmo_stderr_target, 0); + break; + case 'd': + log_parse_category_mask(osmo_stderr_target, optarg); + break; + case 'D': + hnbgw_cmdline_config.daemonize = 1; + break; + case 'T': + log_set_print_timestamp(osmo_stderr_target, 1); + break; + case 'e': + log_set_log_level(osmo_stderr_target, atoi(optarg)); + break; + case 'V': + print_version(1); + exit(0); + break; + default: + /* catch unknown options *as well as* missing arguments. */ + fprintf(stderr, "Error in command line options. Exiting.\n"); + exit(-1); + break; + } + } +} + + int main(int argc, char **argv) { struct osmo_sccp_user *sua_user; @@ -409,6 +484,9 @@ vty_init(&vty_info); hnbgw_vty_init(); + + /* Handle options after vty_init(), for --version */ + handle_options(argc, argv); /* NOTE: if we add a config file, read the config before * fetching the telnet address with vty_get_bind_addr() */ @@ -443,7 +521,7 @@ } g_hnb_gw->iuh = srv; - if (daemonize) { + if (hnbgw_cmdline_config.daemonize) { rc = osmo_daemonize(); if (rc < 0) { perror("Error during daemonize"); -- To view, visit https://gerrit.osmocom.org/706 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I931cee01c605c1b507c16041ada226cf963ea433 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Thu Aug 18 01:26:41 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 18 Aug 2016 01:26:41 +0000 Subject: [PATCH] osmo-iuh[master]: hnbgw: add config file and -c cmdline option Message-ID: Review at https://gerrit.osmocom.org/707 hnbgw: add config file and -c cmdline option Change-Id: I6ac9fa17b35260031c55aab664124d466f60c937 --- M src/hnbgw.c 1 file changed, 16 insertions(+), 4 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/07/707/1 diff --git a/src/hnbgw.c b/src/hnbgw.c index ff5fafe..01f64a7 100644 --- a/src/hnbgw.c +++ b/src/hnbgw.c @@ -389,8 +389,10 @@ static struct { int daemonize; + const char *config_file; } hnbgw_cmdline_config = { - 0 + 0, + "osmo-hnbgw.cfg" }; static void print_usage() @@ -403,6 +405,7 @@ printf(" -h --help This text.\n"); printf(" -d option --debug=DHNBAP:DSUA:DRUA:DRANAP:DMAIN Enable debugging.\n"); printf(" -D --daemonize Fork the process into a background daemon.\n"); + printf(" -c --config-file filename The config file to use.\n"); printf(" -s --disable-color\n"); printf(" -T --timestamp Prefix every log line with a timestamp.\n"); printf(" -V --version Print the version of OsmoHNBGW.\n"); @@ -417,6 +420,7 @@ {"help", 0, 0, 'h'}, {"debug", 1, 0, 'd'}, {"daemonize", 0, 0, 'D'}, + {"config-file", 1, 0, 'c'}, {"disable-color", 0, 0, 's'}, {"timestamp", 0, 0, 'T'}, {"version", 0, 0, 'V' }, @@ -424,7 +428,7 @@ {0, 0, 0, 0} }; - c = getopt_long(argc, argv, "hd:DsTVe:", + c = getopt_long(argc, argv, "hd:Dc:sTVe:", long_options, &option_index); if (c == -1) break; @@ -442,6 +446,9 @@ break; case 'D': hnbgw_cmdline_config.daemonize = 1; + break; + case 'c': + hnbgw_cmdline_config.config_file = optarg; break; case 'T': log_set_print_timestamp(osmo_stderr_target, 1); @@ -488,8 +495,13 @@ /* Handle options after vty_init(), for --version */ handle_options(argc, argv); - /* NOTE: if we add a config file, read the config before - * fetching the telnet address with vty_get_bind_addr() */ + rc = vty_read_config_file(hnbgw_cmdline_config.config_file, NULL); + if (rc < 0) { + LOGP(DMAIN, LOGL_FATAL, "Failed to parse the config file: '%s'\n", + hnbgw_cmdline_config.config_file); + return 1; + } + LOGP(DMAIN, LOGL_NOTICE, "VTY at %s %d\n", vty_get_bind_addr(), 2323); rc = telnet_init_dynif(NULL, g_hnb_gw, vty_get_bind_addr(), 2323); -- To view, visit https://gerrit.osmocom.org/707 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I6ac9fa17b35260031c55aab664124d466f60c937 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Thu Aug 18 01:26:41 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 18 Aug 2016 01:26:41 +0000 Subject: [PATCH] osmo-iuh[master]: hnbgw: make cmdline options stronger than config file Message-ID: Review at https://gerrit.osmocom.org/708 hnbgw: make cmdline options stronger than config file Now that a config file gets parsed after the command line options, e.g. the 'logging timestamp 0' config item is stronger than a -T commandline option. So rather store the cmdline options to take effect after config file parsing. This adds a stupid 'log_disable_color = true' reverse boolean logic, which is unavoidable if we want to use the same default cmdline options as osmo-nitb / osmo-cscn. Change-Id: I16ad55b173a443c36b71dc6b70f58695f6665312 --- M src/hnbgw.c 1 file changed, 29 insertions(+), 5 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/08/708/1 diff --git a/src/hnbgw.c b/src/hnbgw.c index 01f64a7..4cb3c69 100644 --- a/src/hnbgw.c +++ b/src/hnbgw.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -390,9 +391,17 @@ static struct { int daemonize; const char *config_file; + bool log_disable_color; + bool log_enable_timestamp; + int log_level; + const char *log_category_mask; } hnbgw_cmdline_config = { 0, - "osmo-hnbgw.cfg" + "osmo-hnbgw.cfg", + true, + false, + 0, + NULL, }; static void print_usage() @@ -439,10 +448,10 @@ print_help(); exit(0); case 's': - log_set_use_color(osmo_stderr_target, 0); + hnbgw_cmdline_config.log_disable_color = true; break; case 'd': - log_parse_category_mask(osmo_stderr_target, optarg); + hnbgw_cmdline_config.log_category_mask = optarg; break; case 'D': hnbgw_cmdline_config.daemonize = 1; @@ -451,10 +460,10 @@ hnbgw_cmdline_config.config_file = optarg; break; case 'T': - log_set_print_timestamp(osmo_stderr_target, 1); + hnbgw_cmdline_config.log_enable_timestamp = true; break; case 'e': - log_set_log_level(osmo_stderr_target, atoi(optarg)); + hnbgw_cmdline_config.log_level = atoi(optarg); break; case 'V': print_version(1); @@ -502,6 +511,21 @@ return 1; } + /* + * cmdline options take precedence over config file, but if no options + * were passed we must not override the config file. + */ + if (hnbgw_cmdline_config.log_disable_color) + log_set_use_color(osmo_stderr_target, 0); + if (hnbgw_cmdline_config.log_category_mask) + log_parse_category_mask(osmo_stderr_target, + hnbgw_cmdline_config.log_category_mask); + if (hnbgw_cmdline_config.log_enable_timestamp) + log_set_print_timestamp(osmo_stderr_target, 1); + if (hnbgw_cmdline_config.log_level) + log_set_log_level(osmo_stderr_target, + hnbgw_cmdline_config.log_level); + LOGP(DMAIN, LOGL_NOTICE, "VTY at %s %d\n", vty_get_bind_addr(), 2323); rc = telnet_init_dynif(NULL, g_hnb_gw, vty_get_bind_addr(), 2323); -- To view, visit https://gerrit.osmocom.org/708 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I16ad55b173a443c36b71dc6b70f58695f6665312 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Thu Aug 18 01:26:42 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 18 Aug 2016 01:26:42 +0000 Subject: [PATCH] osmo-iuh[master]: hnbgw: move vty commands out to new hnbgw_vty.c Message-ID: Review at https://gerrit.osmocom.org/709 hnbgw: move vty commands out to new hnbgw_vty.c Pass g_hnb_gw and tall_hnb_ctx to hnbgw_vty_init() as they are no longer statically available. Change-Id: If85c1b97a240bd1dcf9f367ea6fca857d542ab22 --- M src/Makefile.am M src/hnbgw.c M src/hnbgw.h A src/hnbgw_vty.c 4 files changed, 95 insertions(+), 63 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/09/709/1 diff --git a/src/Makefile.am b/src/Makefile.am index 2d078f3..17e60e2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -46,6 +46,7 @@ rua_encoder.c rua_decoder.c rua_common.c \ rua_msg_factory.c \ hnbgw.c hnbgw_hnbap.c hnbgw_rua.c hnbgw_ranap.c \ + hnbgw_vty.c \ context_map.c hnbgw_cn.c osmo_hnbgw_LDADD = $(OSMOCORE_LIBS) $(OSMOVTY_LIBS) $(OSMOGSM_LIBS) \ diff --git a/src/hnbgw.c b/src/hnbgw.c index 4cb3c69..d2e7b30 100644 --- a/src/hnbgw.c +++ b/src/hnbgw.c @@ -1,6 +1,7 @@ /* main application for hnb-gw part of osmo-iuh */ /* (C) 2015 by Harald Welte + * (C) 2016 by sysmocom s.f.m.c. GmbH * All Rights Reserved * * This program is free software; you can redistribute it and/or modify @@ -43,7 +44,6 @@ #include #include -#include #include @@ -327,67 +327,6 @@ .version = "0", }; -static void vty_dump_hnb_info(struct vty *vty, struct hnb_context *hnb) -{ - struct hnbgw_context_map *map; - - vty_out(vty, "HNB \"%s\" MCC %u MNC %u LAC %u RAC %u SAC %u CID %u%s", hnb->identity_info, - hnb->id.mcc, hnb->id.mnc, hnb->id.lac, hnb->id.rac, hnb->id.sac, hnb->id.cid, - VTY_NEWLINE); - vty_out(vty, " HNBAP ID %u RUA ID %u%s", hnb->hnbap_stream, hnb->rua_stream, VTY_NEWLINE); - - llist_for_each_entry(map, &hnb->map_list, hnb_list) { - vty_out(vty, " Map %u->%u (RUA->SUA) cnlink=%p state=%u%s", map->rua_ctx_id, map->scu_conn_id, - map->cn_link, map->state, VTY_NEWLINE); - - } -} - -static void vty_dump_ue_info(struct vty *vty, struct ue_context *ue) -{ - vty_out(vty, "UE IMSI \"%s\" context ID %u%s", ue->imsi, ue->context_id, VTY_NEWLINE); -} - -DEFUN(show_hnb, show_hnb_cmd, "show hnb all", SHOW_STR "Display information about a HNB") -{ - struct hnb_context *hnb; - - llist_for_each_entry(hnb, &g_hnb_gw->hnb_list, list) { - vty_dump_hnb_info(vty, hnb); - } - - return CMD_SUCCESS; -} - -DEFUN(show_ue, show_ue_cmd, "show ue all", SHOW_STR "Display information about a UE") -{ - struct ue_context *ue; - - llist_for_each_entry(ue, &g_hnb_gw->ue_list, list) { - vty_dump_ue_info(vty, ue); - } - - return CMD_SUCCESS; -} - -DEFUN(show_talloc, show_talloc_cmd, "show talloc", SHOW_STR "Display talloc info") -{ - talloc_report_full(tall_hnb_ctx, stderr); - talloc_report_full(talloc_asn1_ctx, stderr); - - return CMD_SUCCESS; -} - -static void hnbgw_vty_init(void) -{ - install_element_ve(&show_hnb_cmd); - install_element_ve(&show_ue_cmd); - install_element_ve(&show_talloc_cmd); - - logging_vty_add_cmds(&hnbgw_log_info); -} - - static struct { int daemonize; const char *config_file; @@ -499,7 +438,8 @@ vty_info.copyright = osmo_hnbgw_copyright; vty_init(&vty_info); - hnbgw_vty_init(); + hnbgw_vty_init(g_hnb_gw, tall_hnb_ctx); + logging_vty_add_cmds(&hnbgw_log_info); /* Handle options after vty_init(), for --version */ handle_options(argc, argv); diff --git a/src/hnbgw.h b/src/hnbgw.h index 9f010d9..9b5ae85 100644 --- a/src/hnbgw.h +++ b/src/hnbgw.h @@ -132,6 +132,8 @@ struct hnbgw_cnlink *cnlink_ps; }; +extern void *talloc_asn1_ctx; + struct ue_context *ue_context_by_id(struct hnb_gw *gw, uint32_t id); struct ue_context *ue_context_by_imsi(struct hnb_gw *gw, const char *imsi); struct ue_context *ue_context_alloc(struct hnb_context *hnb, const char *imsi); @@ -139,3 +141,5 @@ struct hnb_context *hnb_context_alloc(struct hnb_gw *gw, struct osmo_stream_srv_link *link, int new_fd); void hnb_context_release(struct hnb_context *ctx); + +void hnbgw_vty_init(struct hnb_gw *gw, void *tall_ctx); diff --git a/src/hnbgw_vty.c b/src/hnbgw_vty.c new file mode 100644 index 0000000..f29b849 --- /dev/null +++ b/src/hnbgw_vty.c @@ -0,0 +1,87 @@ +/* HNB-GW interface to quagga VTY */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include + +#include "hnbgw.h" +#include "context_map.h" + +static void *tall_hnb_ctx = NULL; +static struct hnb_gw *g_hnb_gw = NULL; + +static void vty_dump_hnb_info(struct vty *vty, struct hnb_context *hnb) +{ + struct hnbgw_context_map *map; + + vty_out(vty, "HNB \"%s\" MCC %u MNC %u LAC %u RAC %u SAC %u CID %u%s", hnb->identity_info, + hnb->id.mcc, hnb->id.mnc, hnb->id.lac, hnb->id.rac, hnb->id.sac, hnb->id.cid, + VTY_NEWLINE); + vty_out(vty, " HNBAP ID %u RUA ID %u%s", hnb->hnbap_stream, hnb->rua_stream, VTY_NEWLINE); + + llist_for_each_entry(map, &hnb->map_list, hnb_list) { + vty_out(vty, " Map %u->%u (RUA->SUA) cnlink=%p state=%u%s", map->rua_ctx_id, map->scu_conn_id, + map->cn_link, map->state, VTY_NEWLINE); + + } +} + +static void vty_dump_ue_info(struct vty *vty, struct ue_context *ue) +{ + vty_out(vty, "UE IMSI \"%s\" context ID %u%s", ue->imsi, ue->context_id, VTY_NEWLINE); +} + +DEFUN(show_hnb, show_hnb_cmd, "show hnb all", SHOW_STR "Display information about a HNB") +{ + struct hnb_context *hnb; + + llist_for_each_entry(hnb, &g_hnb_gw->hnb_list, list) { + vty_dump_hnb_info(vty, hnb); + } + + return CMD_SUCCESS; +} + +DEFUN(show_ue, show_ue_cmd, "show ue all", SHOW_STR "Display information about a UE") +{ + struct ue_context *ue; + + llist_for_each_entry(ue, &g_hnb_gw->ue_list, list) { + vty_dump_ue_info(vty, ue); + } + + return CMD_SUCCESS; +} + +DEFUN(show_talloc, show_talloc_cmd, "show talloc", SHOW_STR "Display talloc info") +{ + talloc_report_full(tall_hnb_ctx, stderr); + talloc_report_full(talloc_asn1_ctx, stderr); + + return CMD_SUCCESS; +} + +void hnbgw_vty_init(struct hnb_gw *gw, void *tall_ctx) +{ + g_hnb_gw = gw; + tall_hnb_ctx = tall_ctx; + install_element_ve(&show_hnb_cmd); + install_element_ve(&show_ue_cmd); + install_element_ve(&show_talloc_cmd); +} -- To view, visit https://gerrit.osmocom.org/709 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: If85c1b97a240bd1dcf9f367ea6fca857d542ab22 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Thu Aug 18 01:26:42 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 18 Aug 2016 01:26:42 +0000 Subject: [PATCH] osmo-iuh[master]: hnbgw vty: add empty hnbgw and hnbgw/iuh vty nodes Message-ID: Review at https://gerrit.osmocom.org/710 hnbgw vty: add empty hnbgw and hnbgw/iuh vty nodes Add include/osmocom/iuh/ named after this project (osmo-iuh), and add vty.h to define VTY node enum values. Also add (to) Makefile.am and configure.ac to include in the build. An upcoming commit will add the actual first config item to the hnbgw/iuh node. Change-Id: I71545823d3bd81cb888c85df8e298a56c98bf131 --- M configure.ac M include/osmocom/Makefile.am A include/osmocom/iuh/Makefile.am A include/osmocom/iuh/vty.h M src/hnbgw_vty.c 5 files changed, 62 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/10/710/1 diff --git a/configure.ac b/configure.ac index fc8c737..38e3b4c 100644 --- a/configure.ac +++ b/configure.ac @@ -41,4 +41,5 @@ include/osmocom/hnbap/Makefile include/osmocom/ranap/Makefile include/osmocom/rua/Makefile + include/osmocom/iuh/Makefile ) diff --git a/include/osmocom/Makefile.am b/include/osmocom/Makefile.am index f89b5dc..246cb34 100644 --- a/include/osmocom/Makefile.am +++ b/include/osmocom/Makefile.am @@ -1,2 +1,2 @@ -SUBDIRS = hnbap ranap rua +SUBDIRS = hnbap ranap rua iuh diff --git a/include/osmocom/iuh/Makefile.am b/include/osmocom/iuh/Makefile.am new file mode 100644 index 0000000..e2f7126 --- /dev/null +++ b/include/osmocom/iuh/Makefile.am @@ -0,0 +1,2 @@ +noinst_HEADERS = \ + vty.h diff --git a/include/osmocom/iuh/vty.h b/include/osmocom/iuh/vty.h new file mode 100644 index 0000000..905a949 --- /dev/null +++ b/include/osmocom/iuh/vty.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +enum osmo_iuh_vty_node { + HNBGW_NODE = _LAST_OSMOVTY_NODE + 1, + IUH_NODE, +}; + diff --git a/src/hnbgw_vty.c b/src/hnbgw_vty.c index f29b849..0845ff7 100644 --- a/src/hnbgw_vty.c +++ b/src/hnbgw_vty.c @@ -20,11 +20,39 @@ #include +#include + #include "hnbgw.h" #include "context_map.h" static void *tall_hnb_ctx = NULL; static struct hnb_gw *g_hnb_gw = NULL; + +static struct cmd_node hnbgw_node = { + HNBGW_NODE, + "%s(config-hnbgw)# ", + 1, +}; + +DEFUN(cfg_hnbgw, cfg_hnbgw_cmd, + "hnbgw", "Configure HNBGW options") +{ + vty->node = HNBGW_NODE; + return CMD_SUCCESS; +} + +static struct cmd_node iuh_node = { + IUH_NODE, + "%s(config-hnbgw-iuh)# ", + 1, +}; + +DEFUN(cfg_hnbgw_iuh, cfg_hnbgw_iuh_cmd, + "iuh", "Configure Iuh options") +{ + vty->node = IUH_NODE; + return CMD_SUCCESS; +} static void vty_dump_hnb_info(struct vty *vty, struct hnb_context *hnb) { @@ -77,10 +105,31 @@ return CMD_SUCCESS; } +static int config_write_hnbgw(struct vty *vty) +{ + vty_out(vty, "hnbgw%s", VTY_NEWLINE); + return CMD_SUCCESS; +} + +static int config_write_hnbgw_iuh(struct vty *vty) +{ + vty_out(vty, " iuh%s", VTY_NEWLINE); + return CMD_SUCCESS; +} + void hnbgw_vty_init(struct hnb_gw *gw, void *tall_ctx) { g_hnb_gw = gw; tall_hnb_ctx = tall_ctx; + + install_element(CONFIG_NODE, &cfg_hnbgw_cmd); + install_node(&hnbgw_node, config_write_hnbgw); + vty_install_default(HNBGW_NODE); + + install_element(HNBGW_NODE, &cfg_hnbgw_iuh_cmd); + install_node(&iuh_node, config_write_hnbgw_iuh); + vty_install_default(IUH_NODE); + install_element_ve(&show_hnb_cmd); install_element_ve(&show_ue_cmd); install_element_ve(&show_talloc_cmd); -- To view, visit https://gerrit.osmocom.org/710 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I71545823d3bd81cb888c85df8e298a56c98bf131 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Thu Aug 18 01:26:42 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 18 Aug 2016 01:26:42 +0000 Subject: [PATCH] osmo-iuh[master]: hnbgw: make Iuh bind address configurable via VTY Message-ID: Review at https://gerrit.osmocom.org/711 hnbgw: make Iuh bind address configurable via VTY Add config node hnbgw/iuh/bind, taking an IPv4 address. Use this address to bind the Iuh server. This is particularly useful for the ip.access nano3G, which is very sensitive with SCTP addresses that don't respond to SCTP heartbeats. If the hnbgw listens on 0.0.0.0, there will be SCTP heartbeats for all local interfaces on the machine that the hnbgw runs on; the nano3G will interpret the "missing", or rather, redundant heartbeat acks for the interfaces that aren't really related to the Iuh server and assume a broken Iuh link, leading to an Iuh shutdown and reconnection, looping every minute or so. By binding the hnbgw to only one local interface, the SCTP addresses can be reduced and "missing" heartbeat acks can be avoided. Change-Id: Ie2749c152b878e17aa65dfb806826357d5c494f1 --- M src/hnbgw.c M src/hnbgw.h M src/hnbgw_vty.c 3 files changed, 38 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/11/711/1 diff --git a/src/hnbgw.c b/src/hnbgw.c index d2e7b30..4f23e8d 100644 --- a/src/hnbgw.c +++ b/src/hnbgw.c @@ -289,6 +289,14 @@ return 0; } +const char *hnbgw_get_iuh_bind_addr(struct hnb_gw *gw) +{ + const char *addr = gw->config.iuh_bind_addr; + if (!addr) + addr = HNBGW_IUH_BIND_ADDR_DEFAULT; + return addr; +} + static const struct log_info_cat log_cat[] = { [DMAIN] = { .name = "DMAIN", .loglevel = LOGL_DEBUG, .enabled = 1, @@ -480,6 +488,9 @@ g_hnb_gw->cnlink_cs = hnbgw_cnlink_init(g_hnb_gw, "127.0.0.1", SUA_PORT, 0); g_hnb_gw->cnlink_ps = hnbgw_cnlink_init(g_hnb_gw, "127.0.0.2", SUA_PORT, 1); + LOGP(DMAIN, LOGL_NOTICE, "Listening for Iuh at %s %d\n", + hnbgw_get_iuh_bind_addr(g_hnb_gw), + g_hnb_gw->config.iuh_listen_port); srv = osmo_stream_srv_link_create(tall_hnb_ctx); if (!srv) { perror("cannot create server"); @@ -487,7 +498,7 @@ } osmo_stream_srv_link_set_data(srv, g_hnb_gw); osmo_stream_srv_link_set_proto(srv, IPPROTO_SCTP); - osmo_stream_srv_link_set_addr(srv, "0.0.0.0"); + osmo_stream_srv_link_set_addr(srv, hnbgw_get_iuh_bind_addr(g_hnb_gw)); osmo_stream_srv_link_set_port(srv, g_hnb_gw->config.iuh_listen_port); osmo_stream_srv_link_set_accept_cb(srv, accept_cb); diff --git a/src/hnbgw.h b/src/hnbgw.h index 9b5ae85..21a9602 100644 --- a/src/hnbgw.h +++ b/src/hnbgw.h @@ -107,8 +107,11 @@ struct hnb_context *hnb; }; +#define HNBGW_IUH_BIND_ADDR_DEFAULT "0.0.0.0" + struct hnb_gw { struct { + const char *iuh_bind_addr; /*! SCTP port for Iuh listening */ uint16_t iuh_listen_port; /*! The UDP port where we receive multiplexed CS user @@ -143,3 +146,9 @@ void hnb_context_release(struct hnb_context *ctx); void hnbgw_vty_init(struct hnb_gw *gw, void *tall_ctx); + +/* + * Return IP address passed to the hnbgw/iuh/bind command, or + * IUH_BIND_ADDR_DEFAULT + */ +const char *hnbgw_get_iuh_bind_addr(struct hnb_gw *gw); diff --git a/src/hnbgw_vty.c b/src/hnbgw_vty.c index 0845ff7..1673c0c 100644 --- a/src/hnbgw_vty.c +++ b/src/hnbgw_vty.c @@ -105,6 +105,15 @@ return CMD_SUCCESS; } +DEFUN(cfg_hnbgw_iuh_bind, cfg_hnbgw_iuh_bind_cmd, "bind A.B.C.D", + "Accept Iuh connections on local interface\n" + "Local interface IP address (default: " HNBGW_IUH_BIND_ADDR_DEFAULT ")") +{ + talloc_free((void*)g_hnb_gw->config.iuh_bind_addr); + g_hnb_gw->config.iuh_bind_addr = talloc_strdup(tall_hnb_ctx, argv[0]); + return CMD_SUCCESS; +} + static int config_write_hnbgw(struct vty *vty) { vty_out(vty, "hnbgw%s", VTY_NEWLINE); @@ -113,7 +122,14 @@ static int config_write_hnbgw_iuh(struct vty *vty) { + const char *addr; + vty_out(vty, " iuh%s", VTY_NEWLINE); + + addr = g_hnb_gw->config.iuh_bind_addr; + if (addr && (strcmp(addr, HNBGW_IUH_BIND_ADDR_DEFAULT) != 0)) + vty_out(vty, " bind %s%s", addr, VTY_NEWLINE); + return CMD_SUCCESS; } @@ -129,6 +145,7 @@ install_element(HNBGW_NODE, &cfg_hnbgw_iuh_cmd); install_node(&iuh_node, config_write_hnbgw_iuh); vty_install_default(IUH_NODE); + install_element(IUH_NODE, &cfg_hnbgw_iuh_bind_cmd); install_element_ve(&show_hnb_cmd); install_element_ve(&show_ue_cmd); -- To view, visit https://gerrit.osmocom.org/711 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ie2749c152b878e17aa65dfb806826357d5c494f1 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Thu Aug 18 01:26:42 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 18 Aug 2016 01:26:42 +0000 Subject: [PATCH] osmo-iuh[master]: doc: add example osmo-hnbgw.cfg Message-ID: Review at https://gerrit.osmocom.org/712 doc: add example osmo-hnbgw.cfg Change-Id: I424ccdea02578edc7816e4d23a9ea7c5729315d8 --- A doc/examples/osmo-hnbgw.cfg 1 file changed, 32 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/12/712/1 diff --git a/doc/examples/osmo-hnbgw.cfg b/doc/examples/osmo-hnbgw.cfg new file mode 100644 index 0000000..1cc98c2 --- /dev/null +++ b/doc/examples/osmo-hnbgw.cfg @@ -0,0 +1,32 @@ +! +! OsmoHNBGW (0) configuration saved from vty +!! +! +log stderr + logging filter all 1 + logging color 1 + logging print category 0 + logging timestamp 0 + logging level all everything + logging level main debug + logging level hnbap debug + logging level sua debug + logging level rua debug + logging level ranap debug + logging level lglobal notice + logging level llapd notice + logging level linp notice + logging level lmux notice + logging level lmi notice + logging level lmib notice + logging level lsms notice + logging level lctrl notice + logging level lgtp notice + logging level lstats notice +! +line vty + no login +! +hnbgw + iuh + bind 192.168.0.132 -- To view, visit https://gerrit.osmocom.org/712 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I424ccdea02578edc7816e4d23a9ea7c5729315d8 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Thu Aug 18 05:31:29 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 18 Aug 2016 05:31:29 +0000 Subject: osmo-iuh[master]: hnbgw: add copyright to vty_info In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/705 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I702b606837199ab64c3590546900d4d30357b919 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 18 05:35:23 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 18 Aug 2016 05:35:23 +0000 Subject: osmo-iuh[master]: hnbgw: add cmdline arg parsing with default options In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/706 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I931cee01c605c1b507c16041ada226cf963ea433 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 18 05:35:36 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 18 Aug 2016 05:35:36 +0000 Subject: osmo-iuh[master]: hnbgw: add config file and -c cmdline option In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/707 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I6ac9fa17b35260031c55aab664124d466f60c937 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 18 05:35:49 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 18 Aug 2016 05:35:49 +0000 Subject: osmo-iuh[master]: hnbgw: make cmdline options stronger than config file In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/708 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I16ad55b173a443c36b71dc6b70f58695f6665312 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 18 05:35:53 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 18 Aug 2016 05:35:53 +0000 Subject: osmo-iuh[master]: hnbgw: move vty commands out to new hnbgw_vty.c In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/709 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: If85c1b97a240bd1dcf9f367ea6fca857d542ab22 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 18 05:36:14 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 18 Aug 2016 05:36:14 +0000 Subject: osmo-iuh[master]: hnbgw vty: add empty hnbgw and hnbgw/iuh vty nodes In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/710 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I71545823d3bd81cb888c85df8e298a56c98bf131 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 18 05:36:46 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 18 Aug 2016 05:36:46 +0000 Subject: osmo-iuh[master]: hnbgw: make Iuh bind address configurable via VTY In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/711 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ie2749c152b878e17aa65dfb806826357d5c494f1 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 18 05:36:56 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 18 Aug 2016 05:36:56 +0000 Subject: osmo-iuh[master]: doc: add example osmo-hnbgw.cfg In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/712 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I424ccdea02578edc7816e4d23a9ea7c5729315d8 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 18 05:37:37 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 18 Aug 2016 05:37:37 +0000 Subject: osmo-iuh[master]: doc: add example osmo-hnbgw.cfg In-Reply-To: References: Message-ID: Patch Set 1: Code-Review-1 this wouldn't survive a 'make dist' as it's not in Makefile.am -- To view, visit https://gerrit.osmocom.org/712 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I424ccdea02578edc7816e4d23a9ea7c5729315d8 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 18 06:01:51 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 18 Aug 2016 06:01:51 +0000 Subject: openbsc[master]: Adding LLC-XID encoder / decoder and unit test In-Reply-To: References: Message-ID: Patch Set 8: Code-Review-1 (6 comments) https://gerrit.osmocom.org/#/c/638/8/openbsc/src/gprs/gprs_llc_xid.c File openbsc/src/gprs/gprs_llc_xid.c: Line 209: struct llist_head *gprs_llc_free_xid(struct llist_head *xid_fields) why does this function have a return value if it always returns NULL? It's customary for free() functions to be void. You can of course deviate from that, but it needs to have a good reason (+ probably explanation). Line 211: if (xid_fields != NULL) talloc_free(NULL), like free(NULL) are perfectly valid and well-defined operations, no need for any check Line 226: duplicate_of_xid_field = talloc_zero(ctx, struct gprs_llc_xid_field); no need for talloc_zero() with its zero-initialization, if you for sure overwrite all of the allocated memory in the next line using memcpy Line 228: sizeof(struct gprs_llc_xid_field)); please use sizeof(*duplicate_of_xid_field), as explained in other feedback comment before Line 230: talloc_zero_size(duplicate_of_xid_field, xid_field->data_len); same as above regarding 'zero'. also see talloc_memdup. Line 272: LOGP(DSNDCP, logl, this is a function that is called 'gprs_llc_...' but it uses DSNDCP for logging. Either use DLLC, or if it is sometimes either of both, pass the 'int log_subsys' into the function by the caller. -- To view, visit https://gerrit.osmocom.org/638 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia06e4cb08bf9b48c2a4682606d1b1a91d19a9d37 Gerrit-PatchSet: 8 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 18 06:02:11 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 18 Aug 2016 06:02:11 +0000 Subject: openbsc[master]: Moving grs_sndcp.h header file to include In-Reply-To: References: Message-ID: Patch Set 6: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/636 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: If4e4f1252c81d7907c1b4d738c982bb172b128c9 Gerrit-PatchSet: 6 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 18 06:07:38 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 18 Aug 2016 06:07:38 +0000 Subject: openbsc[master]: Adding LLC-XID related modifications in LLC In-Reply-To: References: Message-ID: Patch Set 12: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/652 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I65b9d625e72d3d61c99abdc7041773701d694d52 Gerrit-PatchSet: 12 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 18 06:12:16 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 18 Aug 2016 06:12:16 +0000 Subject: openbsc[master]: Adding SNDCP-XID encoder / decoder and unit test In-Reply-To: References: Message-ID: Patch Set 11: Code-Review+2 (1 comment) https://gerrit.osmocom.org/#/c/641/11/openbsc/.gitignore File openbsc/.gitignore: Line 84: tests/xid/xid_test die erste zeile gehoert wohl in den anderen patch? -- To view, visit https://gerrit.osmocom.org/641 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e Gerrit-PatchSet: 11 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 18 06:13:01 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 18 Aug 2016 06:13:01 +0000 Subject: openbsc[master]: Adding SLHC (RFC1144 header compression) code from linux kernel In-Reply-To: References: Message-ID: Patch Set 9: Code-Review-1 (1 comment) https://gerrit.osmocom.org/#/c/634/9//COMMIT_MSG Commit Message: Line 14: from two different git trees? I guess this is a mistake? -- To view, visit https://gerrit.osmocom.org/634 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ied69c143678dc4a64cecc671f5c4dfebe19d8519 Gerrit-PatchSet: 9 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 18 06:14:04 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 18 Aug 2016 06:14:04 +0000 Subject: openbsc[master]: SLHC (RFC1144 header compression) integration and unit-test In-Reply-To: References: Message-ID: Patch Set 10: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/635 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 Gerrit-PatchSet: 10 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 18 06:37:28 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 18 Aug 2016 06:37:28 +0000 Subject: openbsc[master]: Adding compression control In-Reply-To: References: Message-ID: Patch Set 16: Code-Review-1 (9 comments) https://gerrit.osmocom.org/#/c/642/16/openbsc/include/openbsc/gprs_sndcp_comp.h File openbsc/include/openbsc/gprs_sndcp_comp.h: Line 39: int nsapi[11]; /* Applicable NSAPIs (default 0) */ it might be better to introduce #defines with meaningful names rather than magic numbers here, but it is not super-critical, I think. Also, why use a signed integer, if the actual value is uint8_t (or maybe uint16_t? I don't remember) but certainly not a signed integer? Line 43: int comp[16]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */ why use a signed integer, if the value is (I believe) uint8_t? Line 67: *comp_entities, int entity); comment regarding 'int' type applies to all function prototypes, too. https://gerrit.osmocom.org/#/c/642/16/openbsc/src/gprs/gprs_sndcp_comp.c File openbsc/src/gprs/gprs_sndcp_comp.c: Line 53: comp_field->comp_len * sizeof(int)); sizeof(comp_entity->comp)? Line 59: comp_entity->nsapi_len * sizeof(int)); same as above. never use the base type in length calculation, always use the name of the struct member. This way a change in struct/type definition doesn't break all over the code in subtle ways. Line 153: llist_for_each_safe(ce, ce2, comp_entities) { hierarchical talloc shouldn't need that, unless there is a way how the entries in the list could not be siblings of the entity (in which case this should probably be documented here). Line 213: if (comp_entity) { we always return early in case of error, rather than having if statements for the successful case. ---------- if (!comp_entity) return NULL success case here... ---------- https://gerrit.osmocom.org/#/c/642/16/openbsc/src/gprs/sgsn_vty.c File openbsc/src/gprs/sgsn_vty.c: Line 1086: NO_STR "compression\n" the no-string has "compression" as help for the "compression" node, while the command below has "Configure compression". Best to introduce a COMPRESSION_STR and use it from both places in order to achieve consistency. Line 1098: "number\n") this should probably be named "Number of compression state slots", too. The fact that 1-256 is a number is probably clear already :) -- To view, visit https://gerrit.osmocom.org/642 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 Gerrit-PatchSet: 16 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 18 06:39:44 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 18 Aug 2016 06:39:44 +0000 Subject: openbsc[master]: V42BIS integration and unit test In-Reply-To: References: Message-ID: Patch Set 21: Code-Review+2 (2 comments) https://gerrit.osmocom.org/#/c/644/21/openbsc/src/gprs/sgsn_main.c File openbsc/src/gprs/sgsn_main.c: Line 302: .description = "V42.bis data compression (SNDCP)", Isn't it V.42bis? https://gerrit.osmocom.org/#/c/644/21/openbsc/tests/v42bis/v42bis_test.c File openbsc/tests/v42bis/v42bis_test.c: Line 39: struct v42bis_output_buffer_t { in a test case I don't mind, but generally we don't call structures _t. -- To view, visit https://gerrit.osmocom.org/644 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d Gerrit-PatchSet: 21 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 18 06:58:41 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Thu, 18 Aug 2016 06:58:41 +0000 Subject: [PATCH] openbsc[master]: lchan: Release channel in case of late activation ack Message-ID: Review at https://gerrit.osmocom.org/713 lchan: Release channel in case of late activation ack In case of the sysmoBTS and receiving a channel activation ack on a channel that was marked as broken, release it again. Use a normal release without SACCH deactivation and release the rqd_ta data. Change-Id: I63dc0deaf15ba7c21e20b1e0c7b85f0437e183ed --- M openbsc/src/libbsc/abis_rsl.c 1 file changed, 11 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/13/713/1 diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index 9f76280..091d179 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -983,8 +983,17 @@ osmo_timer_del(&msg->lchan->act_timer); if (msg->lchan->state == LCHAN_S_BROKEN) { - LOGP(DRSL, LOGL_NOTICE, "%s CHAN ACT ACK for broken channel.\n", - gsm_lchan_name(msg->lchan)); + int do_free = is_sysmobts_v2(msg->lchan->ts->trx->bts); + LOGP(DRSL, LOGL_NOTICE, "%s CHAN ACT ACK for broken channel. %s\n", + gsm_lchan_name(msg->lchan), + do_free ? "Release it" : "Keeping it broken"); + if (do_free) { + talloc_free(msg->lchan->rqd_ref); + msg->lchan->rqd_ref = NULL; + msg->lchan->rqd_ta = 0; + rsl_lchan_set_state(msg->lchan, LCHAN_S_ACTIVE); + rsl_rf_chan_release(msg->lchan, 0, SACCH_NONE); + } return 0; } -- To view, visit https://gerrit.osmocom.org/713 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I63dc0deaf15ba7c21e20b1e0c7b85f0437e183ed Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Holger Freyther From gerrit-no-reply at lists.osmocom.org Thu Aug 18 07:02:45 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Thu, 18 Aug 2016 07:02:45 +0000 Subject: [PATCH] openbsc[master]: lchan: Release channel in case of late activation ack In-Reply-To: References: Message-ID: lchan: Release channel in case of late activation ack In case of the sysmoBTS and receiving a channel activation ack on a channel that was marked as broken, release it again. Use a normal release without SACCH deactivation and release the rqd_ta data. Change-Id: I63dc0deaf15ba7c21e20b1e0c7b85f0437e183ed --- M openbsc/src/libbsc/abis_rsl.c 1 file changed, 13 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/13/713/2 diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index b84a0b5..2c3ff93 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -1121,8 +1121,19 @@ osmo_timer_del(&lchan->act_timer); if (lchan->state == LCHAN_S_BROKEN) { - LOGP(DRSL, LOGL_NOTICE, "%s CHAN ACT ACK for broken channel.\n", - gsm_lchan_name(lchan)); + int do_free = is_sysmobts_v2(lchan->ts->trx->bts); + LOGP(DRSL, LOGL_NOTICE, "%s CHAN ACT ACK for broken channel. %s\n", + gsm_lchan_name(lchan), + do_free ? "Release it" : "Keeping it broken"); + if (do_free) { + talloc_free(lchan->rqd_ref); + lchan->rqd_ref = NULL; + lchan->rqd_ta = 0; + rsl_lchan_set_state(msg->lchan, LCHAN_S_ACTIVE); + if (lchan->ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) + dyn_ts_switchover_complete(lchan); + rsl_rf_chan_release(msg->lchan, 0, SACCH_NONE); + } return 0; } -- To view, visit https://gerrit.osmocom.org/713 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I63dc0deaf15ba7c21e20b1e0c7b85f0437e183ed Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Thu Aug 18 08:01:22 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Thu, 18 Aug 2016 08:01:22 +0000 Subject: [PATCH] openbsc[master]: Adding compression control In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/642 to look at the new patch set (#17). Adding compression control In this commit two modules were added: gprs_sndcp_comp.h/c: This part handles the creation and destruction of conpression entites. It handles the allocation and freeing of the memory and offers functions to query compression parameters (i.e. which compression entity should be used if a packet from NSAPI x has to be compressed?) gprs_sndcp_pcomp.c/h: This is the code that performs the actual header compression. It takes care that the packets are compressed/decompressed with the right modes etc. It works, but is not yet ready for merging. Both files depend on each other so that they only can be merged both at the same time. Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 --- M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_sndcp_comp.h A openbsc/include/openbsc/gprs_sndcp_pcomp.h M openbsc/include/openbsc/sgsn.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_sndcp_comp.c A openbsc/src/gprs/gprs_sndcp_pcomp.c M openbsc/src/gprs/sgsn_vty.c M openbsc/tests/sgsn/Makefile.am 9 files changed, 844 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/42/642/17 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index f402fea..88a7e2c 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,7 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ - slhc.h + slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_sndcp_comp.h b/openbsc/include/openbsc/gprs_sndcp_comp.h new file mode 100644 index 0000000..4982a7e --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_comp.h @@ -0,0 +1,85 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_SNDCP_COMP_H +#define _GPRS_SNDCP_COMP_H + +#include +#include +#include + +/* Header / Data compression entity */ +struct gprs_sndcp_comp { + struct llist_head list; + + /* Serves as an ID in case we want to delete this entity later */ + int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + + /* Specifies to which NSAPIs the compression entity is assigned */ + unsigned nsapi_len; /* Number of applicable NSAPIs (default 0) */ + int nsapi[11]; /* Applicable NSAPIs (default 0) */ + + /* Assigned pcomp values */ + unsigned comp_len; /* Number of contained PCOMP / DCOMP values */ + int comp[16]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */ + + /* Algorithm parameters */ + int algo; /* Algorithm type (see gprs_sndcp_xid.h) */ + int compclass; /* See gprs_sndcp_xid.h/c */ + void *state; /* Algorithm status and parameters */ +}; + +/* Free a list with compression entities */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities); + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, int entity); + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_entities_add(const void *ctx, struct + llist_head + *comp_entities, const struct + gprs_sndcp_comp_field + *comp_field); + +/* Find compression entity by its entity number */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_entity(const struct llist_head + *comp_entities, int entity); + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head + *comp_entities, int comp); + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head + *comp_entities, int nsapi); + +/* Find a comp_index for a given pcomp/dcomp value */ +int gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp + *comp_entity, int comp); + +/* Find a pcomp/dcomp value for a given comp_index */ +int gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp + *comp_entity, int comp_index); + +#endif diff --git a/openbsc/include/openbsc/gprs_sndcp_pcomp.h b/openbsc/include/openbsc/gprs_sndcp_pcomp.h new file mode 100644 index 0000000..2444260 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_pcomp.h @@ -0,0 +1,47 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#ifndef _GPRS_SNDCP_pcomp_H +#define _GPRS_SNDCP_pcomp_H + +#include +#include +#include + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field); + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity); + +/* Expand packet header */ +int gprs_sndcp_pcomp_expand(uint8_t *data_o, uint8_t *data_i, int len, + int pcomp, const struct llist_head *comp_entities); + +/* Compress packet header */ +int gprs_sndcp_pcomp_compress(uint8_t *data_o, uint8_t *data_i, int len, + int *pcomp, + const struct llist_head *comp_entities, + int nsapi); + +#endif diff --git a/openbsc/include/openbsc/sgsn.h b/openbsc/include/openbsc/sgsn.h index 59126fe..2366d7a 100644 --- a/openbsc/include/openbsc/sgsn.h +++ b/openbsc/include/openbsc/sgsn.h @@ -88,6 +88,12 @@ int dynamic_lookup; + /* RFC1144 TCP/IP Header compression */ + struct { + int enabled; + int s01; + } pcomp_rfc1144; + struct oap_config oap; }; diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 245636b..2910c02 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -27,7 +27,7 @@ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ - slhc.c + slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/gprs_sndcp_comp.c b/openbsc/src/gprs/gprs_sndcp_comp.c new file mode 100644 index 0000000..da8ab40 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_comp.c @@ -0,0 +1,337 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +/* Create a new compression entity from a XID-Field */ +static struct gprs_sndcp_comp *gprs_sndcp_comp_create(const void + *ctx, const struct + gprs_sndcp_comp_field + *comp_field) +{ + OSMO_ASSERT(comp_field); + + struct gprs_sndcp_comp *comp_entity; + comp_entity = talloc_zero(ctx, struct gprs_sndcp_comp); + + /* Copy relevant information from the SNDCP-XID field */ + comp_entity->entity = comp_field->entity; + comp_entity->comp_len = comp_field->comp_len; + memcpy(comp_entity->comp, comp_field->comp, + comp_field->comp_len * sizeof(int)); + + if (comp_field->rfc1144_params) { + comp_entity->nsapi_len = comp_field->rfc1144_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc1144_params->nsapi, + comp_entity->nsapi_len * sizeof(int)); + } else if (comp_field->rfc2507_params) { + comp_entity->nsapi_len = comp_field->rfc2507_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc2507_params->nsapi, + comp_entity->nsapi_len * sizeof(int)); + } else if (comp_field->rohc_params) { + comp_entity->nsapi_len = comp_field->rohc_params->nsapi_len; + memcpy(comp_entity->nsapi, comp_field->rohc_params->nsapi, + comp_entity->nsapi_len * sizeof(int)); + } else if (comp_field->v42bis_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + comp_entity->nsapi_len * sizeof(int)); + } else if (comp_field->v44_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + comp_entity->nsapi_len * sizeof(int)); + } else { + /* The caller is expected to check carefully if the all + * data fields required for compression entity creation + * are present. Otherwise we blow an assertion here */ + OSMO_ASSERT(NULL); + } + comp_entity->algo = comp_field->algo; + + /* Check if an NSAPI is selected, if not, it does not make sense + * to create the compression entity, since the caller should + * have checked the presence of the NSAPI, we blow an assertion + * in case of missing NSAPIs */ + OSMO_ASSERT(comp_entity->nsapi_len > 0) + + /* Determine of which class our compression entity will be + * (Protocol or Data compresson ?) */ + comp_entity->compclass = gprs_sndcp_get_compression_class(comp_field); + OSMO_ASSERT(comp_entity->compclass != -1); + + /* Create an algorithm specific compression context */ + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + if (gprs_sndcp_pcomp_init(ctx, comp_entity, comp_field) != 0) { + talloc_free(comp_entity); + comp_entity = NULL; + } + } else { + LOGP(DSNDCP, LOGL_ERROR, + "We don't support data compression yet!\n"); + talloc_free(comp_entity); + return NULL; + } + + /* Display info message */ + if (comp_entity == NULL) { + LOGP(DSNDCP, LOGL_ERROR, + "Header compression entity (%i) creation failed!\n", + comp_entity->entity); + return NULL; + } + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "New header compression entity (%i) created.\n", + comp_entity->entity); + } else { + LOGP(DSNDCP, LOGL_INFO, + "New data compression entity (%i) created.\n", + comp_entity->entity); + } + + return comp_entity; +} + +/* Free a list with compression entities */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities) +{ + struct llist_head *ce, *ce2; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + /* Free compression entity */ + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %i ...\n", + comp_entity->entity); + gprs_sndcp_pcomp_term(comp_entity); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %i ...\n", + comp_entity->entity); + } + } + + llist_for_each_safe(ce, ce2, comp_entities) { + llist_del(ce); + talloc_free(ce); + } + +} + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, int entity) +{ + struct gprs_sndcp_comp *comp_entity; + struct gprs_sndcp_comp *comp_entity_to_delete = NULL; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) + comp_entity_to_delete = comp_entity; + } + + if (comp_entity_to_delete) { + if (comp_entity_to_delete->compclass == + SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %i ...\n", + comp_entity_to_delete->entity); + gprs_sndcp_pcomp_term(comp_entity_to_delete); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %i ...\n", + comp_entity_to_delete->entity); + } + + /* Delete compression entity */ + llist_del(&comp_entity_to_delete->list); + talloc_free(comp_entity_to_delete); + } + +} + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_entities_add(const void *ctx, struct + llist_head + *comp_entities, const struct + gprs_sndcp_comp_field + *comp_field) +{ + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(comp_entities); + OSMO_ASSERT(comp_field); + + /* Just to be sure, if the entity is already in + * the list it will be deleted now */ + gprs_sndcp_comp_delete(comp_entities, comp_field->entity); + + /* Create and add a new entity to the list */ + comp_entity = gprs_sndcp_comp_create(ctx, comp_field); + + if (comp_entity) { + llist_add(&comp_entity->list, comp_entities); + return comp_entity; + } + + return NULL; +} + +/* Find compression entity by its entity number */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_entity(const struct + llist_head + *comp_entities, int entity) +{ + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) + return comp_entity; + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given entity number %i.\n", + entity); + return NULL; +} + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct + llist_head + *comp_entities, int comp) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return comp_entity; + } + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given pcomp/dcomp value %i.\n", + comp); + return NULL; +} + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct + llist_head + *comp_entities, int nsapi) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->nsapi_len; i++) { + if (comp_entity->nsapi[i] == nsapi) + return comp_entity; + } + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given nsapi value %i\n", + nsapi); + return NULL; + +} + +/* Find a comp_index for a given pcomp/dcomp value */ +int gprs_sndcp_comp_get_idx(const struct + gprs_sndcp_comp + *comp_entity, int comp) +{ + int i; + + OSMO_ASSERT(comp_entity); + + /* A pcomp/dcomp field set to zero always disables + * all sort of compression and is assigned fix. So we + * just return zero in this case */ + if (comp == 0) + return 0; + + /* Look in the pcomp/dcomp list for the index */ + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return i + 1; + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching comp_index for given pcomp/dcomp value %i\n", + comp); + return 0; + +} + +/* Find a pcomp/dcomp value for a given comp_index */ +int gprs_sndcp_comp_get_comp(const struct + gprs_sndcp_comp + *comp_entity, int comp_index) +{ + OSMO_ASSERT(comp_entity); + + /* A comp_index of zero translates to zero right away. */ + if (comp_index == 0) + return 0; + + if (comp_index > comp_entity->comp_len) { + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching pcomp/dcomp value for given comp_index value %i.\n", + comp_index); + return 0; + } + + /* Look in the pcomp/dcomp list for the comp_index */ + return comp_entity->comp[comp_index - 1]; + +} diff --git a/openbsc/src/gprs/gprs_sndcp_pcomp.c b/openbsc/src/gprs/gprs_sndcp_pcomp.c new file mode 100644 index 0000000..41f6c6a --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_pcomp.c @@ -0,0 +1,334 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG_RFC1144 1 + +/* Show details of the RFC1144 compressed packet header */ +static void debug_rfc1144_header(uint8_t *header) +{ +#if DEBUG_RFC1144 == 1 + + int t,c,i,p,s,a,w,u = 0; + t = (header[0] >> 7) & 1; + c = (header[0] >> 6) & 1; + i = (header[0] >> 5) & 1; + p = (header[0] >> 4) & 1; + s = (header[0] >> 3) & 1; + a = (header[0] >> 2) & 1; + w = (header[0] >> 1) & 1; + u = header[0] & 1; + + DEBUGP(DSNDCP,"rfc1144 header:\n"); + DEBUGP(DSNDCP," Tag bit = %d\n",t); + DEBUGP(DSNDCP," C = %d\n",c); + DEBUGP(DSNDCP," I = %d\n",i); + DEBUGP(DSNDCP," P = %d\n",p); + DEBUGP(DSNDCP," S = %d\n",s); + DEBUGP(DSNDCP," A = %d\n",a); + DEBUGP(DSNDCP," W = %d\n",w); + DEBUGP(DSNDCP," U = %d\n",u); + + header++; + if(c) { + DEBUGP(DSNDCP," Connection number (C) = %d\n",*header); + header++; + } + + DEBUGP(DSNDCP," TCP Checksum = %02x%02x\n",header[0],header[1]); + header+=2; + + if(s && w && u) { + DEBUGP(DSNDCP," Special case I (SPECIAL_I) => short header\n"); + return; + } else if(s && a && w && u) { + DEBUGP(DSNDCP," Special case D (SPECIAL_D) => short header\n"); + return; + } + + if(u) { + DEBUGP(DSNDCP," Urgent Pointer (U) = %02x\n",*header); + header++; + } + if(w) { + DEBUGP(DSNDCP," Delta Window (W) = %02x\n",*header); + header++; + } + if(a) { + DEBUGP(DSNDCP," Delta Ack (A) = %02x\n",*header); + header++; + } + if(s) { + DEBUGP(DSNDCP," Delta Sequence (S) = %02x\n",*header); + header++; + } + if(i) { + DEBUGP(DSNDCP," Delta IP ID (I) = %02x\n",*header); + header++; + } + + /* FIXME: Header values will be usually fit in 8 bits, implement + * implement variable length decoding for values larger then 8 bit */ +#endif +} + + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a new header compression + * entity is created by gprs_sndcp.c */ + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + comp_entity->state = + slhc_init(ctx, comp_field->rfc1144_params->s01 + 1, + comp_field->rfc1144_params->s01 + 1); + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression initalized.\n"); + return 0; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a header compression + * entity is deleted by gprs_sndcp.c */ + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + if (comp_entity->state) { + slhc_free((struct slcompress *)comp_entity->state); + comp_entity->state = NULL; + } + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression terminated.\n"); + return; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Compress a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_compress(int *pcomp_index, uint8_t *data_o, + uint8_t *data_i, int len, + struct slcompress *comp) +{ + uint8_t *comp_ptr; /* Not used */ + int compr_len; + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Run compressor */ + compr_len = slhc_compress(comp, data_i, len, data_o, &comp_ptr, 0); + + /* Generate pcomp_index */ + if (data_o[0] & SL_TYPE_COMPRESSED_TCP) { + *pcomp_index = 2; + data_o[0] &= ~SL_TYPE_COMPRESSED_TCP; + debug_rfc1144_header(data_o); + } else if ((data_o[0] & SL_TYPE_UNCOMPRESSED_TCP) == + SL_TYPE_UNCOMPRESSED_TCP) { + *pcomp_index = 1; + data_o[0] &= 0x4F; + } else + *pcomp_index = 0; + + return compr_len; +} + +/* Expand a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_expand(uint8_t *data_o, uint8_t *data_i, + int len, int pcomp_index, + struct slcompress *comp) +{ + int data_decompressed_len; + int type = -1; + + /* Note: this function should never be called with pcomp_index=0, + * since this condition is already filtered + * out by gprs_sndcp_pcomp_expand() */ + + /* Determine the data type by the PCOMP index */ + switch (pcomp_index) { + case 1: + type = SL_TYPE_UNCOMPRESSED_TCP; + break; + case 2: + type = SL_TYPE_COMPRESSED_TCP; + break; + } + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Restore the original version nibble on + * marked uncompressed packets */ + if (type == SL_TYPE_UNCOMPRESSED_TCP) { + + /* Just in case the phone tags uncompressed tcp-datas + * (normally this is handled by pcomp so there is + * no need for tagging the datas) */ + data_o[0] &= 0x4F; + data_decompressed_len = slhc_remember(comp, data_o, len); + return data_decompressed_len; + } + + /* Uncompress compressed packets */ + else if (type == SL_TYPE_COMPRESSED_TCP) { + data_decompressed_len = slhc_uncompress(comp, data_o, len); + return data_decompressed_len; + } + + /* Regular or unknown packets will not be touched */ + return len; +} + +/* Expand packet header */ +int gprs_sndcp_pcomp_expand(uint8_t *data_o, uint8_t *data_i, int len, + int pcomp, const struct llist_head *comp_entities) +{ + int rc; + int pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data_o); + OSMO_ASSERT(data_i); + OSMO_ASSERT(comp_entities); + + /* Skip on pcomp=0 */ + if (pcomp == 0) { + memcpy(data_o,data_i,len); + return len; + } + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_comp(comp_entities, pcomp); + + /* Skip compression if no suitable compression entity can be found */ + if (comp_entity == NULL) { + memcpy(data_o,data_i,len); + return len; + } + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION); + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144); + + /* Find pcomp_index */ + pcomp_index = gprs_sndcp_comp_get_idx(comp_entity, pcomp); + + /* Run decompression algo */ + rc = gprs_sndcp_pcomp_rfc1144_expand(data_o, data_i, len, pcomp_index, + comp_entity->state); + slhc_i_status(comp_entity->state); + slhc_o_status(comp_entity->state); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header expansion done, old length=%i, new length=%i\n", + len, rc); + + return rc; +} + +/* Compress packet header */ +int gprs_sndcp_pcomp_compress(uint8_t *data_o, uint8_t *data_i, int len, + int *pcomp, + const struct llist_head *comp_entities, int nsapi) +{ + int rc; + int pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data_o); + OSMO_ASSERT(data_i); + OSMO_ASSERT(pcomp); + OSMO_ASSERT(comp_entities); + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_nsapi(comp_entities, nsapi); + + /* Skip compression if no suitable compression entity can be found */ + if (!comp_entity) { + *pcomp = 0; + memcpy(data_o,data_i,len); + return len; + } + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION); + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144); + + /* Run compression algo */ + rc = gprs_sndcp_pcomp_rfc1144_compress(&pcomp_index, data_o, data_i, + len, comp_entity->state); + slhc_i_status(comp_entity->state); + slhc_o_status(comp_entity->state); + + /* Find pcomp value */ + *pcomp = gprs_sndcp_comp_get_comp(comp_entity, pcomp_index); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header compression done, old length=%i, new length=%i\n", + len, rc); + return rc; +} diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c index e6dc68d..1b67092 100644 --- a/openbsc/src/gprs/sgsn_vty.c +++ b/openbsc/src/gprs/sgsn_vty.c @@ -269,6 +269,13 @@ vty_out(vty, " timer t3395 %d%s", g_cfg->timers.T3395, VTY_NEWLINE); vty_out(vty, " timer t3397 %d%s", g_cfg->timers.T3397, VTY_NEWLINE); + if (g_cfg->pcomp_rfc1144.enabled) { + vty_out(vty, " compression rfc1144 slots %d%s", + g_cfg->pcomp_rfc1144.s01+1, VTY_NEWLINE); + } else { + vty_out(vty, " no compression rfc1144%s", VTY_NEWLINE); + } + return CMD_SUCCESS; } @@ -1074,6 +1081,27 @@ return CMD_SUCCESS; } +DEFUN(cfg_no_comp_rfc1144, cfg_no_comp_rfc1144_cmd, + "no compression rfc1144", + NO_STR "compression\n" + "disable rfc1144 TCP/IP header compression\n") +{ + g_cfg->pcomp_rfc1144.enabled = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_comp_rfc1144, cfg_comp_rfc1144_cmd, + "compression rfc1144 slots <1-256>", + "Configure compression\n" + "RFC1144 Header compresion scheme\n" + "Number of compression state slots\n" + "number\n") +{ + g_cfg->pcomp_rfc1144.enabled = 1; + g_cfg->pcomp_rfc1144.s01 = atoi(argv[0]) - 1; + return CMD_SUCCESS; +} + int sgsn_vty_init(void) { install_element_ve(&show_sgsn_cmd); @@ -1128,6 +1156,9 @@ install_element(SGSN_NODE, &cfg_sgsn_T3395_cmd); install_element(SGSN_NODE, &cfg_sgsn_T3397_cmd); + install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd); + install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd); + return 0; } diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 3e66978..1804280 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -33,6 +33,8 @@ $(top_builddir)/src/gprs/gprs_llc_xid.o \ $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ $(top_builddir)/src/gprs/slhc.o \ + $(top_builddir)/src/gprs/gprs_sndcp_comp.o \ + $(top_builddir)/src/gprs/gprs_sndcp_pcomp.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ -- To view, visit https://gerrit.osmocom.org/642 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 Gerrit-PatchSet: 17 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Thu Aug 18 08:01:22 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Thu, 18 Aug 2016 08:01:22 +0000 Subject: [PATCH] openbsc[master]: Adding SLHC (RFC1144 header compression) code from linux kernel In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/634 to look at the new patch set (#10). Adding SLHC (RFC1144 header compression) code from linux kernel Slhc is an Implementation of RFC1144 TCP/IP header compression. We will need RFC1144 compression to compress GPRS TCP/IP traffic. The implementation pushed with this commit was taken from git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git commit 29b4817d4018df78086157ea3a55c1d9424a7cfc Change-Id: Ied69c143678dc4a64cecc671f5c4dfebe19d8519 --- A openbsc/include/openbsc/slhc_vj.h M openbsc/src/gprs/sgsn_main.c A openbsc/src/gprs/slhc.c 3 files changed, 932 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/34/634/10 diff --git a/openbsc/include/openbsc/slhc_vj.h b/openbsc/include/openbsc/slhc_vj.h new file mode 100644 index 0000000..8716d59 --- /dev/null +++ b/openbsc/include/openbsc/slhc_vj.h @@ -0,0 +1,183 @@ +#ifndef _SLHC_H +#define _SLHC_H +/* + * Definitions for tcp compression routines. + * + * $Header: slcompress.h,v 1.10 89/12/31 08:53:02 van Exp $ + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van at helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + * + * + * modified for KA9Q Internet Software Package by + * Katie Stevens (dkstevens at ucdavis.edu) + * University of California, Davis + * Computing Services + * - 01-31-90 initial adaptation + * + * - Feb 1991 Bill_Simpson at um.cc.umich.edu + * variable number of conversation slots + * allow zero or one slots + * separate routines + * status display + */ + +/* + * Compressed packet format: + * + * The first octet contains the packet type (top 3 bits), TCP + * 'push' bit, and flags that indicate which of the 4 TCP sequence + * numbers have changed (bottom 5 bits). The next octet is a + * conversation number that associates a saved IP/TCP header with + * the compressed packet. The next two octets are the TCP checksum + * from the original datagram. The next 0 to 15 octets are + * sequence number changes, one change per bit set in the header + * (there may be no changes and there are two special cases where + * the receiver implicitly knows what changed -- see below). + * + * There are 5 numbers which can change (they are always inserted + * in the following order): TCP urgent pointer, window, + * acknowledgment, sequence number and IP ID. (The urgent pointer + * is different from the others in that its value is sent, not the + * change in value.) Since typical use of SLIP links is biased + * toward small packets (see comments on MTU/MSS below), changes + * use a variable length coding with one octet for numbers in the + * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the + * range 256 - 65535 or 0. (If the change in sequence number or + * ack is more than 65535, an uncompressed packet is sent.) + */ + +/* + * Packet types (must not conflict with IP protocol version) + * + * The top nibble of the first octet is the packet type. There are + * three possible types: IP (not proto TCP or tcp with one of the + * control flags set); uncompressed TCP (a normal IP/TCP packet but + * with the 8-bit protocol field replaced by an 8-bit connection id -- + * this type of packet syncs the sender & receiver); and compressed + * TCP (described above). + * + * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and + * is logically part of the 4-bit "changes" field that follows. Top + * three bits are actual packet type. For backward compatibility + * and in the interest of conserving bits, numbers are chosen so the + * IP protocol version number (4) which normally appears in this nibble + * means "IP packet". + */ + + +#include +#include + +/* SLIP compression masks for len/vers byte */ +#define SL_TYPE_IP 0x40 +#define SL_TYPE_UNCOMPRESSED_TCP 0x70 +#define SL_TYPE_COMPRESSED_TCP 0x80 +#define SL_TYPE_ERROR 0x00 + +/* Bits in first octet of compressed packet */ +#define NEW_C 0x40 /* flag bits for what changed in a packet */ +#define NEW_I 0x20 +#define NEW_S 0x08 +#define NEW_A 0x04 +#define NEW_W 0x02 +#define NEW_U 0x01 + +/* reserved, special-case values of above */ +#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */ +#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */ +#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U) + +#define TCP_PUSH_BIT 0x10 + +/* + * data type and sizes conversion assumptions: + * + * VJ code KA9Q style generic + * u_char byte_t unsigned char 8 bits + * u_short int16 unsigned short 16 bits + * u_int int16 unsigned short 16 bits + * u_long unsigned long unsigned long 32 bits + * int int32 long 32 bits + */ + +typedef __u8 byte_t; +typedef __u32 int32; + +/* + * "state" data for each active tcp conversation on the wire. This is + * basically a copy of the entire IP/TCP header from the last packet + * we saw from the conversation together with a small identifier + * the transmit & receive ends of the line use to locate saved header. + */ +struct cstate { + byte_t cs_this; /* connection id number (xmit) */ + struct cstate *next; /* next in ring (xmit) */ + struct iphdr cs_ip; /* ip/tcp hdr from most recent packet */ + struct tcphdr cs_tcp; + unsigned char cs_ipopt[64]; + unsigned char cs_tcpopt[64]; + int cs_hsize; +}; +#define NULLSLSTATE (struct cstate *)0 + +/* + * all the state data for one serial line (we need one of these per line). + */ +struct slcompress { + struct cstate *tstate; /* transmit connection states (array)*/ + struct cstate *rstate; /* receive connection states (array)*/ + + byte_t tslot_limit; /* highest transmit slot id (0-l)*/ + byte_t rslot_limit; /* highest receive slot id (0-l)*/ + + byte_t xmit_oldest; /* oldest xmit in ring */ + byte_t xmit_current; /* most recent xmit id */ + byte_t recv_current; /* most recent rcvd id */ + + byte_t flags; +#define SLF_TOSS 0x01 /* tossing rcvd frames until id received */ + + int32 sls_o_nontcp; /* outbound non-TCP packets */ + int32 sls_o_tcp; /* outbound TCP packets */ + int32 sls_o_uncompressed; /* outbound uncompressed packets */ + int32 sls_o_compressed; /* outbound compressed packets */ + int32 sls_o_searches; /* searches for connection state */ + int32 sls_o_misses; /* times couldn't find conn. state */ + + int32 sls_i_uncompressed; /* inbound uncompressed packets */ + int32 sls_i_compressed; /* inbound compressed packets */ + int32 sls_i_error; /* inbound error packets */ + int32 sls_i_tossed; /* inbound packets tossed because of error */ + + int32 sls_i_runt; + int32 sls_i_badcheck; +}; +#define NULLSLCOMPR (struct slcompress *)0 + +/* In slhc.c: */ +struct slcompress *slhc_init(int rslots, int tslots); +void slhc_free(struct slcompress *comp); + +int slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, + unsigned char *ocp, unsigned char **cpp, int compress_cid); +int slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize); +int slhc_remember(struct slcompress *comp, unsigned char *icp, int isize); +int slhc_toss(struct slcompress *comp); + +#endif /* _SLHC_H */ diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c index 52fc985..894ce84 100644 --- a/openbsc/src/gprs/sgsn_main.c +++ b/openbsc/src/gprs/sgsn_main.c @@ -292,6 +292,11 @@ .description = "SCCP User Adaptation (SUA)", .enabled = 1, .loglevel = LOGL_DEBUG, }, + [DSLHC] = { + .name = "DSLHC", + .description = "RFC1144 TCP/IP Header compression (SLHC)", + .enabled = 1, .loglevel = LOGL_DEBUG, + }, }; static const struct log_info gprs_log_info = { diff --git a/openbsc/src/gprs/slhc.c b/openbsc/src/gprs/slhc.c new file mode 100644 index 0000000..27ed252 --- /dev/null +++ b/openbsc/src/gprs/slhc.c @@ -0,0 +1,744 @@ +/* + * Routines to compress and uncompress tcp packets (for transmission + * over low speed serial lines). + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van at helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + * + * + * modified for KA9Q Internet Software Package by + * Katie Stevens (dkstevens at ucdavis.edu) + * University of California, Davis + * Computing Services + * - 01-31-90 initial adaptation (from 1.19) + * PPP.05 02-15-90 [ks] + * PPP.08 05-02-90 [ks] use PPP protocol field to signal compression + * PPP.15 09-90 [ks] improve mbuf handling + * PPP.16 11-02 [karn] substantially rewritten to use NOS facilities + * + * - Feb 1991 Bill_Simpson at um.cc.umich.edu + * variable number of conversation slots + * allow zero or one slots + * separate routines + * status display + * - Jul 1994 Dmitry Gorodchanin + * Fixes for memory leaks. + * - Oct 1994 Dmitry Gorodchanin + * Modularization. + * - Jan 1995 Bjorn Ekwall + * Use ip_fast_csum from ip.h + * - July 1995 Christos A. Polyzols + * Spotted bug in tcp option checking + * + * + * This module is a difficult issue. It's clearly inet code but it's also clearly + * driver code belonging close to PPP and SLIP + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_INET +/* Entire module is for IP only */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned char *encode(unsigned char *cp, unsigned short n); +static long decode(unsigned char **cpp); +static unsigned char * put16(unsigned char *cp, unsigned short x); +static unsigned short pull16(unsigned char **cpp); + +/* Allocate compression data structure + * slots must be in range 0 to 255 (zero meaning no compression) + * Returns pointer to structure or ERR_PTR() on error. + */ +struct slcompress * +slhc_init(int rslots, int tslots) +{ + register short i; + register struct cstate *ts; + struct slcompress *comp; + + if (rslots < 0 || rslots > 255 || tslots < 0 || tslots > 255) + return ERR_PTR(-EINVAL); + + comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL); + if (! comp) + goto out_fail; + + if (rslots > 0) { + size_t rsize = rslots * sizeof(struct cstate); + comp->rstate = kzalloc(rsize, GFP_KERNEL); + if (! comp->rstate) + goto out_free; + comp->rslot_limit = rslots - 1; + } + + if (tslots > 0) { + size_t tsize = tslots * sizeof(struct cstate); + comp->tstate = kzalloc(tsize, GFP_KERNEL); + if (! comp->tstate) + goto out_free2; + comp->tslot_limit = tslots - 1; + } + + comp->xmit_oldest = 0; + comp->xmit_current = 255; + comp->recv_current = 255; + /* + * don't accept any packets with implicit index until we get + * one with an explicit index. Otherwise the uncompress code + * will try to use connection 255, which is almost certainly + * out of range + */ + comp->flags |= SLF_TOSS; + + if ( tslots > 0 ) { + ts = comp->tstate; + for(i = comp->tslot_limit; i > 0; --i){ + ts[i].cs_this = i; + ts[i].next = &(ts[i - 1]); + } + ts[0].next = &(ts[comp->tslot_limit]); + ts[0].cs_this = 0; + } + return comp; + +out_free2: + kfree(comp->rstate); +out_free: + kfree(comp); +out_fail: + return ERR_PTR(-ENOMEM); +} + + +/* Free a compression data structure */ +void +slhc_free(struct slcompress *comp) +{ + if ( comp == NULLSLCOMPR ) + return; + + if ( comp->tstate != NULLSLSTATE ) + kfree( comp->tstate ); + + if ( comp->rstate != NULLSLSTATE ) + kfree( comp->rstate ); + + kfree( comp ); +} + + +/* Put a short in host order into a char array in network order */ +static inline unsigned char * +put16(unsigned char *cp, unsigned short x) +{ + *cp++ = x >> 8; + *cp++ = x; + + return cp; +} + + +/* Encode a number */ +static unsigned char * +encode(unsigned char *cp, unsigned short n) +{ + if(n >= 256 || n == 0){ + *cp++ = 0; + cp = put16(cp,n); + } else { + *cp++ = n; + } + return cp; +} + +/* Pull a 16-bit integer in host order from buffer in network byte order */ +static unsigned short +pull16(unsigned char **cpp) +{ + short rval; + + rval = *(*cpp)++; + rval <<= 8; + rval |= *(*cpp)++; + return rval; +} + +/* Decode a number */ +static long +decode(unsigned char **cpp) +{ + register int x; + + x = *(*cpp)++; + if(x == 0){ + return pull16(cpp) & 0xffff; /* pull16 returns -1 on error */ + } else { + return x & 0xff; /* -1 if PULLCHAR returned error */ + } +} + +/* + * icp and isize are the original packet. + * ocp is a place to put a copy if necessary. + * cpp is initially a pointer to icp. If the copy is used, + * change it to ocp. + */ + +int +slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, + unsigned char *ocp, unsigned char **cpp, int compress_cid) +{ + register struct cstate *ocs = &(comp->tstate[comp->xmit_oldest]); + register struct cstate *lcs = ocs; + register struct cstate *cs = lcs->next; + register unsigned long deltaS, deltaA; + register short changes = 0; + int hlen; + unsigned char new_seq[16]; + register unsigned char *cp = new_seq; + struct iphdr *ip; + struct tcphdr *th, *oth; + __sum16 csum; + + + /* + * Don't play with runt packets. + */ + + if(isizeprotocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x3fff)) { + /* Send as regular IP */ + if(ip->protocol != IPPROTO_TCP) + comp->sls_o_nontcp++; + else + comp->sls_o_tcp++; + return isize; + } + /* Extract TCP header */ + + th = (struct tcphdr *)(((unsigned char *)ip) + ip->ihl*4); + hlen = ip->ihl*4 + th->doff*4; + + /* Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or + * some other control bit is set). Also uncompressible if + * it's a runt. + */ + if(hlen > isize || th->syn || th->fin || th->rst || + ! (th->ack)){ + /* TCP connection stuff; send as regular IP */ + comp->sls_o_tcp++; + return isize; + } + /* + * Packet is compressible -- we're going to send either a + * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way, + * we need to locate (or create) the connection state. + * + * States are kept in a circularly linked list with + * xmit_oldest pointing to the end of the list. The + * list is kept in lru order by moving a state to the + * head of the list whenever it is referenced. Since + * the list is short and, empirically, the connection + * we want is almost always near the front, we locate + * states via linear search. If we don't find a state + * for the datagram, the oldest state is (re-)used. + */ + for ( ; ; ) { + if( ip->saddr == cs->cs_ip.saddr + && ip->daddr == cs->cs_ip.daddr + && th->source == cs->cs_tcp.source + && th->dest == cs->cs_tcp.dest) + goto found; + + /* if current equal oldest, at end of list */ + if ( cs == ocs ) + break; + lcs = cs; + cs = cs->next; + comp->sls_o_searches++; + } + /* + * Didn't find it -- re-use oldest cstate. Send an + * uncompressed packet that tells the other side what + * connection number we're using for this conversation. + * + * Note that since the state list is circular, the oldest + * state points to the newest and we only need to set + * xmit_oldest to update the lru linkage. + */ + comp->sls_o_misses++; + comp->xmit_oldest = lcs->cs_this; + goto uncompressed; + +found: + /* + * Found it -- move to the front on the connection list. + */ + if(lcs == ocs) { + /* found at most recently used */ + } else if (cs == ocs) { + /* found at least recently used */ + comp->xmit_oldest = lcs->cs_this; + } else { + /* more than 2 elements */ + lcs->next = cs->next; + cs->next = ocs->next; + ocs->next = cs; + } + + /* + * Make sure that only what we expect to change changed. + * Check the following: + * IP protocol version, header length & type of service. + * The "Don't fragment" bit. + * The time-to-live field. + * The TCP header length. + * IP options, if any. + * TCP options, if any. + * If any of these things are different between the previous & + * current datagram, we send the current datagram `uncompressed'. + */ + oth = &cs->cs_tcp; + + if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl + || ip->tos != cs->cs_ip.tos + || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000)) + || ip->ttl != cs->cs_ip.ttl + || th->doff != cs->cs_tcp.doff + || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) + || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){ + goto uncompressed; + } + + /* + * Figure out which of the changing fields changed. The + * receiver expects changes in the order: urgent, window, + * ack, seq (the order minimizes the number of temporaries + * needed in this section of code). + */ + if(th->urg){ + deltaS = ntohs(th->urg_ptr); + cp = encode(cp,deltaS); + changes |= NEW_U; + } else if(th->urg_ptr != oth->urg_ptr){ + /* argh! URG not set but urp changed -- a sensible + * implementation should never do this but RFC793 + * doesn't prohibit the change so we have to deal + * with it. */ + goto uncompressed; + } + if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){ + cp = encode(cp,deltaS); + changes |= NEW_W; + } + if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){ + if(deltaA > 0x0000ffff) + goto uncompressed; + cp = encode(cp,deltaA); + changes |= NEW_A; + } + if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){ + if(deltaS > 0x0000ffff) + goto uncompressed; + cp = encode(cp,deltaS); + changes |= NEW_S; + } + + switch(changes){ + case 0: /* Nothing changed. If this packet contains data and the + * last one didn't, this is probably a data packet following + * an ack (normal on an interactive connection) and we send + * it compressed. Otherwise it's probably a retransmit, + * retransmitted ack or window probe. Send it uncompressed + * in case the other side missed the compressed version. + */ + if(ip->tot_len != cs->cs_ip.tot_len && + ntohs(cs->cs_ip.tot_len) == hlen) + break; + goto uncompressed; + case SPECIAL_I: + case SPECIAL_D: + /* actual changes match one of our special case encodings -- + * send packet uncompressed. + */ + goto uncompressed; + case NEW_S|NEW_A: + if(deltaS == deltaA && + deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ + /* special case for echoed terminal traffic */ + changes = SPECIAL_I; + cp = new_seq; + } + break; + case NEW_S: + if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ + /* special case for data xfer */ + changes = SPECIAL_D; + cp = new_seq; + } + break; + } + deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id); + if(deltaS != 1){ + cp = encode(cp,deltaS); + changes |= NEW_I; + } + if(th->psh) + changes |= TCP_PUSH_BIT; + /* Grab the cksum before we overwrite it below. Then update our + * state with this packet's header. + */ + csum = th->check; + memcpy(&cs->cs_ip,ip,20); + memcpy(&cs->cs_tcp,th,20); + /* We want to use the original packet as our compressed packet. + * (cp - new_seq) is the number of bytes we need for compressed + * sequence numbers. In addition we need one byte for the change + * mask, one for the connection id and two for the tcp checksum. + * So, (cp - new_seq) + 4 bytes of header are needed. + */ + deltaS = cp - new_seq; + if(compress_cid == 0 || comp->xmit_current != cs->cs_this){ + cp = ocp; + *cpp = ocp; + *cp++ = changes | NEW_C; + *cp++ = cs->cs_this; + comp->xmit_current = cs->cs_this; + } else { + cp = ocp; + *cpp = ocp; + *cp++ = changes; + } + *(__sum16 *)cp = csum; + cp += 2; +/* deltaS is now the size of the change section of the compressed header */ + memcpy(cp,new_seq,deltaS); /* Write list of deltas */ + memcpy(cp+deltaS,icp+hlen,isize-hlen); + comp->sls_o_compressed++; + ocp[0] |= SL_TYPE_COMPRESSED_TCP; + return isize - hlen + deltaS + (cp - ocp); + + /* Update connection state cs & send uncompressed packet (i.e., + * a regular ip/tcp packet but with the 'conversation id' we hope + * to use on future compressed packets in the protocol field). + */ +uncompressed: + memcpy(&cs->cs_ip,ip,20); + memcpy(&cs->cs_tcp,th,20); + if (ip->ihl > 5) + memcpy(cs->cs_ipopt, ip+1, ((ip->ihl) - 5) * 4); + if (th->doff > 5) + memcpy(cs->cs_tcpopt, th+1, ((th->doff) - 5) * 4); + comp->xmit_current = cs->cs_this; + comp->sls_o_uncompressed++; + memcpy(ocp, icp, isize); + *cpp = ocp; + ocp[9] = cs->cs_this; + ocp[0] |= SL_TYPE_UNCOMPRESSED_TCP; + return isize; +} + + +int +slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) +{ + register int changes; + long x; + register struct tcphdr *thp; + register struct iphdr *ip; + register struct cstate *cs; + int len, hdrlen; + unsigned char *cp = icp; + + /* We've got a compressed packet; read the change byte */ + comp->sls_i_compressed++; + if(isize < 3){ + comp->sls_i_error++; + return 0; + } + changes = *cp++; + if(changes & NEW_C){ + /* Make sure the state index is in range, then grab the state. + * If we have a good state index, clear the 'discard' flag. + */ + x = *cp++; /* Read conn index */ + if(x < 0 || x > comp->rslot_limit) + goto bad; + + comp->flags &=~ SLF_TOSS; + comp->recv_current = x; + } else { + /* this packet has an implicit state index. If we've + * had a line error since the last time we got an + * explicit state index, we have to toss the packet. */ + if(comp->flags & SLF_TOSS){ + comp->sls_i_tossed++; + return 0; + } + } + cs = &comp->rstate[comp->recv_current]; + thp = &cs->cs_tcp; + ip = &cs->cs_ip; + + thp->check = *(__sum16 *)cp; + cp += 2; + + thp->psh = (changes & TCP_PUSH_BIT) ? 1 : 0; +/* + * we can use the same number for the length of the saved header and + * the current one, because the packet wouldn't have been sent + * as compressed unless the options were the same as the previous one + */ + + hdrlen = ip->ihl * 4 + thp->doff * 4; + + switch(changes & SPECIALS_MASK){ + case SPECIAL_I: /* Echoed terminal traffic */ + { + register short i; + i = ntohs(ip->tot_len) - hdrlen; + thp->ack_seq = htonl( ntohl(thp->ack_seq) + i); + thp->seq = htonl( ntohl(thp->seq) + i); + } + break; + + case SPECIAL_D: /* Unidirectional data */ + thp->seq = htonl( ntohl(thp->seq) + + ntohs(ip->tot_len) - hdrlen); + break; + + default: + if(changes & NEW_U){ + thp->urg = 1; + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->urg_ptr = htons(x); + } else + thp->urg = 0; + if(changes & NEW_W){ + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->window = htons( ntohs(thp->window) + x); + } + if(changes & NEW_A){ + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->ack_seq = htonl( ntohl(thp->ack_seq) + x); + } + if(changes & NEW_S){ + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->seq = htonl( ntohl(thp->seq) + x); + } + break; + } + if(changes & NEW_I){ + if((x = decode(&cp)) == -1) { + goto bad; + } + ip->id = htons (ntohs (ip->id) + x); + } else + ip->id = htons (ntohs (ip->id) + 1); + + /* + * At this point, cp points to the first byte of data in the + * packet. Put the reconstructed TCP and IP headers back on the + * packet. Recalculate IP checksum (but not TCP checksum). + */ + + len = isize - (cp - icp); + if (len < 0) + goto bad; + len += hdrlen; + ip->tot_len = htons(len); + ip->check = 0; + + memmove(icp + hdrlen, cp, len - hdrlen); + + cp = icp; + memcpy(cp, ip, 20); + cp += 20; + + if (ip->ihl > 5) { + memcpy(cp, cs->cs_ipopt, (ip->ihl - 5) * 4); + cp += (ip->ihl - 5) * 4; + } + + put_unaligned(ip_fast_csum(icp, ip->ihl), + &((struct iphdr *)icp)->check); + + memcpy(cp, thp, 20); + cp += 20; + + if (thp->doff > 5) { + memcpy(cp, cs->cs_tcpopt, ((thp->doff) - 5) * 4); + cp += ((thp->doff) - 5) * 4; + } + + return len; +bad: + comp->sls_i_error++; + return slhc_toss( comp ); +} + + +int +slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +{ + register struct cstate *cs; + unsigned ihl; + + unsigned char index; + + if(isize < 20) { + /* The packet is shorter than a legal IP header */ + comp->sls_i_runt++; + return slhc_toss( comp ); + } + /* Peek at the IP header's IHL field to find its length */ + ihl = icp[0] & 0xf; + if(ihl < 20 / 4){ + /* The IP header length field is too small */ + comp->sls_i_runt++; + return slhc_toss( comp ); + } + index = icp[9]; + icp[9] = IPPROTO_TCP; + + if (ip_fast_csum(icp, ihl)) { + /* Bad IP header checksum; discard */ + comp->sls_i_badcheck++; + return slhc_toss( comp ); + } + if(index > comp->rslot_limit) { + comp->sls_i_error++; + return slhc_toss(comp); + } + + /* Update local state */ + cs = &comp->rstate[comp->recv_current = index]; + comp->flags &=~ SLF_TOSS; + memcpy(&cs->cs_ip,icp,20); + memcpy(&cs->cs_tcp,icp + ihl*4,20); + if (ihl > 5) + memcpy(cs->cs_ipopt, icp + sizeof(struct iphdr), (ihl - 5) * 4); + if (cs->cs_tcp.doff > 5) + memcpy(cs->cs_tcpopt, icp + ihl*4 + sizeof(struct tcphdr), (cs->cs_tcp.doff - 5) * 4); + cs->cs_hsize = ihl*2 + cs->cs_tcp.doff*2; + /* Put headers back on packet + * Neither header checksum is recalculated + */ + comp->sls_i_uncompressed++; + return isize; +} + +int +slhc_toss(struct slcompress *comp) +{ + if ( comp == NULLSLCOMPR ) + return 0; + + comp->flags |= SLF_TOSS; + return 0; +} + +#else /* CONFIG_INET */ + +int +slhc_toss(struct slcompress *comp) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss"); + return -EINVAL; +} +int +slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress"); + return -EINVAL; +} +int +slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, + unsigned char *ocp, unsigned char **cpp, int compress_cid) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress"); + return -EINVAL; +} + +int +slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember"); + return -EINVAL; +} + +void +slhc_free(struct slcompress *comp) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free"); +} +struct slcompress * +slhc_init(int rslots, int tslots) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init"); + return NULL; +} + +#endif /* CONFIG_INET */ + +/* VJ header compression */ +EXPORT_SYMBOL(slhc_init); +EXPORT_SYMBOL(slhc_free); +EXPORT_SYMBOL(slhc_remember); +EXPORT_SYMBOL(slhc_compress); +EXPORT_SYMBOL(slhc_uncompress); +EXPORT_SYMBOL(slhc_toss); + +MODULE_LICENSE("Dual BSD/GPL"); -- To view, visit https://gerrit.osmocom.org/634 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ied69c143678dc4a64cecc671f5c4dfebe19d8519 Gerrit-PatchSet: 10 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Thu Aug 18 08:01:22 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Thu, 18 Aug 2016 08:01:22 +0000 Subject: [PATCH] openbsc[master]: SLHC (RFC1144 header compression) integration and unit-test In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/635 to look at the new patch set (#11). SLHC (RFC1144 header compression) integration and unit-test The previously pushed slhc implementation has been modified to compile and function outside of the kernel. Also debug log messages were added and datatypes ware matched. The implementation is now ready to be used Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 --- M openbsc/.gitignore M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/debug.h R openbsc/include/openbsc/slhc.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/slhc.c M openbsc/tests/Makefile.am M openbsc/tests/sgsn/Makefile.am A openbsc/tests/slhc/Makefile.am A openbsc/tests/slhc/packets.txt A openbsc/tests/slhc/slhc_test.c A openbsc/tests/slhc/slhc_test.ok M openbsc/tests/testsuite.at 14 files changed, 576 insertions(+), 91 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/35/635/11 diff --git a/openbsc/.gitignore b/openbsc/.gitignore index 8ce3b70..e75b9eb 100644 --- a/openbsc/.gitignore +++ b/openbsc/.gitignore @@ -83,6 +83,7 @@ tests/mm_auth/mm_auth_test tests/xid/xid_test tests/sndcp_xid/sndcp_xid_test +tests/slhc/slhc_test tests/atconfig tests/atlocal diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 53072bd..18980b0 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -231,6 +231,7 @@ tests/mm_auth/Makefile tests/xid/Makefile tests/sndcp_xid/Makefile + tests/slhc/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index e200b05..f402fea 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,8 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h + gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ + slhc.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 43ebb19..90ddca5 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -29,6 +29,7 @@ DBSSGP, DLLC, DSNDCP, + DSLHC, DNAT, DCTRL, DSMPP, diff --git a/openbsc/include/openbsc/slhc_vj.h b/openbsc/include/openbsc/slhc.h similarity index 97% rename from openbsc/include/openbsc/slhc_vj.h rename to openbsc/include/openbsc/slhc.h index 8716d59..cd5a47c 100644 --- a/openbsc/include/openbsc/slhc_vj.h +++ b/openbsc/include/openbsc/slhc.h @@ -171,7 +171,8 @@ #define NULLSLCOMPR (struct slcompress *)0 /* In slhc.c: */ -struct slcompress *slhc_init(int rslots, int tslots); +struct slcompress *slhc_init(const void *ctx, int rslots, int tslots); + void slhc_free(struct slcompress *comp); int slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, @@ -180,4 +181,7 @@ int slhc_remember(struct slcompress *comp, unsigned char *icp, int isize); int slhc_toss(struct slcompress *comp); +void slhc_i_status(struct slcompress *comp); +void slhc_o_status(struct slcompress *comp); + #endif /* _SLHC_H */ diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index fa4a3dd..245636b 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -26,7 +26,8 @@ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ - oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c + oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ + slhc.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/slhc.c b/openbsc/src/gprs/slhc.c index 27ed252..cbdf8db 100644 --- a/openbsc/src/gprs/slhc.c +++ b/openbsc/src/gprs/slhc.c @@ -50,61 +50,77 @@ * driver code belonging close to PPP and SLIP */ -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#ifdef CONFIG_INET -/* Entire module is for IP only */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#define ERR_PTR(x) x + static unsigned char *encode(unsigned char *cp, unsigned short n); static long decode(unsigned char **cpp); static unsigned char * put16(unsigned char *cp, unsigned short x); static unsigned short pull16(unsigned char **cpp); +/* Replacement for kernel space function ip_fast_csum() */ +static uint16_t ip_fast_csum(uint8_t *iph, int ihl) +{ + int i; + uint16_t temp; + uint32_t accumulator = 0xFFFF; + + for(i=0;i0xFFFF) + { + accumulator++; + accumulator&=0xFFFF; + } + } + + return (uint16_t)(htons(~accumulator)&0xFFFF); +} + +/* Replacement for kernel space function put_unaligned() */ +static void put_unaligned(uint16_t val, void *ptr) +{ + memcpy(ptr,&val,sizeof(val)); +} + + /* Allocate compression data structure * slots must be in range 0 to 255 (zero meaning no compression) * Returns pointer to structure or ERR_PTR() on error. */ struct slcompress * -slhc_init(int rslots, int tslots) +slhc_init(const void *ctx, int rslots, int tslots) { register short i; register struct cstate *ts; struct slcompress *comp; if (rslots < 0 || rslots > 255 || tslots < 0 || tslots > 255) - return ERR_PTR(-EINVAL); + return NULL; - comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL); + comp = (struct slcompress *)talloc_zero_size(ctx,sizeof(struct slcompress)); if (! comp) goto out_fail; if (rslots > 0) { size_t rsize = rslots * sizeof(struct cstate); - comp->rstate = kzalloc(rsize, GFP_KERNEL); + comp->rstate = (struct cstate *) talloc_zero_size(ctx, rsize); if (! comp->rstate) goto out_free; comp->rslot_limit = rslots - 1; @@ -112,7 +128,7 @@ if (tslots > 0) { size_t tsize = tslots * sizeof(struct cstate); - comp->tstate = kzalloc(tsize, GFP_KERNEL); + comp->tstate = (struct cstate *) talloc_zero_size(ctx, tsize); if (! comp->tstate) goto out_free2; comp->tslot_limit = tslots - 1; @@ -141,11 +157,11 @@ return comp; out_free2: - kfree(comp->rstate); + talloc_free(comp->rstate); out_free: - kfree(comp); + talloc_free(comp); out_fail: - return ERR_PTR(-ENOMEM); + return NULL; } @@ -153,16 +169,18 @@ void slhc_free(struct slcompress *comp) { + DEBUGP(DSLHC, "slhc_free(): Freeing compression states...\n"); + if ( comp == NULLSLCOMPR ) return; if ( comp->tstate != NULLSLSTATE ) - kfree( comp->tstate ); + talloc_free(comp->tstate ); if ( comp->rstate != NULLSLSTATE ) - kfree( comp->rstate ); + talloc_free( comp->rstate ); - kfree( comp ); + talloc_free( comp ); } @@ -187,6 +205,8 @@ } else { *cp++ = n; } + + DEBUGP(DSLHC, "encode(): n=%04x\n",n); return cp; } @@ -256,6 +276,7 @@ comp->sls_o_nontcp++; else comp->sls_o_tcp++; + DEBUGP(DSLHC, "slhc_compress(): Not a TCP packat, will not touch...\n"); return isize; } /* Extract TCP header */ @@ -271,6 +292,7 @@ ! (th->ack)){ /* TCP connection stuff; send as regular IP */ comp->sls_o_tcp++; + DEBUGP(DSLHC, "slhc_compress(): Packet is part of a TCP connection, will not touch...\n"); return isize; } /* @@ -287,6 +309,9 @@ * states via linear search. If we don't find a state * for the datagram, the oldest state is (re-)used. */ + + DEBUGP(DSLHC, "slhc_compress(): Compressible packet detected!\n"); + for ( ; ; ) { if( ip->saddr == cs->cs_ip.saddr && ip->daddr == cs->cs_ip.daddr @@ -310,11 +335,14 @@ * state points to the newest and we only need to set * xmit_oldest to update the lru linkage. */ + + DEBUGP(DSLHC, "slhc_compress(): Header not yet seen, will memorize header for the next turn...\n"); comp->sls_o_misses++; comp->xmit_oldest = lcs->cs_this; goto uncompressed; found: + DEBUGP(DSLHC, "slhc_compress(): Header already seen, trying to compress...\n"); /* * Found it -- move to the front on the connection list. */ @@ -344,6 +372,39 @@ */ oth = &cs->cs_tcp; + /* Display a little more debug information about which of the + * header fields changed unexpectedly */ + if(ip->version != cs->cs_ip.version) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->version != cs->cs_ip.version\n"); + if(ip->ihl != cs->cs_ip.ihl) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->ihl != cs->cs_ip.ihl\n"); + if(ip->tos != cs->cs_ip.tos) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->tos != cs->cs_ip.tos\n"); + if((ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))\n"); + if(ip->ttl != cs->cs_ip.ttl) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->ttl != cs->cs_ip.ttl\n"); + if(th->doff != cs->cs_tcp.doff) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: th->doff != cs->cs_tcp.doff\n"); + if(ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) { + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0)\n"); + DEBUGP(DSLHC, "slhc_compress(): ip->ihl = %i\n", ip->ihl); + DEBUGP(DSLHC, "slhc_compress(): ip+1 = %s\n", + osmo_hexdump_nospc((uint8_t*)(ip+1),((ip->ihl)-5)*4)); + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: cs->cs_ipopt = %s\n", + osmo_hexdump_nospc((uint8_t*)(cs->cs_ipopt),((ip->ihl)-5)*4)); + } + if(th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0) { + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)\n"); + DEBUGP(DSLHC, "slhc_compress(): th->doff = %i\n", th->doff); + DEBUGP(DSLHC, "slhc_compress(): th+1 = %s\n", + osmo_hexdump_nospc((uint8_t*)(th+1),((th->doff)-5)*4)); + DEBUGP(DSLHC, "slhc_compress(): cs->cs_tcpopt = %s\n", + osmo_hexdump_nospc((uint8_t*)cs->cs_tcpopt, + ((th->doff)-5)*4)); + } + + if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl || ip->tos != cs->cs_ip.tos || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000)) @@ -351,6 +412,7 @@ || th->doff != cs->cs_tcp.doff || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){ + DEBUGP(DSLHC, "slhc_compress(): The header contains unexpected changes, can't compress...\n"); goto uncompressed; } @@ -362,6 +424,7 @@ */ if(th->urg){ deltaS = ntohs(th->urg_ptr); + DEBUGP(DSLHC, "slhc_compress(): flag: Urgent Pointer (U) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_U; } else if(th->urg_ptr != oth->urg_ptr){ @@ -369,21 +432,29 @@ * implementation should never do this but RFC793 * doesn't prohibit the change so we have to deal * with it. */ + DEBUGP(DSLHC, "slhc_compress(): URG not set but urp changed, can't compress...\n"); goto uncompressed; } if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){ + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Window (W) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_W; } if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){ - if(deltaA > 0x0000ffff) + if(deltaA > 0x0000ffff) { + DEBUGP(DSLHC, "slhc_compress(): (deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L, can't compress...\n"); goto uncompressed; + } + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Ack (A) = 1\n"); cp = encode(cp,deltaA); changes |= NEW_A; } if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){ - if(deltaS > 0x0000ffff) + if(deltaS > 0x0000ffff) { + DEBUGP(DSLHC, "slhc_compress(): (deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L, can't compress...\n"); goto uncompressed; + } + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_S; } @@ -399,17 +470,21 @@ if(ip->tot_len != cs->cs_ip.tot_len && ntohs(cs->cs_ip.tot_len) == hlen) break; + DEBUGP(DSLHC, "slhc_compress(): Retransmitted packet detected, can't compress...\n"); goto uncompressed; case SPECIAL_I: case SPECIAL_D: /* actual changes match one of our special case encodings -- * send packet uncompressed. */ + DEBUGP(DSLHC, "slhc_compress(): Special case detected, can't compress...\n"); goto uncompressed; case NEW_S|NEW_A: if(deltaS == deltaA && deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ /* special case for echoed terminal traffic */ + DEBUGP(DSLHC, "slhc_compress(): Special case for echoed terminal traffic detected...\n"); + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1, Delta Window (W) = 1, Urgent Pointer (U) = 1\n"); changes = SPECIAL_I; cp = new_seq; } @@ -417,6 +492,8 @@ case NEW_S: if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ /* special case for data xfer */ + DEBUGP(DSLHC, "slhc_compress(): Special case for data xfer detected...\n"); + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1, Delta Ack (A) = 1, Delta Window (W) = 1, Urgent Pointer (U) = 1\n"); changes = SPECIAL_D; cp = new_seq; } @@ -424,11 +501,14 @@ } deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id); if(deltaS != 1){ + DEBUGP(DSLHC, "slhc_compress(): flag: Delta IP ID (I) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_I; } - if(th->psh) + if(th->psh) { + DEBUGP(DSLHC, "slhc_compress(): flag: Push (P) = 1\n"); changes |= TCP_PUSH_BIT; + } /* Grab the cksum before we overwrite it below. Then update our * state with this packet's header. */ @@ -445,6 +525,7 @@ if(compress_cid == 0 || comp->xmit_current != cs->cs_this){ cp = ocp; *cpp = ocp; + DEBUGP(DSLHC, "slhc_compress(): flag: Connection number (C) = 1\n"); *cp++ = changes | NEW_C; *cp++ = cs->cs_this; comp->xmit_current = cs->cs_this; @@ -456,6 +537,10 @@ *(__sum16 *)cp = csum; cp += 2; /* deltaS is now the size of the change section of the compressed header */ + + DEBUGP(DSLHC, "slhc_compress(): Delta-list length (deltaS) = %li\n",deltaS); + DEBUGP(DSLHC, "slhc_compress(): Original header len (hlen) = %i\n",hlen); + memcpy(cp,new_seq,deltaS); /* Write list of deltas */ memcpy(cp+deltaS,icp+hlen,isize-hlen); comp->sls_o_compressed++; @@ -467,6 +552,7 @@ * to use on future compressed packets in the protocol field). */ uncompressed: + DEBUGP(DSLHC, "slhc_compress(): Packet will be sent uncompressed...\n"); memcpy(&cs->cs_ip,ip,20); memcpy(&cs->cs_tcp,th,20); if (ip->ihl > 5) @@ -538,6 +624,8 @@ switch(changes & SPECIALS_MASK){ case SPECIAL_I: /* Echoed terminal traffic */ + DEBUGP(DSLHC, "slhc_uncompress(): Echoed terminal traffic detected\n"); + { register short i; i = ntohs(ip->tot_len) - hdrlen; @@ -547,11 +635,13 @@ break; case SPECIAL_D: /* Unidirectional data */ + DEBUGP(DSLHC, "slhc_uncompress(): Unidirectional data detected\n"); thp->seq = htonl( ntohl(thp->seq) + ntohs(ip->tot_len) - hdrlen); break; default: + DEBUGP(DSLHC, "slhc_uncompress(): default packet type detected\n"); if(changes & NEW_U){ thp->urg = 1; if((x = decode(&cp)) == -1) { @@ -601,6 +691,7 @@ ip->tot_len = htons(len); ip->check = 0; + DEBUGP(DSLHC, "slhc_uncompress(): making space for the reconstructed header...\n"); memmove(icp + hdrlen, cp, len - hdrlen); cp = icp; @@ -625,6 +716,7 @@ return len; bad: + DEBUGP(DSLHC, "slhc_uncompress(): bad packet detected!\n"); comp->sls_i_error++; return slhc_toss( comp ); } @@ -641,6 +733,7 @@ if(isize < 20) { /* The packet is shorter than a legal IP header */ comp->sls_i_runt++; + DEBUGP(DSLHC, "slhc_remember(): The packet is shorter than a legal IP header ==> slhc_toss()\n"); return slhc_toss( comp ); } /* Peek at the IP header's IHL field to find its length */ @@ -648,6 +741,7 @@ if(ihl < 20 / 4){ /* The IP header length field is too small */ comp->sls_i_runt++; + DEBUGP(DSLHC, "slhc_remember(): The IP header length field is too small ==> slhc_toss()\n"); return slhc_toss( comp ); } index = icp[9]; @@ -656,10 +750,12 @@ if (ip_fast_csum(icp, ihl)) { /* Bad IP header checksum; discard */ comp->sls_i_badcheck++; + DEBUGP(DSLHC, "slhc_remember(): Bad IP header checksum; discard ==> slhc_toss()\n"); return slhc_toss( comp ); } if(index > comp->rslot_limit) { comp->sls_i_error++; + DEBUGP(DSLHC, "slhc_remember(): index > comp->rslot_limit ==> slhc_toss()\n"); return slhc_toss(comp); } @@ -683,6 +779,7 @@ int slhc_toss(struct slcompress *comp) { + DEBUGP(DSLHC, "slhc_toss(): Reset compression state...\n"); if ( comp == NULLSLCOMPR ) return 0; @@ -690,55 +787,27 @@ return 0; } -#else /* CONFIG_INET */ - -int -slhc_toss(struct slcompress *comp) +void slhc_i_status(struct slcompress *comp) { - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss"); - return -EINVAL; -} -int -slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress"); - return -EINVAL; -} -int -slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, - unsigned char *ocp, unsigned char **cpp, int compress_cid) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress"); - return -EINVAL; + if (comp != NULLSLCOMPR) { + DEBUGP(DSLHC, "slhc_i_status(): %d Cmp, %d Uncmp, %d Bad, %d Tossed\n", + comp->sls_i_compressed, + comp->sls_i_uncompressed, + comp->sls_i_error, + comp->sls_i_tossed); + } } -int -slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +void slhc_o_status(struct slcompress *comp) { - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember"); - return -EINVAL; + if (comp != NULLSLCOMPR) { + DEBUGP(DSLHC, "slhc_o_status(): %d Cmp, %d Uncmp, %d AsIs, %d NotTCP %d Searches, %d Misses\n", + comp->sls_o_compressed, + comp->sls_o_uncompressed, + comp->sls_o_tcp, + comp->sls_o_nontcp, + comp->sls_o_searches, + comp->sls_o_misses); + } } -void -slhc_free(struct slcompress *comp) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free"); -} -struct slcompress * -slhc_init(int rslots, int tslots) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init"); - return NULL; -} - -#endif /* CONFIG_INET */ - -/* VJ header compression */ -EXPORT_SYMBOL(slhc_init); -EXPORT_SYMBOL(slhc_free); -EXPORT_SYMBOL(slhc_remember); -EXPORT_SYMBOL(slhc_compress); -EXPORT_SYMBOL(slhc_uncompress); -EXPORT_SYMBOL(slhc_toss); - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index 1debb2d..d5aa356 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid slhc if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 45d1780..3e66978 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -32,6 +32,7 @@ $(top_builddir)/src/gprs/oap_messages.o \ $(top_builddir)/src/gprs/gprs_llc_xid.o \ $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ + $(top_builddir)/src/gprs/slhc.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ diff --git a/openbsc/tests/slhc/Makefile.am b/openbsc/tests/slhc/Makefile.am new file mode 100644 index 0000000..d21990f --- /dev/null +++ b/openbsc/tests/slhc/Makefile.am @@ -0,0 +1,21 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) + +EXTRA_DIST = slhc_test.ok + +noinst_PROGRAMS = slhc_test + +slhc_test_SOURCES = slhc_test.c + +slhc_test_LDADD = \ + $(top_builddir)/src/gprs/slhc.o \ + $(top_builddir)/src/libcommon/libcommon.a \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOGB_LIBS) \ + $(LIBCARES_LIBS) \ + $(LIBCRYPTO_LIBS) \ + -lgtp -lrt -lm + + diff --git a/openbsc/tests/slhc/packets.txt b/openbsc/tests/slhc/packets.txt new file mode 100644 index 0000000..9f7adeb --- /dev/null +++ b/openbsc/tests/slhc/packets.txt @@ -0,0 +1,6 @@ +4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 +4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 +4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 +4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 +4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a +4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20 diff --git a/openbsc/tests/slhc/slhc_test.c b/openbsc/tests/slhc/slhc_test.c new file mode 100644 index 0000000..41babae --- /dev/null +++ b/openbsc/tests/slhc/slhc_test.c @@ -0,0 +1,311 @@ +/* Test SLHC/RFC1144 TCP/IP Header compression/decompression */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include + +#include +#include + +#include + +#include +#include +#include + +/* Number of compression slots (S0-1) */ +#define SLOTS 8 + +/* Maximum packet bytes to display */ +#define DISP_MAX_BYTES 100 + +/* Compress a packet using Van Jacobson RFC1144 header compression */ +static int compress(uint8_t *data_o, uint8_t *data_i, int len, + struct slcompress *comp) +{ + uint8_t *comp_ptr; /* Not used */ + int compr_len; + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Run compressor */ + compr_len = slhc_compress(comp, data_i, len, data_o, &comp_ptr, 0); + return compr_len; +} + +/* Expand a packet using Van Jacobson RFC1144 header compression */ +static int expand(uint8_t *data_o, uint8_t *data_i, int len, + struct slcompress *comp) +{ + int data_decompressed_len; + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Handle an uncompressed packet (learn header information */ + if ((data_i[0] & SL_TYPE_UNCOMPRESSED_TCP) == SL_TYPE_UNCOMPRESSED_TCP) { + data_o[0] &= 0x4F; + data_decompressed_len = slhc_remember(comp, data_o, len); + return data_decompressed_len; + } + + /* Uncompress compressed packets */ + else if (data_o[0] & SL_TYPE_COMPRESSED_TCP) { + data_decompressed_len = slhc_uncompress(comp, data_o, len); + return data_decompressed_len; + } + + /* Regular or unknown packets will not be touched */ + return len; +} + +/* Calculate TCP/IP checksum */ +static uint16_t calc_ip_csum(uint8_t *data, int len) +{ + int i; + uint32_t accumulator = 0; + uint16_t *pointer = (uint16_t *) data; + + for (i = len; i > 1; i -= 2) { + accumulator += *pointer; + pointer++; + } + + if (len % 2) + accumulator += *pointer; + + accumulator = (accumulator & 0xffff) + ((accumulator >> 16) & 0xffff); + accumulator += (accumulator >> 16) & 0xffff; + return (~accumulator); +} + +/* Calculate TCP/IP checksum */ +static uint16_t calc_tcpip_csum(const void *ctx, uint8_t *packet, int len) +{ + uint8_t *buf; + uint16_t csum; + + buf = talloc_zero_size(ctx, len); + memset(buf, 0, len); + memcpy(buf, packet + 12, 8); + buf[9] = packet[9]; + buf[11] = (len - 20) & 0xFF; + buf[10] = (len - 20) >> 8 & 0xFF; + memcpy(buf + 12, packet + 20, len - 20); + csum = calc_ip_csum(buf, len - 20 + 12); + talloc_free(buf); + return csum; +} + +/* Check TCP/IP packet */ +static void check_packet(const void *ctx, uint8_t *packet, int len) +{ + /* Check IP header */ + OSMO_ASSERT(len > 20); + OSMO_ASSERT(calc_ip_csum(packet, 20) == 0); + + /* Check TCP packet */ + if (packet[9] != 0x06) + return; + OSMO_ASSERT(len > 40); + OSMO_ASSERT(calc_tcpip_csum(ctx, packet, len) == 0); +} + +/* Strip TCP options from TCP/IP packet */ +static int strip_tcp_options(const void *ctx, uint8_t *packet, int len) +{ + uint8_t doff; + uint16_t csum; + + /* Check if the packet can be handled here */ + if (len < 37) + return len; + if (packet[9] != 0x06) + return len; + + /* Strip TCP/IP options from packet */ + doff = ((packet[32] >> 4) & 0x0F) * 4; + memmove(packet + 40, packet + doff + 20, len - 40 - (doff - 20)); + len = len - (doff - 20); + + /* Repair data offset (TCP header length) */ + packet[32] &= 0x0F; + packet[32] |= 0x50; + + /* Repair checksum */ + packet[36] = 0; + packet[37] = 0; + csum = calc_tcpip_csum(ctx, packet, len); + packet[36] = csum & 0xFF; + packet[37] = csum >> 8 & 0xFF; + + /* Repair total length */ + packet[3] = len & 0xFF; + packet[2] = len >> 8 & 0xFF; + + /* Repair IP header checksum */ + packet[10] = 0; + packet[11] = 0; + csum = calc_ip_csum(packet, 20); + packet[10] = csum & 0xFF; + packet[11] = csum >> 8 & 0xFF; + printf("csum=%04x\n", csum); + + return len; +} + +/* osmo_hexparse() does not like line breaks, this fixes that */ +static void fixup_hexstring(char *str) +{ + int i; + for (i = 0; i < strlen(str); i++) { + if (str[i] == '\n') + str[i] = 0; + } +} + +/* Compress / Decompress packets */ +static void test_slhc(const void *ctx) +{ + char packet_ascii[2048]; + FILE *fd = NULL; + char *rc_fgets; + + struct slcompress *comp; + uint8_t packet[1024]; + int packet_len; + uint8_t packet_compr[1024]; + int packet_compr_len; + uint8_t packet_decompr[1024]; + int packet_decompr_len; + + + printf("Allocating compression state...\n"); + comp = slhc_init(ctx, SLOTS, SLOTS); + OSMO_ASSERT(comp); + + printf("Opening file with sample packets...\n"); + fd = fopen("packets.txt", "r"); + OSMO_ASSERT(fd) + printf("\n"); + + while (1) { + /* Read input file */ + memset(packet_ascii, 0, sizeof(packet_ascii)); + memset(packet, 0, sizeof(packet)); + memset(packet_compr, 0, sizeof(packet_compr)); + memset(packet_decompr, 0, sizeof(packet_decompr)); + printf("Reading packet from file...\n"); + rc_fgets = fgets(packet_ascii, sizeof(packet_ascii), fd); + if (rc_fgets == NULL || strlen(packet_ascii) < 20) { + printf("=> End of file detected, test done!\n\n"); + break; + } + fixup_hexstring(packet_ascii); + packet_len = + osmo_hexparse(packet_ascii, packet, sizeof(packet)); + check_packet(ctx, packet, packet_len); + packet_len = strip_tcp_options(ctx, packet, packet_len); + check_packet(ctx, packet, packet_len); + + /* Run compression/decompression algorithm */ + printf("Compressing...\n"); + packet_compr_len = + compress(packet_compr, packet, packet_len, comp); + printf("Decompressing...\n"); + packet_decompr_len = + expand(packet_decompr, packet_compr, packet_compr_len, + comp); + OSMO_ASSERT(packet_decompr_len == packet_len); + check_packet(ctx,packet_decompr,packet_decompr_len); + + /* Display results */ + printf("Results:\n"); + if (packet_compr_len > DISP_MAX_BYTES) + packet_compr_len = DISP_MAX_BYTES; + if (packet_len > DISP_MAX_BYTES) + packet_len = DISP_MAX_BYTES; + if (packet_decompr_len > DISP_MAX_BYTES) + packet_decompr_len = DISP_MAX_BYTES; + printf("Original Packet: (%i bytes) %s\n", packet_len, + osmo_hexdump_nospc(packet, packet_len)); + printf("DecompressedPacket: (%i bytes) %s\n", + packet_decompr_len, osmo_hexdump_nospc(packet_decompr, + packet_decompr_len)); + printf("CompressedPacket: (%i bytes) %s\n", packet_compr_len, + osmo_hexdump_nospc(packet_compr, packet_compr_len)); + slhc_o_status(comp); + slhc_o_status(comp); + + printf("\n"); + } + + printf("Freeing compression state...\n"); + slhc_free(comp); + printf("\n"); + fclose(fd); +} + +static struct log_info_cat gprs_categories[] = { + [DSNDCP] = { + .name = "DSNDCP", + .description = + "GPRS Sub-Network Dependent Control Protocol (SNDCP)", + .enabled = 1,.loglevel = LOGL_DEBUG, + }, + [DSLHC] = { + .name = "DSLHC", + .description = + "Van Jacobson RFC1144 TCP/IP header compression (SLHC)", + .enabled = 1,.loglevel = LOGL_DEBUG, + } +}; + +static struct log_info info = { + .cat = gprs_categories, + .num_cat = ARRAY_SIZE(gprs_categories), +}; + +int main(int argc, char **argv) +{ + void *ctx; + + osmo_init_logging(&info); + + ctx = talloc_named_const(NULL, 0, "slhc_ctx"); + + test_slhc(ctx); + + printf("Done\n"); + + talloc_report_full(ctx, stderr); + OSMO_ASSERT(talloc_total_blocks(ctx) == 1); + return 0; +} + +/* stubs */ +struct osmo_prim_hdr; +int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) +{ + abort(); +} diff --git a/openbsc/tests/slhc/slhc_test.ok b/openbsc/tests/slhc/slhc_test.ok new file mode 100644 index 0000000..3f802ea --- /dev/null +++ b/openbsc/tests/slhc/slhc_test.ok @@ -0,0 +1,63 @@ +Allocating compression state... +Opening file with sample packets... + +Reading packet from file... +csum=b3a9 +Compressing... +Decompressing... +Results: +Original Packet: (52 bytes) 4510003446dd40004006a9b3c0a8646ec0a864640017ad8b81980100f3ac984d501800e371410000fffd18fffd20fffd23fffd27 +DecompressedPacket: (52 bytes) 4510003446dd40004006a9b3c0a8646ec0a864640017ad8b81980100f3ac984d501800e371410000fffd18fffd20fffd23fffd27 +CompressedPacket: (52 bytes) 7510003446dd40004000a9b3c0a8646ec0a864640017ad8b81980100f3ac984d501800e371410000fffd18fffd20fffd23fffd27 + +Reading packet from file... +csum=97a9 +Compressing... +Decompressing... +Results: +Original Packet: (79 bytes) 4510004f46de40004006a997c0a8646ec0a864640017ad8b8198010cf3ac984d501800e3cda40000fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 +DecompressedPacket: (79 bytes) 4510004f46de40004006a997c0a8646ec0a864640017ad8b8198010cf3ac984d501800e3cda40000fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 +CompressedPacket: (43 bytes) df00cda4fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 + +Reading packet from file... +csum=baa9 +Compressing... +Decompressing... +Results: +Original Packet: (43 bytes) 4510002b46df40004006a9bac0a8646ec0a864640017ad8b81980133f3ac989f501800e3a70a0000fffd01 +DecompressedPacket: (43 bytes) 4510002b46df40004006a9bac0a8646ec0a864640017ad8b81980133f3ac989f501800e3a70a0000fffd01 +CompressedPacket: (9 bytes) dc00a70a5227fffd01 + +Reading packet from file... +csum=b9a9 +Compressing... +Decompressing... +Results: +Original Packet: (43 bytes) 4510002b46e040004006a9b9c0a8646ec0a864640017ad8b81980136f3ac98a2501800e3a7060000fffb01 +DecompressedPacket: (43 bytes) 4510002b46e040004006a9b9c0a8646ec0a864640017ad8b81980136f3ac98a2501800e3a7060000fffb01 +CompressedPacket: (7 bytes) db00a706fffb01 + +Reading packet from file... +csum=7ba9 +Compressing... +Decompressing... +Results: +Original Packet: (100 bytes) 4510006846e140004006a97bc0a8646ec0a864640017ad8b81980139f3ac98a5501800e3c2d000000d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d +DecompressedPacket: (100 bytes) 4510006846e140004006a97bc0a8646ec0a864640017ad8b81980139f3ac98a5501800e3c2d000000d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d +CompressedPacket: (68 bytes) db00c2d00d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a + +Reading packet from file... +csum=aca9 +Compressing... +Decompressing... +Results: +Original Packet: (54 bytes) 4510003646e240004006a9acc0a8646ec0a864640017ad8b81980179f3ac98a5501800e321fb0000706f6c6c7578206c6f67696e3a20 +DecompressedPacket: (54 bytes) 4510003646e240004006a9acc0a8646ec0a864640017ad8b81980179f3ac98a5501800e321fb0000706f6c6c7578206c6f67696e3a20 +CompressedPacket: (18 bytes) df0021fb706f6c6c7578206c6f67696e3a20 + +Reading packet from file... +=> End of file detected, test done! + +Freeing compression state... + +Done diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index 85a81d6..5f37b8e 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -136,3 +136,8 @@ AT_CHECK([$abs_top_builddir/tests/sndcp_xid/sndcp_xid_test], [], [expout], [ignore]) AT_CLEANUP +AT_SETUP([slhc]) +AT_KEYWORDS([slhc]) +cat $abs_srcdir/slhc/slhc_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/slhc/slhc_test], [], [expout], [ignore]) +AT_CLEANUP -- To view, visit https://gerrit.osmocom.org/635 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 Gerrit-PatchSet: 11 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Thu Aug 18 09:41:14 2016 From: gerrit-no-reply at lists.osmocom.org (pravin) Date: Thu, 18 Aug 2016 09:41:14 +0000 Subject: [PATCH] osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Hello Max, Neels Hofmeyr, Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/416 to look at the new patch set (#18). Add decoding of compressed bitmap in EPDAN Implemented tree based algorithm to decode compressed bitmap in EPDAN as described in section 9.1.10 of 3GPP 44.060. This algorithm intends to improve the performance over existing method. New Regression test is added under bitcomp directory. Test case is added to validate decompressed result of the bitmap Present in EPDAN. Test is done for multiple bitmaps of varying length. Invalid inputs are also part of the test vector. Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce --- M src/Makefile.am M src/decoding.cpp A src/egprs_rlc_compression.cpp A src/egprs_rlc_compression.h M tests/Makefile.am A tests/bitcomp/BitcompTest A tests/bitcomp/BitcompTest.cpp A tests/bitcomp/BitcompTest.err A tests/bitcomp/BitcompTest.ok M tests/testsuite.at 10 files changed, 780 insertions(+), 18 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/16/416/18 diff --git a/src/Makefile.am b/src/Makefile.am index 9bdec2f..9b047e7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -62,7 +62,8 @@ rlc.cpp \ osmobts_sock.cpp \ gprs_codel.c \ - gprs_coding_scheme.cpp + gprs_coding_scheme.cpp \ + egprs_rlc_compression.cpp bin_PROGRAMS = \ osmo-pcu @@ -94,7 +95,8 @@ pcu_utils.h \ cxx_linuxlist.h \ gprs_codel.h \ - gprs_coding_scheme.h + gprs_coding_scheme.h \ + egprs_rlc_compression.h osmo_pcu_SOURCES = pcu_main.cpp diff --git a/src/decoding.cpp b/src/decoding.cpp index 7c00ff7..2b00a07 100644 --- a/src/decoding.cpp +++ b/src/decoding.cpp @@ -20,6 +20,7 @@ #include #include #include +#include extern "C" { #include @@ -652,10 +653,10 @@ int num_blocks = 0; struct bitvec urbb; int i; + int rc; bool have_bitmap; int implicitly_acked_blocks; int ssn = desc->STARTING_SEQUENCE_NUMBER; - int rc; if (desc->FINAL_ACK_INDICATION) return handle_final_ack(bits, bsn_begin, bsn_end, window); @@ -695,24 +696,20 @@ if (crbb_len > 0) { int old_len = bits->cur_bit; - struct bitvec crbb; - crbb.data = (uint8_t *)desc->CRBB; - crbb.data_len = sizeof(desc->CRBB); - crbb.cur_bit = desc->CRBB_LENGTH; - - rc = osmo_t4_decode(&crbb, desc->CRBB_STARTING_COLOR_CODE, - bits); - + LOGP(DRLCMACDL, LOGL_DEBUG, "Compress bitmap exist," + "CRBB LEN =%d and Starting color code =%d", + desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE); + rc = decompress_crbb(desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE, + desc->CRBB, bits); if (rc < 0) { LOGP(DRLCMACUL, LOGL_NOTICE, - "Failed to decode CRBB: " - "length %d, data '%s'\n", - desc->CRBB_LENGTH, - osmo_hexdump(crbb.data, crbb.data_len)); + "Failed to decode CRBB: length %d, data '%s'\n", + desc->CRBB_LENGTH, osmo_hexdump( + desc->CRBB, (desc->CRBB_LENGTH + 7)/8)); /* We don't know the SSN offset for the URBB, - * return what we have so far and assume the - * bitmap has stopped here */ + * return what we have so far and assume the + * bitmap has stopped here */ goto aborted; } diff --git a/src/egprs_rlc_compression.cpp b/src/egprs_rlc_compression.cpp new file mode 100644 index 0000000..e18dc20 --- /dev/null +++ b/src/egprs_rlc_compression.cpp @@ -0,0 +1,340 @@ +/* egprs_rlc_compression.h +* Routines for EGPRS RLC bitmap compression handling +*/ +#include +#include +#include + +extern "C" { +#include +#include +#include +} + +egprs_compress *egprs_compress::s_instance = 0; + +/* Function to create tree node */ +Node *egprs_compress::create_tree_node() +{ + Node *new_node; + + new_node = talloc_zero(tall_tree_ctx, Node); + new_node->left = NULL; + new_node->right = NULL; + new_node->run_length = -1; + return new_node; +} + +/* Function to build the codeword tree + * \param iter[in] Iterate the node on the tree + * \param len[in] Length of the code word + * \param i[in] Iterator + * \param idx[in] Iterate index of the code word table + */ +void egprs_compress::build_codeword(Node *root, const char *cdwd[]) +{ + Node *iter; + int len; + int i; + int idx; + + root->left = NULL; + root->right = NULL; + root->run_length = -1; + + for (idx = 0; idx < MAX_CDWDTBL_LEN; idx++) { + len = strlen((const char *)cdwd[idx]); + iter = root; + for (i = 0; i < len; i++) { + if (cdwd[idx][i] == '0') { + if (!iter->left) + iter->left = create_tree_node(); + iter = iter->left; + } else if (cdwd[idx][i] == '1') { + if (!iter->right) + iter->right = create_tree_node(); + iter = iter->right; + } + } + if (iter) { + if (idx < 64) + (iter->run_length) = idx; + else + (iter->run_length) = (idx - 63) * 64; + } + } +} + +const char *one_run_len_code_list[MAX_CDWDTBL_LEN] = { + "00110101", + "000111", + "0111", + "1000", + "1011", + "1100", + "1110", + "1111", + "10011", + "10100", + "00111", + "01000", + "001000", + "000011", + "110100", + "110101", + "101010", + "101011", + "0100111", + "0001100", + "0001000", + "0010111", + "0000011", + "0000100", + "0101000", + "0101011", + "0010011", + "0100100", + "0011000", + "00000010", + "00000011", + "00011010", + "00011011", + "00010010", + "00010011", + "00010100", + "00010101", + "00010110", + "00010111", + "00101000", + "00101001", + "00101010", + "00101011", + "00101100", + "00101101", + "00000100", + "00000101", + "00001010", + "00001011", + "01010010", + "01010011", + "01010100", + "01010101", + "00100100", + "00100101", + "01011000", + "01011001", + "01011010", + "01011011", + "01001010", + "01001011", + "00110010", + "00110011", + "00110100", + "11011", + "10010", + "010111", + "0110111", + "00110110", + "00110111", + "01100100", + "01100101", + "01101000", + "01100111", + "011001100", + "011001101", + "011010010", + "011010011", + "011010100" +}; + +const char *zero_run_len_code_list[MAX_CDWDTBL_LEN] = { + "0000110111", + "10", + "11", + "010", + "011", + "0011", + "0010", + "00011", + "000101", + "000100", + "0000100", + "0000101", + "0000111", + "00000100", + "00000111", + "000011000", + "0000010111", + "0000011000", + "0000001000", + "00001100111", + "00001101000", + "00001101100", + "00000110111", + "00000101000", + "00000010111", + "00000011000", + "000011001010", + "000011001011", + "000011001100", + "000011001101", + "000001101000", + "000001101001", + "000001101010", + "000001101011", + "000011010010", + "000011010011", + "000011010100", + "000011010101", + "000011010110", + "000011010111", + "000001101100", + "000001101101", + "000011011010", + "000011011011", + "000001010100", + "000001010101", + "000001010110", + "000001010111", + "000001100100", + "000001100101", + "000001010010", + "000001010011", + "000000100100", + "000000110111", + "000000111000", + "000000100111", + "000000101000", + "000001011000", + "000001011001", + "000000101011", + "000000101100", + "000001011010", + "000001100110", + "000001100111", + "0000001111", + "000011001000", + "000011001001", + "000001011011", + "000000110011", + "000000110100", + "000000110101", + "0000001101100", + "0000001101101", + "0000001001010", + "0000001001011", + "0000001001100", + "0000001001101", + "0000001110010", + "0000001110011" +}; + +/* search_runlen function will return the runlength for the codeword + * \param root[in] Root of Ones or Zeros tree + * \param bmbuf[in] Recevied compressed bitmap buf + * \param bit_pos[in] The start bit pos to read codeword + * \param len_codewd[in] Length of code word + * \param rlen[out] Run length value + */ +static int search_runlen( + Node *root, + const uint8_t *bmbuf, + uint8_t bit_pos, + uint8_t *len_codewd, + uint16_t *rlen) +{ + Node *iter; + uint8_t dir; + + iter = root; + *len_codewd = 0; + + while (iter->run_length == -1) { + if ((!iter->left) && (!iter->right)) + return -1; + /* get the bit value at the bitpos and put it in right most of dir */ + dir = ((bmbuf[BITS_TO_BYTES(bit_pos)-1] + >>(7-(MOD8(bit_pos)))) & 0x01); + (bit_pos)++; + (*len_codewd)++; + if (((dir&0x01) == 0) && (iter->left != NULL)) + iter = iter->left; + else if (((dir&0x01) == 1) && (iter->right != NULL)) + iter = iter->right; + else + return -1; + } + (*rlen) = (iter->run_length); + return 1; +} + +/* Function to decompress crbb + * \param[in] Compressed bitmap length + * \clr_code_bit[in] Color code 1 for Ones runlength 0 for Zero runlength + * \orig_crbb_buf[in] Received block crbb bitmap + * \dest[out] Uncompressed bitvector + */ +int decompress_crbb( + int8_t compress_bmap_len, + uint8_t clr_code_bit, + const uint8_t *orig_crbb_buf, + bitvec *dest) +{ + + uint8_t bit_pos = 0; + uint8_t data = 0x0; + node *list = NULL; + uint8_t nbits = 0; /* number of bits of codeword */ + uint16_t run_length = 0; + uint16_t cbmaplen = 0; /* compressed bitmap part after decompression */ + unsigned wp = dest->cur_bit; + int rc = 0; + egprs_compress *compress = egprs_compress::instance(); + + while (compress_bmap_len > 0) { + if (clr_code_bit == 1) { + data = 0xff; + list = compress->ones_list; + } else { + data = 0x00; + list = compress->zeros_list; + } + rc = search_runlen(list, orig_crbb_buf, + bit_pos, &nbits, &run_length); + if (rc == -1) + return -1; + /* If run length > 64, need makeup and terminating code */ + if (run_length < 64) + clr_code_bit ? clr_code_bit = 0 : clr_code_bit = 1; + cbmaplen = cbmaplen + run_length; + /* put run length of Ones in uncompressed bitmap */ + while (run_length != 0) { + if (run_length > 8) { + bitvec_write_field(dest, wp, data, 8); + run_length = run_length - 8; + } else { + bitvec_write_field(dest, wp, data, run_length); + run_length = 0; + } + } + bit_pos = bit_pos + nbits; + compress_bmap_len = compress_bmap_len - nbits; + } + return 0; +} + +/* init function to build codeword */ +int egprs_compress::decode_tree_init() +{ + tall_tree_ctx = talloc_named_const(tall_pcu_ctx, 0, + "decode-tree context"); + if (!tall_tree_ctx) + return -ENOMEM; + ones_list = talloc(tall_tree_ctx, Node); + zeros_list = talloc(tall_tree_ctx, Node); + build_codeword( + ones_list, one_run_len_code_list); + build_codeword( + zeros_list, zero_run_len_code_list); + return 0; +} diff --git a/src/egprs_rlc_compression.h b/src/egprs_rlc_compression.h new file mode 100644 index 0000000..de1b2d2 --- /dev/null +++ b/src/egprs_rlc_compression.h @@ -0,0 +1,62 @@ +/* egprs_rlc_compression.h + * Routines for EGPRS RLC bitmap compression handling + */ +#include +#include + +extern "C" { +#include +} + +#include +#include +#include + +#define MAX_CDWDTBL_LEN 79 /* total number of codewords */ +#define BITS_TO_BYTES(X) ((X ? (X/8):0)+1) +#define MOD8(X) (((X)+8) & (0x07)) + +typedef struct node { + struct node *left; + struct node *right; + int run_length; +} Node; + +extern const char *one_run_len_code_list[MAX_CDWDTBL_LEN]; +extern const char *zero_run_len_code_list[MAX_CDWDTBL_LEN]; +extern void *tall_pcu_ctx; + +int decompress_crbb(int8_t compress_bmap_len, uint8_t clr_code_bit, + const uint8_t *orig_buf, bitvec *dest); + +/* Creating singleton class + */ +class egprs_compress +{ + void *tall_tree_ctx; + static egprs_compress *s_instance; + + egprs_compress() + { + if (decode_tree_init() < 0) { + fprintf(stderr, "Error initializing tree\n"); + exit(1); + } + } + Node *create_tree_node(); + void build_codeword(Node *root, const char *cdwd[]); + ~egprs_compress(); +public: + Node *ones_list; + Node *zeros_list; + + int decode_tree_init(void); + + static egprs_compress *instance() + { + if (!s_instance) + s_instance = new egprs_compress; + + return s_instance; + } +}; diff --git a/tests/Makefile.am b/tests/Makefile.am index 2a3415e..6325164 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,7 +1,7 @@ AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGB_CFLAGS) $(LIBOSMOGSM_CFLAGS) -I$(top_srcdir)/src/ AM_LDFLAGS = -lrt -check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest llc/LlcTest codel/codel_test edge/EdgeTest +check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest llc/LlcTest codel/codel_test edge/EdgeTest bitcomp/BitcompTest noinst_PROGRAMS = emu/pcu_emu rlcmac_RLCMACTest_SOURCES = rlcmac/RLCMACTest.cpp @@ -25,6 +25,18 @@ $(LIBOSMOGSM_LIBS) \ $(LIBOSMOCORE_LIBS) \ $(COMMON_LA) + +bitcomp_BitcompTest_SOURCES = bitcomp/BitcompTest.cpp +bitcomp_BitcompTest_LDADD = \ + $(top_builddir)/src/libgprs.la \ + $(LIBOSMOGB_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(COMMON_LA) + +bitcomp_BitcompTest_LDFLAGS = \ + -Wl,-u,bssgp_prim_cb + edge_EdgeTest_SOURCES = edge/EdgeTest.cpp edge_EdgeTest_LDADD = \ @@ -108,6 +120,7 @@ rlcmac/RLCMACTest.ok rlcmac/RLCMACTest.err \ alloc/AllocTest.ok alloc/AllocTest.err \ tbf/TbfTest.ok tbf/TbfTest.err \ + bitcomp/BitcompTest.ok bitcomp/BitcompTest.err \ types/TypesTest.ok types/TypesTest.err \ ms/MsTest.ok ms/MsTest.err \ llc/LlcTest.ok llc/LlcTest.err \ diff --git a/tests/bitcomp/BitcompTest b/tests/bitcomp/BitcompTest new file mode 100755 index 0000000..465de31 --- /dev/null +++ b/tests/bitcomp/BitcompTest Binary files differ diff --git a/tests/bitcomp/BitcompTest.cpp b/tests/bitcomp/BitcompTest.cpp new file mode 100644 index 0000000..1eb6fd3 --- /dev/null +++ b/tests/bitcomp/BitcompTest.cpp @@ -0,0 +1,246 @@ +#include "egprs_rlc_compression.h" +#include "decoding.h" +#include "bts.h" +#include "tbf.h" +#include "gprs_debug.h" +#include "pcu_utils.h" +#include "gprs_bssgp_pcu.h" +#include "pcu_l1_if.h" + +extern "C" { +#include "pcu_vty.h" + +#include +#include +#include +#include +#include +#include +} + +#define NEW 1 +#define MASK(n) (0xFF << (8-n)) +#define MAX_CRBB_LEN 23 +#define MAX_URBB_LEN 40 + +void *tall_pcu_ctx; +int16_t spoof_mnc = 0, spoof_mcc = 0; + +struct test_data { + int8_t crbb_len; + uint8_t cc; + uint8_t crbb_data[MAX_CRBB_LEN]; /* compressed data */ + uint8_t ucmp_data[MAX_URBB_LEN]; /* uncompressed data */ + int ucmp_len; + int verify; +} test[] = { + { .crbb_len = 67, .cc = 1, + .crbb_data = { + 0x02, 0x0c, 0xa0, 0x30, 0xcb, 0x1a, 0x0c, 0xe3, 0x6c + }, + .ucmp_data = { + 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x01, 0xff, 0xff, + 0xff, 0xf8, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, + 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xdb + }, + .ucmp_len = 194, .verify = 1 + }, + { .crbb_len = 40, .cc = 1, + .crbb_data = { + 0x53, 0x06, 0xc5, 0x40, 0x6d + }, + .ucmp_data = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x03 + }, + .ucmp_len = 182, .verify = 1 + }, + { .crbb_len = 8, .cc = 1, + .crbb_data = {0x02}, + .ucmp_data = {0xff, 0xff, 0xff, 0xf8}, + .ucmp_len = 29, .verify = 1 + }, + { .crbb_len = 103, .cc = 1, + .crbb_data = { + 0x02, 0x0c, 0xe0, 0x41, 0xa0, 0x0c, 0x36, 0x0d, 0x03, + 0x71, 0xb0, 0x6e, 0x24 + }, + .ucmp_data = { + 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xf8, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, + 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff + }, + .ucmp_len = 288, .verify = 1 + }, + /* Test vector from libosmocore test */ + { .crbb_len = 35, .cc = 0, + .crbb_data = {0xde, 0x88, 0x75, 0x65, 0x80}, + .ucmp_data = {0x37, 0x47, 0x81, 0xf0}, + .ucmp_len = 28, .verify = 1 + }, + { .crbb_len = 18, .cc = 1, + .crbb_data = {0xdd, 0x41, 0x00}, + .ucmp_data = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00 + }, + .ucmp_len = 90, .verify = 1 + }, + /*Invalid inputs*/ + { .crbb_len = 18, .cc = 1, + .crbb_data = {0x1E, 0x70, 0xc0}, + .ucmp_data = {0x0}, + .ucmp_len = 0, .verify = 0 + }, + { .crbb_len = 14, .cc = 1, + .crbb_data = {0x00, 0x1E, 0x7c}, + .ucmp_data = {0x0}, + .ucmp_len = 0, .verify = 0 + }, + { .crbb_len = 24, .cc = 0, + .crbb_data = {0x00, 0x00, 0x00}, + .ucmp_data = {0x0}, + .ucmp_len = 0, .verify = 0 + } + }; + +static const struct log_info_cat default_categories[] = { + {"DCSN1", "\033[1;31m", "Concrete Syntax Notation One (CSN1)", LOGL_INFO, 0}, + {"DL1IF", "\033[1;32m", "GPRS PCU L1 interface (L1IF)", LOGL_DEBUG, 1}, + {"DRLCMAC", "\033[0;33m", "GPRS RLC/MAC layer (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACDATA", "\033[0;33m", "GPRS RLC/MAC layer Data (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACDL", "\033[1;33m", "GPRS RLC/MAC layer Downlink (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACUL", "\033[1;36m", "GPRS RLC/MAC layer Uplink (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACSCHED", "\033[0;36m", "GPRS RLC/MAC layer Scheduling (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACMEAS", "\033[1;31m", "GPRS RLC/MAC layer Measurements (RLCMAC)", LOGL_INFO, 1}, + {"DNS", "\033[1;34m", "GPRS Network Service Protocol (NS)", LOGL_INFO, 1}, + {"DBSSGP", "\033[1;34m", "GPRS BSS Gateway Protocol (BSSGP)", LOGL_INFO, 1}, + {"DPCU", "\033[1;35m", "GPRS Packet Control Unit (PCU)", LOGL_NOTICE, 1}, +}; + +static int filter_fn(const struct log_context *ctx, + struct log_target *tar) +{ + return 1; +} + +/* To verify the result with expected result */ +int check_result(bitvec bits, uint8_t *exp_data, int exp_len) +{ + if (bits.cur_bit != exp_len) + return 0; + size_t n = (exp_len / 8); + int rem = (exp_len % 8); + + if (memcmp(exp_data, bits.data, n) == 0) { + if (rem == 0) + return 1; + if ((bits.data[n] & MASK(rem)) == ((*(exp_data + n)) & MASK(rem))) + return 1; + else + return 0; + } else + return 0; +} + +/* To test decoding of compressed bitmap by Tree based method + * and to verify the result with expected result + * for invalid input verfication is suppressed + */ +static void test_EPDAN_decode_tree(void) +{ + bitvec dest; + int init_flag = 1; + int itr; + int rc; + uint8_t bits_data[RLC_EGPRS_MAX_WS/8]; + + printf("=== start %s ===\n", __func__); + + for (itr = 0 ; itr < (sizeof(test) / sizeof(test_data)) ; itr++) { + dest.data = bits_data; + dest.data_len = sizeof(bits_data); + dest.cur_bit = 0; + memset(dest.data, 0, sizeof(bits_data)); + LOGP(DRLCMACDL, LOGL_DEBUG, "\nTest:%d\nTree based decoding:" + "\nuncompressed data = %s\nlen = %d\n", itr + 1, + osmo_hexdump(test[itr].crbb_data, + (test[itr].crbb_len + 7)/8), test[itr].crbb_len + ); + rc = decompress_crbb(test[itr].crbb_len, test[itr].cc, + test[itr].crbb_data, &dest + ); + if (rc < 0) { + LOGP(DRLCMACUL, LOGL_NOTICE, + "\nFailed to decode CRBB: length %d, data %s", + test[itr].crbb_len, osmo_hexdump( + test[itr].crbb_data, (test[itr].crbb_len + 7)/8)); + } + if (init_flag) + init_flag = 0; + if (test[itr].verify) { + if (check_result(dest, test[itr].ucmp_data, + test[itr].ucmp_len) == 0) { + LOGP(DRLCMACDL, LOGL_DEBUG, "\nTree based decoding" + ":Error\nexpected data = %s\nexpected" + " len = %d\ndecoded data = %s\n" + "decoded len = %d\n", + osmo_hexdump(test[itr].ucmp_data, + (test[itr].ucmp_len + 7)/8), + test[itr].ucmp_len, osmo_hexdump(dest.data, + (dest.cur_bit + 7)/8), dest.cur_bit + ); + OSMO_ASSERT(0); + } + } + LOGP(DRLCMACDL, LOGL_DEBUG, "\nexpected data = %s\nexpected len = %d" + "\ndecoded data = %s\ndecoded len = %d\n", + osmo_hexdump(test[itr].ucmp_data, + (test[itr].ucmp_len + 7)/8), + test[itr].ucmp_len, osmo_hexdump(dest.data, + (dest.cur_bit + 7)/8), dest.cur_bit + ); + } + + printf("=== end %s ===\n", __func__); +} + +const struct log_info debug_log_info = { + filter_fn, + (struct log_info_cat *)default_categories, + ARRAY_SIZE(default_categories), +}; + +int main(int argc, char **argv) +{ + struct vty_app_info pcu_vty_info = {0}; + + osmo_init_logging(&debug_log_info); + log_set_use_color(osmo_stderr_target, 0); + log_set_print_filename(osmo_stderr_target, 0); + bssgp_set_log_ss(DBSSGP); + + vty_init(&pcu_vty_info); + pcu_vty_init(&debug_log_info); + + tall_pcu_ctx = talloc_named_const(NULL, 1, "moiji-mobile TbfTest context"); + if (!tall_pcu_ctx) + abort(); + test_EPDAN_decode_tree(); + if (getenv("TALLOC_REPORT_FULL")) + talloc_report_full(tall_pcu_ctx, stderr); + talloc_free(tall_pcu_ctx); + return EXIT_SUCCESS; +} + +/* + * stubs that should not be reached + */ +extern "C" { +void l1if_pdch_req() { abort(); } +void l1if_connect_pdch() { abort(); } +void l1if_close_pdch() { abort(); } +void l1if_open_pdch() { abort(); } +} diff --git a/tests/bitcomp/BitcompTest.err b/tests/bitcomp/BitcompTest.err new file mode 100644 index 0000000..a9078d0 --- /dev/null +++ b/tests/bitcomp/BitcompTest.err @@ -0,0 +1,92 @@ + +Test:1 +Tree based decoding: +uncompressed data = 02 0c a0 30 cb 1a 0c e3 6c +len = 67 + +expected data = ff ff ff f8 00 00 01 ff ff ff f8 00 00 00 ff ff ff fe 00 00 3f ff ff ff db +expected len = 194 +decoded data = ff ff ff f8 00 00 01 ff ff ff f8 00 00 00 ff ff ff fe 00 00 3f ff ff ff db +decoded len = 194 + +Test:2 +Tree based decoding: +uncompressed data = 53 06 c5 40 6d +len = 40 + +expected data = ff ff ff ff ff ff c0 00 00 00 00 3f ff ff ff ff ff f8 00 00 00 00 03 +expected len = 182 +decoded data = ff ff ff ff ff ff c0 00 00 00 00 3f ff ff ff ff ff f8 00 00 00 00 03 +decoded len = 182 + +Test:3 +Tree based decoding: +uncompressed data = 02 +len = 8 + +expected data = ff ff ff f8 +expected len = 29 +decoded data = ff ff ff f8 +decoded len = 29 + +Test:4 +Tree based decoding: +uncompressed data = 02 0c e0 41 a0 0c 36 0d 03 71 b0 6e 24 +len = 103 + +expected data = ff ff ff f8 00 00 ff ff ff f8 00 00 7f ff ff fe 00 00 0f ff ff ff e0 00 00 7f ff ff ff 80 00 01 ff ff ff ff +expected len = 288 +decoded data = ff ff ff f8 00 00 ff ff ff f8 00 00 7f ff ff fe 00 00 0f ff ff ff e0 00 00 7f ff ff ff 80 00 01 ff ff ff ff +decoded len = 288 + +Test:5 +Tree based decoding: +uncompressed data = de 88 75 65 80 +len = 35 + +expected data = 37 47 81 f0 +expected len = 28 +decoded data = 37 47 81 f0 +decoded len = 28 + +Test:6 +Tree based decoding: +uncompressed data = dd 41 00 +len = 18 + +expected data = ff ff ff ff ff ff ff ff ff ff 00 00 +expected len = 90 +decoded data = ff ff ff ff ff ff ff ff ff ff 00 00 +decoded len = 90 + +Test:7 +Tree based decoding: +uncompressed data = 1e 70 c0 +len = 18 + +expected data = +expected len = 0 +decoded data = +decoded len = 19 + +Test:8 +Tree based decoding: +uncompressed data = 00 1e +len = 14 + +Failed to decode CRBB: length 14, data 00 1e +expected data = +expected len = 0 +decoded data = +decoded len = 0 + +Test:9 +Tree based decoding: +uncompressed data = 00 00 00 +len = 24 + +Failed to decode CRBB: length 24, data 00 00 00 +expected data = +expected len = 0 +decoded data = +decoded len = 0 diff --git a/tests/bitcomp/BitcompTest.ok b/tests/bitcomp/BitcompTest.ok new file mode 100644 index 0000000..f7720fc --- /dev/null +++ b/tests/bitcomp/BitcompTest.ok @@ -0,0 +1,2 @@ +=== start test_EPDAN_decode_tree === +=== end test_EPDAN_decode_tree === diff --git a/tests/testsuite.at b/tests/testsuite.at index 1049b31..3ab39cc 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -23,6 +23,14 @@ AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/tbf/TbfTest], [0], [expout], [experr]) AT_CLEANUP + +AT_SETUP([bitcomp]) +AT_KEYWORDS([bitcomp]) +cat $abs_srcdir/bitcomp/BitcompTest.ok > expout +cat $abs_srcdir/bitcomp/BitcompTest.err > experr +AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/bitcomp/BitcompTest], [0], [expout], [experr]) +AT_CLEANUP + AT_SETUP([edge]) AT_KEYWORDS([edge]) cat $abs_srcdir/edge/EdgeTest.ok > expout -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 18 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: pravin From gerrit-no-reply at lists.osmocom.org Thu Aug 18 10:13:38 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 18 Aug 2016 10:13:38 +0000 Subject: openbsc[master]: Adding compression control In-Reply-To: References: Message-ID: Patch Set 17: (23 comments) https://gerrit.osmocom.org/#/c/642/17//COMMIT_MSG Commit Message: Line 9: In this commit two modules were added: up for opinions, but it's usually shortest to write the imperative present tense form, which I personally like very much for its crisp brevity: "Add compression control" and "Add two modules:" and "gprs_sndcp_comp.h/c: Handle creation and destruction..." Line 12: destruction of conpression entites. It handles the allocation conpression :) Line 21: It works, but is not yet ready for merging. Both files depend writing this in a commit log that is up for review doesn't really make sense -- or rather, once the patch is ready for merging, this sentence must definitely go away. https://gerrit.osmocom.org/#/c/642/17/openbsc/include/openbsc/gprs_sndcp_comp.h File openbsc/include/openbsc/gprs_sndcp_comp.h: Line 3: /* (C) 2016 by Sysmocom s.f.m.c. GmbH I think it would be good to add . See gprs/gtphub.h. So far we have 'sysmocom' in lower case only. Not sure if it matters, but can't hurt to keep it so. Line 24: #define _GPRS_SNDCP_COMP_H Older files use this way, yes, but in newer files we now tend to use #pragma once instead. This allows dropping all of #ifndef, #define and #endif for one short line. See for example gprs/gtphub.h. Line 60: llist_head rather not break an argument over multiple lines. Remove an indent if necessary. (same below) https://gerrit.osmocom.org/#/c/642/17/openbsc/include/openbsc/gprs_sndcp_pcomp.h File openbsc/include/openbsc/gprs_sndcp_pcomp.h: Line 3: /* (C) 2016 by Sysmocom s.f.m.c. GmbH "sysmocom" (?) and email addr Line 24: #define _GPRS_SNDCP_pcomp_H #pragma once https://gerrit.osmocom.org/#/c/642/17/openbsc/include/openbsc/sgsn.h File openbsc/include/openbsc/sgsn.h: Line 95: } pcomp_rfc1144; curious, any reason to not add this at the end of the struct? https://gerrit.osmocom.org/#/c/642/17/openbsc/src/gprs/gprs_sndcp_comp.c File openbsc/src/gprs/gprs_sndcp_comp.c: Line 40: *ctx, const struct (line breaks) Line 59: comp_entity->nsapi_len * sizeof(int)); sizeof(struct member) Line 83: OSMO_ASSERT(NULL); OSMO_ASSERT(0); Line 114: "Header compression entity (%i) creation failed!\n", we usually use %d, not %i (same below) Line 173: if (comp_entity_to_delete) { exit early and save indent space: if (!comp_entity_to_delete) return; Line 190: remove extra blank line before '}' (more like this below) Line 196: llist_head (line breaks, more below) Line 213: if (comp_entity) { if (!comp_entity) return NULL; Line 249: OSMO_ASSERT(comp_entities); does any code path ever even handle a NULL comp_entities? It gives a warm fuzzy feeling to assert on this, but usually this is not necessary... https://gerrit.osmocom.org/#/c/642/17/openbsc/src/gprs/gprs_sndcp_pcomp.c File openbsc/src/gprs/gprs_sndcp_pcomp.c: Line 118: /* Note: This function is automatically called from apparently we want the comment style like /* * text * more text */ Line 135: OSMO_ASSERT(false); you're not including ... OSMO_ASSERT(0) again? Line 167: uint8_t *comp_ptr; /* Not used */ then why have it? Line 174: compr_len = slhc_compress(comp, data_i, len, data_o, &comp_ptr, 0); it is used here? Line 219: drop blank line? -- To view, visit https://gerrit.osmocom.org/642 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 Gerrit-PatchSet: 17 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 18 10:28:23 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 18 Aug 2016 10:28:23 +0000 Subject: openbsc[master]: SLHC (RFC1144 header compression) integration and unit-test In-Reply-To: References: Message-ID: Patch Set 11: (1 comment) https://gerrit.osmocom.org/#/c/635/11/openbsc/tests/slhc/slhc_test.c File openbsc/tests/slhc/slhc_test.c: Line 208: fd = fopen("packets.txt", "r"); the test fails because upon 'make check', the test is run from a different directory and the packets.txt is not found. -- To view, visit https://gerrit.osmocom.org/635 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 Gerrit-PatchSet: 11 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 18 10:29:54 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 18 Aug 2016 10:29:54 +0000 Subject: osmo-iuh[master]: doc: add example osmo-hnbgw.cfg In-Reply-To: References: Message-ID: Patch Set 1: > this wouldn't survive a 'make dist' as it's not in Makefile.am it was late ... thx -- To view, visit https://gerrit.osmocom.org/712 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I424ccdea02578edc7816e4d23a9ea7c5729315d8 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 18 10:32:50 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 18 Aug 2016 10:32:50 +0000 Subject: osmo-iuh[master]: doc: add example osmo-hnbgw.cfg In-Reply-To: References: Message-ID: Patch Set 1: > this wouldn't survive a 'make dist' as it's not in Makefile.am So ... it appears jenkins doesn't check 'make dist'? Ah, jenkins.sh: "# distcheck is broken" (It's not the only thing broken in osmo-iuh ATM) -- To view, visit https://gerrit.osmocom.org/712 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I424ccdea02578edc7816e4d23a9ea7c5729315d8 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 18 10:55:04 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 18 Aug 2016 10:55:04 +0000 Subject: [PATCH] sandbox[master]: t1 Message-ID: Review at https://gerrit.osmocom.org/714 t1 Change-Id: I48835575eebb08cf44e4605b15bfe3da74ef8d5e --- M x 1 file changed, 1 insertion(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/sandbox refs/changes/14/714/1 diff --git a/x b/x index 59d2b02..251132d 100644 --- a/x +++ b/x @@ -26,3 +26,4 @@ 1 3 x +more -- To view, visit https://gerrit.osmocom.org/714 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I48835575eebb08cf44e4605b15bfe3da74ef8d5e Gerrit-PatchSet: 1 Gerrit-Project: sandbox Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Thu Aug 18 10:55:04 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 18 Aug 2016 10:55:04 +0000 Subject: [PATCH] sandbox[master]: t2 Message-ID: Review at https://gerrit.osmocom.org/715 t2 Change-Id: If9f04d74af8b847810789d17c4cb89771f5547ff --- M x 1 file changed, 1 insertion(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/sandbox refs/changes/15/715/1 diff --git a/x b/x index 251132d..5fc2574 100644 --- a/x +++ b/x @@ -27,3 +27,4 @@ 3 x more +yet more -- To view, visit https://gerrit.osmocom.org/715 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: If9f04d74af8b847810789d17c4cb89771f5547ff Gerrit-PatchSet: 1 Gerrit-Project: sandbox Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Thu Aug 18 10:55:04 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 18 Aug 2016 10:55:04 +0000 Subject: [PATCH] sandbox[master]: t3 Message-ID: Review at https://gerrit.osmocom.org/716 t3 Change-Id: I15ec904c178942d181baca5a3ee2604a954a9e65 --- M x 1 file changed, 1 insertion(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/sandbox refs/changes/16/716/1 diff --git a/x b/x index 5fc2574..6260bff 100644 --- a/x +++ b/x @@ -28,3 +28,4 @@ x more yet more +yet more and more -- To view, visit https://gerrit.osmocom.org/716 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I15ec904c178942d181baca5a3ee2604a954a9e65 Gerrit-PatchSet: 1 Gerrit-Project: sandbox Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Thu Aug 18 10:55:50 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 18 Aug 2016 10:55:50 +0000 Subject: sandbox[master]: t1 In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 Verified+1 -- To view, visit https://gerrit.osmocom.org/714 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I48835575eebb08cf44e4605b15bfe3da74ef8d5e Gerrit-PatchSet: 1 Gerrit-Project: sandbox Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 18 10:55:59 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 18 Aug 2016 10:55:59 +0000 Subject: sandbox[master]: t2 In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 Verified+1 -- To view, visit https://gerrit.osmocom.org/715 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: If9f04d74af8b847810789d17c4cb89771f5547ff Gerrit-PatchSet: 1 Gerrit-Project: sandbox Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 18 10:58:32 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 18 Aug 2016 10:58:32 +0000 Subject: sandbox[master]: t3 In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 Verified+1 -- To view, visit https://gerrit.osmocom.org/716 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I15ec904c178942d181baca5a3ee2604a954a9e65 Gerrit-PatchSet: 1 Gerrit-Project: sandbox Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 18 10:58:34 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 18 Aug 2016 10:58:34 +0000 Subject: [MERGED] sandbox[master]: t3 In-Reply-To: References: Message-ID: Neels Hofmeyr has submitted this change and it was merged. Change subject: t3 ...................................................................... t3 Change-Id: I15ec904c178942d181baca5a3ee2604a954a9e65 --- M x 1 file changed, 1 insertion(+), 0 deletions(-) Approvals: Neels Hofmeyr: Looks good to me, approved; Verified diff --git a/x b/x index 5fc2574..6260bff 100644 --- a/x +++ b/x @@ -28,3 +28,4 @@ x more yet more +yet more and more -- To view, visit https://gerrit.osmocom.org/716 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I15ec904c178942d181baca5a3ee2604a954a9e65 Gerrit-PatchSet: 1 Gerrit-Project: sandbox Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Thu Aug 18 10:58:34 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 18 Aug 2016 10:58:34 +0000 Subject: [MERGED] sandbox[master]: t2 In-Reply-To: References: Message-ID: Neels Hofmeyr has submitted this change and it was merged. Change subject: t2 ...................................................................... t2 Change-Id: If9f04d74af8b847810789d17c4cb89771f5547ff --- M x 1 file changed, 1 insertion(+), 0 deletions(-) Approvals: Neels Hofmeyr: Looks good to me, approved; Verified diff --git a/x b/x index 251132d..5fc2574 100644 --- a/x +++ b/x @@ -27,3 +27,4 @@ 3 x more +yet more -- To view, visit https://gerrit.osmocom.org/715 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: If9f04d74af8b847810789d17c4cb89771f5547ff Gerrit-PatchSet: 1 Gerrit-Project: sandbox Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Thu Aug 18 10:58:34 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 18 Aug 2016 10:58:34 +0000 Subject: [MERGED] sandbox[master]: t1 In-Reply-To: References: Message-ID: Neels Hofmeyr has submitted this change and it was merged. Change subject: t1 ...................................................................... t1 Change-Id: I48835575eebb08cf44e4605b15bfe3da74ef8d5e --- M x 1 file changed, 1 insertion(+), 0 deletions(-) Approvals: Neels Hofmeyr: Looks good to me, approved; Verified diff --git a/x b/x index 59d2b02..251132d 100644 --- a/x +++ b/x @@ -26,3 +26,4 @@ 1 3 x +more -- To view, visit https://gerrit.osmocom.org/714 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I48835575eebb08cf44e4605b15bfe3da74ef8d5e Gerrit-PatchSet: 1 Gerrit-Project: sandbox Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Thu Aug 18 10:59:38 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 18 Aug 2016 10:59:38 +0000 Subject: [PATCH] sandbox[master]: t1 Message-ID: Review at https://gerrit.osmocom.org/717 t1 Change-Id: I21de28ca57e9150524f45aea997186b2fce43c15 --- M x 1 file changed, 1 insertion(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/sandbox refs/changes/17/717/1 diff --git a/x b/x index 6260bff..2ec4a40 100644 --- a/x +++ b/x @@ -29,3 +29,4 @@ more yet more yet more and more +xx -- To view, visit https://gerrit.osmocom.org/717 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I21de28ca57e9150524f45aea997186b2fce43c15 Gerrit-PatchSet: 1 Gerrit-Project: sandbox Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Thu Aug 18 10:59:38 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 18 Aug 2016 10:59:38 +0000 Subject: [PATCH] sandbox[master]: t2 Message-ID: Review at https://gerrit.osmocom.org/718 t2 Change-Id: I1906b498ff1cd1438399bfbb516c2d766075ddcc --- M x 1 file changed, 1 insertion(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/sandbox refs/changes/18/718/1 diff --git a/x b/x index 2ec4a40..c817c1c 100644 --- a/x +++ b/x @@ -30,3 +30,4 @@ yet more yet more and more xx +yy -- To view, visit https://gerrit.osmocom.org/718 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I1906b498ff1cd1438399bfbb516c2d766075ddcc Gerrit-PatchSet: 1 Gerrit-Project: sandbox Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Thu Aug 18 10:59:39 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 18 Aug 2016 10:59:39 +0000 Subject: [PATCH] sandbox[master]: t3 Message-ID: Review at https://gerrit.osmocom.org/719 t3 Change-Id: I0928e9cd687ef30ee5ba0e0a35d2a7d584750e52 --- M x 1 file changed, 1 insertion(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/sandbox refs/changes/19/719/1 diff --git a/x b/x index c817c1c..5c8ecd5 100644 --- a/x +++ b/x @@ -31,3 +31,4 @@ yet more and more xx yy +zz -- To view, visit https://gerrit.osmocom.org/719 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I0928e9cd687ef30ee5ba0e0a35d2a7d584750e52 Gerrit-PatchSet: 1 Gerrit-Project: sandbox Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Thu Aug 18 11:00:09 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 18 Aug 2016 11:00:09 +0000 Subject: sandbox[master]: t1 In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 Verified+1 -- To view, visit https://gerrit.osmocom.org/717 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I21de28ca57e9150524f45aea997186b2fce43c15 Gerrit-PatchSet: 1 Gerrit-Project: sandbox Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 18 11:00:16 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 18 Aug 2016 11:00:16 +0000 Subject: sandbox[master]: t2 In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 Verified+1 -- To view, visit https://gerrit.osmocom.org/718 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I1906b498ff1cd1438399bfbb516c2d766075ddcc Gerrit-PatchSet: 1 Gerrit-Project: sandbox Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 18 14:29:50 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 18 Aug 2016 14:29:50 +0000 Subject: [PATCH] osmo-iuh[master]: add to dist: doc subdir with all current doc files Message-ID: Review at https://gerrit.osmocom.org/720 add to dist: doc subdir with all current doc files Change-Id: Idfef4f050e21a5d0eae3a530fe319a5adf81534d --- M Makefile.am M configure.ac A doc/Makefile.am 3 files changed, 12 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/20/720/1 diff --git a/Makefile.am b/Makefile.am index c2167d4..ab8191e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ AUTOMAKE_OPTIONS = foreign dist-bzip2 -SUBDIRS = src include +SUBDIRS = src include doc pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libosmo-ranap.pc diff --git a/configure.ac b/configure.ac index 38e3b4c..2ca32b1 100644 --- a/configure.ac +++ b/configure.ac @@ -42,4 +42,5 @@ include/osmocom/ranap/Makefile include/osmocom/rua/Makefile include/osmocom/iuh/Makefile + doc/Makefile ) diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..6974e89 --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,10 @@ +EXTRA_DIST = \ + hnb_cs_lu.msc \ + hnb_cs_mo_call.msc \ + hnb_cs_mo_sms.msc \ + hnb_cs_mt_call.msc \ + hnb_cs_mt_sms.msc \ + hnb_ps_lu.msc \ + hnb_ps_pdp_act.msc \ + protocols_around_hnbgw.txt \ + README -- To view, visit https://gerrit.osmocom.org/720 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Idfef4f050e21a5d0eae3a530fe319a5adf81534d Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Thu Aug 18 14:29:50 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 18 Aug 2016 14:29:50 +0000 Subject: [PATCH] osmo-iuh[master]: add doc/examples, Makefile.am adds all *.cfg files generically Message-ID: Review at https://gerrit.osmocom.org/721 add doc/examples, Makefile.am adds all *.cfg files generically doc/examples/Makefile.am taken from openbsc/openbsc/doc/examples. Change-Id: I1fadad4deb7f73d2b3aa753a84a76ba5b9bf9574 --- M configure.ac M doc/Makefile.am A doc/examples/Makefile.am 3 files changed, 26 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/21/721/1 diff --git a/configure.ac b/configure.ac index 2ca32b1..c3a65d6 100644 --- a/configure.ac +++ b/configure.ac @@ -43,4 +43,5 @@ include/osmocom/rua/Makefile include/osmocom/iuh/Makefile doc/Makefile + doc/examples/Makefile ) diff --git a/doc/Makefile.am b/doc/Makefile.am index 6974e89..81a25e2 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1,3 +1,5 @@ +SUBDIRS = examples + EXTRA_DIST = \ hnb_cs_lu.msc \ hnb_cs_mo_call.msc \ diff --git a/doc/examples/Makefile.am b/doc/examples/Makefile.am new file mode 100644 index 0000000..8f14fdc --- /dev/null +++ b/doc/examples/Makefile.am @@ -0,0 +1,23 @@ + +CFG_FILES = find $(srcdir) -name '*.cfg*' | sed -e 's,^$(srcdir),,' + +dist-hook: + for f in $$($(CFG_FILES)); do \ + j="$(distdir)/$$f" && \ + mkdir -p "$$(dirname $$j)" && \ + $(INSTALL_DATA) $(srcdir)/$$f $$j; \ + done + +install-data-hook: + for f in $$($(CFG_FILES)); do \ + j="$(DESTDIR)$(docdir)/examples/$$f" && \ + mkdir -p "$$(dirname $$j)" && \ + $(INSTALL_DATA) $(srcdir)/$$f $$j; \ + done + +uninstall-hook: + @$(PRE_UNINSTALL) + for f in $$($(CFG_FILES)); do \ + j="$(DESTDIR)$(docdir)/examples/$$f" && \ + $(RM) $$j; \ + done -- To view, visit https://gerrit.osmocom.org/721 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I1fadad4deb7f73d2b3aa753a84a76ba5b9bf9574 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Thu Aug 18 17:13:13 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Thu, 18 Aug 2016 17:13:13 +0000 Subject: [PATCH] openbsc[master]: Adding SNDCP-XID encoder / decoder and unit test In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/641 to look at the new patch set (#12). Adding SNDCP-XID encoder / decoder and unit test The SNDCP-XID (or layer-3 xid) is used to exchange layer-3 parameters such as compression. The encoder encodes a bytestream that is then sent as regular XID field from LLC. We will need the SNDCP-XID to negotiate the parameters for our upcomming GPRS data and header compression features Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e --- M openbsc/.gitignore M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_sndcp_xid.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_sndcp_xid.c M openbsc/tests/Makefile.am M openbsc/tests/sgsn/Makefile.am A openbsc/tests/sndcp_xid/Makefile.am A openbsc/tests/sndcp_xid/sndcp_xid_test.c A openbsc/tests/sndcp_xid/sndcp_xid_test.ok M openbsc/tests/testsuite.at 12 files changed, 2,418 insertions(+), 5 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/41/641/12 diff --git a/openbsc/.gitignore b/openbsc/.gitignore index 518a960..8ce3b70 100644 --- a/openbsc/.gitignore +++ b/openbsc/.gitignore @@ -82,6 +82,7 @@ tests/gtphub/gtphub_test tests/mm_auth/mm_auth_test tests/xid/xid_test +tests/sndcp_xid/sndcp_xid_test tests/atconfig tests/atlocal diff --git a/openbsc/configure.ac b/openbsc/configure.ac index fbf2930..53072bd 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -230,6 +230,7 @@ tests/gtphub/Makefile tests/mm_auth/Makefile tests/xid/Makefile + tests/sndcp_xid/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index ce5f768..e200b05 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,7 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_llc_xid.h gprs_sndcp.h + gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_sndcp_xid.h b/openbsc/include/openbsc/gprs_sndcp_xid.h new file mode 100644 index 0000000..8062119 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_xid.h @@ -0,0 +1,216 @@ +/* GPRS SNDCP XID field encoding/decoding as per 3GPP TS 44.065 */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include + +#define CURRENT_SNDCP_VERSION 0 /* See 3GPP TS 44.065, clause 8 */ +#define MAX_ENTITIES 32 /* 3GPP TS 44.065 reserves 5 bit + * for compression enitity number */ +#define MAX_COMP 16 /* Maximum number of possible pcomp/dcomp values */ +#define MAX_NSAPI 11 /* Maximum number usable NSAPIs */ +#define MAX_ROHC 16 /* Maximum number of ROHC compression profiles */ + +/* According to: 3GPP TS 44.065, 6.5.1.1 Format of the protocol control + * information compression field (Figure 7) + * 3GPP TS 44.065, 6.6.1.1 Format of the data compression + * field (Figure 9) */ +struct gprs_sndcp_comp_field { + struct llist_head list; + + /* Propose bit (P), see also: 6.5.1.1.2 and 6.6.1.1.2 */ + unsigned int p; + + /* Entity number, see also: 6.5.1.1.3 and 6.6.1.1.3 */ + unsigned int entity; + + /* Algorithm identifier, see also: 6.5.1.1.4 and 6.6.1.1.4 */ + int algo; + + /* Number of contained PCOMP / DCOMP values */ + uint8_t comp_len; + + /* PCOMP / DCOMP values, see also: 6.5.1.1.5 and 6.6.1.1.5 */ + uint8_t comp[MAX_COMP]; + + /* Note: Only one of the following struct pointers may, + be used unused pointers must be set to NULL! */ + struct gprs_sndcp_pcomp_rfc1144_params *rfc1144_params; + struct gprs_sndcp_pcomp_rfc2507_params *rfc2507_params; + struct gprs_sndcp_pcomp_rohc_params *rohc_params; + struct gprs_sndcp_dcomp_v42bis_params *v42bis_params; + struct gprs_sndcp_dcomp_v44_params *v44_params; +}; + +/* According to: 3GPP TS 44.065, 6.5.1.1.4 Algorithm identifier */ +enum gprs_sndcp_hdr_comp_algo { + RFC_1144, /* TCP/IP header compression, see also 6.5.2 */ + RFC_2507, /* TCP/UDP/IP header compression, see also: 6.5.3 */ + ROHC /* Robust Header Compression, see also 6.5.4 */ +}; + +/* According to: 3GPP TS 44.065, 6.5.1.1.4 Algorithm identifier */ +enum gprs_sndcp_data_comp_algo { + V42BIS, /* V.42bis data compression, see also 6.6.2 */ + V44 /* V44 data compression, see also: 6.6.3 */ +}; + +/* According to: 3GPP TS 44.065, 8 SNDCP XID parameters */ +enum gprs_sndcp_xid_param_types { + SNDCP_XID_VERSION_NUMBER, + SNDCP_XID_DATA_COMPRESSION, /* See also: subclause 6.6.1 */ + SNDCP_XID_PROTOCOL_COMPRESSION, /* See also: subclause 6.5.1 */ +}; + +/* According to: 3GPP TS 44.065, 6.5.2.1 Parameters (Table 5) */ +struct gprs_sndcp_pcomp_rfc1144_params { + uint8_t nsapi_len; /* Number of applicable NSAPIs + * (default 0) */ + uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */ + int s01; /* (default 15) */ +}; + +/* According to: 3GPP TS 44.065, 6.5.2.2 Assignment of PCOMP values */ +enum gprs_sndcp_pcomp_rfc1144_pcomp { + RFC1144_PCOMP1, /* Uncompressed TCP */ + RFC1144_PCOMP2, /* Compressed TCP */ + RFC1144_PCOMP_NUM /* Number of pcomp values */ +}; + +/* According to: 3GPP TS 44.065, 6.5.3.1 Parameters (Table 6) */ +struct gprs_sndcp_pcomp_rfc2507_params { + uint8_t nsapi_len; /* Number of applicable NSAPIs + * (default 0) */ + uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */ + int f_max_period; /* (default 256) */ + int f_max_time; /* (default 5) */ + int max_header; /* (default 168) */ + int tcp_space; /* (default 15) */ + int non_tcp_space; /* (default 15) */ +}; + +/* According to: 3GPP TS 44.065, 6.5.3.2 Assignment of PCOMP values for RFC2507 */ +enum gprs_sndcp_pcomp_rfc2507_pcomp { + RFC2507_PCOMP1, /* Full Header */ + RFC2507_PCOMP2, /* Compressed TCP */ + RFC2507_PCOMP3, /* Compressed TCP non delta */ + RFC2507_PCOMP4, /* Compressed non TCP */ + RFC2507_PCOMP5, /* Context state */ + RFC2507_PCOMP_NUM /* Number of pcomp values */ +}; + +/* According to: 3GPP TS 44.065, 6.5.4.1 Parameter (Table 10) */ +struct gprs_sndcp_pcomp_rohc_params { + uint8_t nsapi_len; /* Number of applicable NSAPIs + * (default 0) */ + uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */ + int max_cid; /* (default 15) */ + int max_header; /* (default 168) */ + uint8_t profile_len; /* (default 1) */ + uint16_t profile[MAX_ROHC]; /* (default 0, ROHC uncompressed) */ +}; + +/* According to: 3GPP TS 44.065, 6.5.4.2 Assignment of PCOMP values for ROHC */ +enum gprs_sndcp_pcomp_rohc_pcomp { + ROHC_PCOMP1, /* ROHC small CIDs */ + ROHC_PCOMP2, /* ROHC large CIDs */ + ROHC_PCOMP_NUM /* Number of pcomp values */ +}; + +/* ROHC compression profiles, see also: + http://www.iana.org/assignments/rohc-pro-ids/rohc-pro-ids.xhtml */ +enum gprs_sndcp_xid_rohc_profiles { + ROHC_UNCOMPRESSED = 0x0000, /* ROHC uncompressed [RFC5795] */ + ROHC_RTP = 0x0001, /* ROHC RTP [RFC3095] */ + ROHCV2_RTP = 0x0101, /* ROHCv2 RTP [RFC5225] */ + ROHC_UDP = 0x0002, /* ROHC UDP [RFC3095] */ + ROHCv2_UDP = 0x0102, /* ROHCv2 UDP [RFC5225] */ + ROHC_ESP = 0x0003, /* ROHC ESP [RFC3095] */ + ROHCV2_ESP = 0x0103, /* ROHCv2 ESP [RFC5225] */ + ROHC_IP = 0x0004, /* ROHC IP [RFC3843] */ + ROHCV2_IP = 0x0104, /* ROHCv2 IP [RFC5225] */ + ROHC_LLA = 0x0005, /* ROHC LLA [RFC4362] */ + ROHC_LLA_WITH_R_MODE = 0x0105, /* ROHC LLA with R-mode [RFC3408] */ + ROHC_TCP = 0x0006, /* ROHC TCP [RFC6846] */ + ROHC_RTP_UDP_LITE = 0x0007, /* ROHC RTP/UDP-Lite [RFC4019] */ + ROHCV2_RTP_UDP_LITE = 0x0107, /* ROHCv2 RTP/UDP-Lite [RFC5225] */ + ROHC_UDP_LITE = 0x0008, /* ROHC UDP-Lite [RFC4019] */ + ROHCV2_UDP_LITE = 0x0108, /* ROHCv2 UDP-Lite [RFC5225] */ +}; + +/* According to: 3GPP TS 44.065, 6.6.2.1 Parameters (Table 7a) */ +struct gprs_sndcp_dcomp_v42bis_params { + uint8_t nsapi_len; /* Number of applicable NSAPIs + * (default 0) */ + uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */ + int p0; /* (default 3) */ + int p1; /* (default 2048) */ + int p2; /* (default 20) */ + +}; + +/* According to: 3GPP TS 44.065, 6.6.2.2 Assignment of DCOMP values */ +enum gprs_sndcp_dcomp_v42bis_dcomp { + V42BIS_DCOMP1, /* V.42bis enabled */ + V42BIS_DCOMP_NUM /* Number of dcomp values */ +}; + +/* According to: 3GPP TS 44.065, 6.6.3.1 Parameters (Table 7c) */ +struct gprs_sndcp_dcomp_v44_params { + uint8_t nsapi_len; /* Number of applicable NSAPIs + * (default 0) */ + uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */ + int c0; /* (default 10000000) */ + int p0; /* (default 3) */ + int p1t; /* Refer to subclause 6.6.3.1.4 */ + int p1r; /* Refer to subclause 6.6.3.1.5 */ + int p3t; /* (default 3 x p1t) */ + int p3r; /* (default 3 x p1r) */ +}; + +/* According to: 3GPP TS 44.065, 6.6.3.2 Assignment of DCOMP values */ +enum gprs_sndcp_dcomp_v44_dcomp { + V44_DCOMP1, /* Packet method compressed */ + V44_DCOMP2, /* Multi packet method compressed */ + V44_DCOMP_NUM /* Number of dcomp values */ +}; + +/* Transform a list with compression fields into an SNDCP-XID message (dst) */ +int gprs_sndcp_compile_xid(uint8_t *dst, unsigned int dst_maxlen, + const struct llist_head *comp_fields); + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +struct llist_head *gprs_sndcp_parse_xid(const void *ctx, + const uint8_t * src, + unsigned int src_len, + const struct llist_head *comp_fields_req); + +/* Find out to which compression class the specified comp-field belongs + * (header compression or data compression?) */ +int gprs_sndcp_get_compression_class( + const struct gprs_sndcp_comp_field *comp_field); + +/* Dump a list with SNDCP-XID fields (Debug) */ +void gprs_sndcp_dump_comp_fields(const struct llist_head *comp_fields, + unsigned int logl); + diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 1b6de46..fa4a3dd 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -26,11 +26,11 @@ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ - oap.c oap_messages.c gprs_llc_xid.c + oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ - $(LIBCRYPTO_LIBS) -lrt + $(LIBCRYPTO_LIBS) -lrt -lm osmo_gtphub_SOURCES = gtphub_main.c gtphub.c gtphub_sock.c gtphub_ares.c \ gtphub_vty.c sgsn_ares.c gprs_utils.c diff --git a/openbsc/src/gprs/gprs_sndcp_xid.c b/openbsc/src/gprs/gprs_sndcp_xid.c new file mode 100644 index 0000000..c58b097 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_xid.c @@ -0,0 +1,1874 @@ +/* GPRS SNDCP XID field encoding/decoding as per 3GPP TS 44.065 */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* When the propose bit in an SNDCP-XID compression field is set to zero, + * the algorithm identifier is stripped. The algoritm parameters are specific + * for each algorithms. The following struct is used to pass the information + * about the referenced algorithm to the parser. */ +struct entity_algo_table { + unsigned int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + unsigned int algo; /* see also: 6.5.1.1.4 and 6.6.1.1.4 */ + unsigned int compclass; /* Can be either SNDCP_XID_DATA_COMPRESSION or + SNDCP_XID_PROTOCOL_COMPRESSION */ +}; + +/* FUNCTIONS RELATED TO SNDCP-XID ENCODING */ + +/* Encode applicable sapis (works the same in all three compression schemes) */ +static int encode_pcomp_applicable_sapis(uint8_t *dst, + const uint8_t *nsapis, + uint8_t nsapis_len) +{ + /* NOTE: Buffer *dst needs offer at 2 bytes + * of space to store the generation results */ + + uint16_t blob; + uint8_t nsapi; + int i; + + OSMO_ASSERT(dst); + OSMO_ASSERT(nsapis); + + /* Bail if number of possible nsapis exceeds valid range + * (Only 11 nsapis possible for PDP-Contexts) */ + OSMO_ASSERT(nsapis_len <= 11); + + /* Encode applicable SAPIs */ + blob = 0; + for (i = 0; i < nsapis_len; i++) { + nsapi = nsapis[i]; + /* Only NSAPI 5 to 15 are applicable for user traffic (PDP- + * contexts). Only for these NSAPIs SNDCP-XID parameters + * can apply. See also 3GPP TS 44.065, 5.1 Service primitives */ + OSMO_ASSERT(nsapi >= 5 && nsapi <= 15); + blob |= (1 << nsapi); + } + + /* Store result */ + *dst = (blob >> 8) & 0xFF; + dst++; + *dst = blob & 0xFF; + + return 2; +} + +/* Encode rfc1144 parameter field + * (see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */ +static int encode_pcomp_rfc1144_params(uint8_t *dst, unsigned int dst_maxlen, + const struct + gprs_sndcp_pcomp_rfc1144_params *params) +{ + /* NOTE: Buffer *dst should offer at least 3 bytes + * of space to store the generation results */ + + int dst_counter = 0; + int rc; + + OSMO_ASSERT(params); + OSMO_ASSERT(dst); + OSMO_ASSERT(dst_maxlen >= 3); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode s01 (see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */ + OSMO_ASSERT(params->s01 >= 0); + OSMO_ASSERT(params->s01 <= 255); + *dst = params->s01; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + +/* + * Encode rfc2507 parameter field + * (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) + */ +static int encode_pcomp_rfc2507_params(uint8_t *dst, unsigned int dst_maxlen, + const struct + gprs_sndcp_pcomp_rfc2507_params *params) +{ + /* NOTE: Buffer *dst should offer at least 3 bytes + * of space to store the generation results */ + + int dst_counter = 0; + int rc; + + OSMO_ASSERT(params); + OSMO_ASSERT(dst); + OSMO_ASSERT(dst_maxlen >= 9); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode F_MAX_PERIOD (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->f_max_period >= 1); + OSMO_ASSERT(params->f_max_period <= 65535); + *dst = (params->f_max_period >> 8) & 0xFF; + dst++; + dst_counter++; + *dst = (params->f_max_period) & 0xFF; + dst++; + dst_counter++; + + /* Encode F_MAX_TIME (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->f_max_time >= 1); + OSMO_ASSERT(params->f_max_time <= 255); + *dst = params->f_max_time; + dst++; + dst_counter++; + + /* Encode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->max_header >= 60); + OSMO_ASSERT(params->max_header <= 255); + *dst = params->max_header; + dst++; + dst_counter++; + + /* Encode TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->tcp_space >= 3); + OSMO_ASSERT(params->tcp_space <= 255); + *dst = params->tcp_space; + dst++; + dst_counter++; + + /* Encode NON_TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->non_tcp_space >= 3); + OSMO_ASSERT(params->non_tcp_space <= 65535); + *dst = (params->non_tcp_space >> 8) & 0xFF; + dst++; + dst_counter++; + *dst = (params->non_tcp_space) & 0xFF; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + +/* Encode ROHC parameter field + * (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ +static int encode_pcomp_rohc_params(uint8_t *dst, unsigned int dst_maxlen, + const struct gprs_sndcp_pcomp_rohc_params + *params) +{ + /* NOTE: Buffer *dst should offer at least 36 + * (2 * 16 Profiles + 2 * 3 Parameter) bytes + * of memory space to store generation results */ + + int i; + int dst_counter = 0; + int rc; + + OSMO_ASSERT(params); + OSMO_ASSERT(dst); + OSMO_ASSERT(dst_maxlen >= 38); + + /* Bail if number of ROHC profiles exceeds limit + * (ROHC supports only a maximum of 16 different profiles) */ + OSMO_ASSERT(params->profile_len >= 0); + OSMO_ASSERT(params->profile_len <= 16); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode MAX_CID (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + OSMO_ASSERT(params->max_cid >= 0); + OSMO_ASSERT(params->max_cid <= 16383); + *dst = (params->max_cid >> 8) & 0xFF; + dst++; + *dst = params->max_cid & 0xFF; + dst++; + dst_counter += 2; + + /* Encode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + OSMO_ASSERT(params->max_header >= 60); + OSMO_ASSERT(params->max_header <= 255); + *dst = (params->max_header >> 8) & 0xFF; + dst++; + *dst = params->max_header & 0xFF; + dst++; + dst_counter += 2; + + /* Encode ROHC Profiles (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + for (i = 0; i < params->profile_len; i++) { + *dst = (params->profile[i] >> 8) & 0xFF; + dst++; + *dst = params->profile[i] & 0xFF; + dst++; + dst_counter += 2; + } + + /* Return generated length */ + return dst_counter; +} + +/* Encode V.42bis parameter field + * (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ +static int encode_dcomp_v42bis_params(uint8_t *dst, unsigned int dst_maxlen, + const struct + gprs_sndcp_dcomp_v42bis_params *params) +{ + /* NOTE: Buffer *dst should offer at least 6 bytes + * of space to store the generation results */ + + int dst_counter = 0; + int rc; + + OSMO_ASSERT(params); + OSMO_ASSERT(dst); + OSMO_ASSERT(dst_maxlen >= 6); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode P0 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + OSMO_ASSERT(params->p0 >= 0); + OSMO_ASSERT(params->p0 <= 3); + *dst = params->p0 & 0x03; + dst++; + dst_counter++; + + /* Encode P1 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + OSMO_ASSERT(params->p1 >= 512); + OSMO_ASSERT(params->p1 <= 65535); + *dst = (params->p1 >> 8) & 0xFF; + dst++; + *dst = params->p1 & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P2 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + OSMO_ASSERT(params->p2 >= 6); + OSMO_ASSERT(params->p2 <= 250); + *dst = params->p2; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + +/* Encode V44 parameter field + * (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ +static int encode_dcomp_v44_params(uint8_t *dst, unsigned int dst_maxlen, + const struct gprs_sndcp_dcomp_v44_params + *params) +{ + /* NOTE: Buffer *dst should offer at least 12 bytes + * of space to store the generation results */ + + int dst_counter = 0; + int rc; + + OSMO_ASSERT(params); + OSMO_ASSERT(dst); + OSMO_ASSERT(dst_maxlen >= 12); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode C0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->c0 == 0x80 || params->c0 == 0xC0); + *dst = params->c0 & 0xC0; + dst++; + dst_counter++; + + /* Encode P0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p0 >= 0); + OSMO_ASSERT(params->p0 <= 3); + *dst = params->p0 & 0x03; + dst++; + dst_counter++; + + /* Encode P1T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p1t >= 256); + OSMO_ASSERT(params->p1t <= 65535); + *dst = (params->p1t >> 8) & 0xFF; + dst++; + *dst = params->p1t & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P1R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p1r >= 256); + OSMO_ASSERT(params->p1r <= 65535); + *dst = (params->p1r >> 8) & 0xFF; + dst++; + *dst = params->p1r & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P3T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p3t >= 0); + OSMO_ASSERT(params->p3t <= 65535); + OSMO_ASSERT(params->p3t >= 2 * params->p1t); + *dst = (params->p3t >> 8) & 0xFF; + dst++; + *dst = params->p3t & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P3R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p3r >= 0); + OSMO_ASSERT(params->p3r <= 65535); + OSMO_ASSERT(params->p3r >= 2 * params->p1r); + *dst = (params->p3r >> 8) & 0xFF; + dst++; + *dst = params->p3r & 0xFF; + dst++; + dst_counter += 2; + + /* Return generated length */ + return dst_counter; +} + +/* Encode data or protocol control information compression field + * (see also: 3GPP TS 44.065, 6.6.1.1, Figure 9 and + * 3GPP TS 44.065, 6.5.1.1, Figure 7) */ +static int encode_comp_field(uint8_t *dst, unsigned int dst_maxlen, + const struct gprs_sndcp_comp_field *comp_field) +{ + int dst_counter = 0; + int len; + int expected_length; + int i; + + OSMO_ASSERT(dst); + OSMO_ASSERT(comp_field); + + uint8_t payload_bytes[256]; + int payload_bytes_len = -1; + + /* If possible, try do encode payload bytes first */ + if (comp_field->rfc1144_params) { + payload_bytes_len = + encode_pcomp_rfc1144_params(payload_bytes, + sizeof(payload_bytes), + comp_field->rfc1144_params); + } else if (comp_field->rfc2507_params) { + payload_bytes_len = + encode_pcomp_rfc2507_params(payload_bytes, + sizeof(payload_bytes), + comp_field->rfc2507_params); + } else if (comp_field->rohc_params) { + payload_bytes_len = + encode_pcomp_rohc_params(payload_bytes, + sizeof(payload_bytes), + comp_field->rohc_params); + } else if (comp_field->v42bis_params) { + payload_bytes_len = + encode_dcomp_v42bis_params(payload_bytes, + sizeof(payload_bytes), + comp_field->v42bis_params); + } else if (comp_field->v44_params) { + payload_bytes_len = + encode_dcomp_v44_params(payload_bytes, + sizeof(payload_bytes), + comp_field->v44_params); + } else + OSMO_ASSERT(false); + + /* Bail immediately if payload byte generation failed */ + OSMO_ASSERT(payload_bytes_len >= 0); + + /* Bail if comp_len is out of bounds */ + OSMO_ASSERT(comp_field->comp_len <= sizeof(comp_field->comp)); + + /* Calculate length field of the data block */ + if (comp_field->p) { + len = + payload_bytes_len + + ceil((double)(comp_field->comp_len) / 2.0); + expected_length = len + 3; + } else { + len = payload_bytes_len; + expected_length = len + 2; + } + + /* Bail immediately if no sufficient memory space is supplied */ + OSMO_ASSERT(dst_maxlen >= expected_length); + + /* Check if the entity number is within bounds */ + OSMO_ASSERT(comp_field->entity <= 0x1f); + + /* Check if the algorithm number is within bounds */ + OSMO_ASSERT(comp_field->algo >= 0 || comp_field->algo <= 0x1f); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode Propose bit */ + if (comp_field->p) + *dst |= (1 << 7); + + /* Encode entity number */ + *dst |= comp_field->entity & 0x1F; + dst++; + dst_counter++; + + /* Encode algorithm number */ + if (comp_field->p) { + *dst |= comp_field->algo & 0x1F; + dst++; + dst_counter++; + } + + /* Encode length field */ + *dst |= len & 0xFF; + dst++; + dst_counter++; + + /* Encode PCOMP/DCOMP values */ + if (comp_field->p) { + for (i = 0; i < comp_field->comp_len; i++) { + /* Check if submitted PCOMP/DCOMP + values are within bounds */ + if ((comp_field->comp[i] < 0) + || (comp_field->comp[i] > 0x0F)) + return -EINVAL; + + if (i & 1) { + *dst |= comp_field->comp[i] & 0x0F; + dst++; + dst_counter++; + } else + *dst |= (comp_field->comp[i] << 4) & 0xF0; + } + + if (i & 1) { + dst++; + dst_counter++; + } + } + + /* Append payload bytes */ + memcpy(dst, payload_bytes, payload_bytes_len); + dst_counter += payload_bytes_len; + + /* Return generated length */ + return dst_counter; +} + +/* Find out to which compression class the specified comp-field belongs + * (header compression or data compression?) */ +int gprs_sndcp_get_compression_class(const struct gprs_sndcp_comp_field + *comp_field) +{ + OSMO_ASSERT(comp_field); + + if (comp_field->rfc1144_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->rfc2507_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->rohc_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->v42bis_params) + return SNDCP_XID_DATA_COMPRESSION; + else if (comp_field->v44_params) + return SNDCP_XID_DATA_COMPRESSION; + else + return -EINVAL; +} + +/* Convert all compression fields to bytstreams */ +static int gprs_sndcp_pack_fields(const struct llist_head *comp_fields, + uint8_t *dst, + unsigned int dst_maxlen, int class) +{ + struct gprs_sndcp_comp_field *comp_field; + int byte_counter = 0; + int rc; + + OSMO_ASSERT(comp_fields); + OSMO_ASSERT(dst); + + llist_for_each_entry_reverse(comp_field, comp_fields, list) { + if (class == gprs_sndcp_get_compression_class(comp_field)) { + rc = encode_comp_field(dst + byte_counter, + dst_maxlen - byte_counter, + comp_field); + + /* When input data is correct, there is + * no reason for the encoder to fail! */ + OSMO_ASSERT(rc >= 0); + + byte_counter += rc; + } + } + + /* Return generated length */ + return byte_counter; +} + +/* Transform a list with compression fields into an SNDCP-XID message (dst) */ +int gprs_sndcp_compile_xid(uint8_t *dst, unsigned int dst_maxlen, + const struct llist_head *comp_fields) +{ + int rc; + int byte_counter = 0; + uint8_t comp_bytes[512]; + uint8_t xid_version_number[1] = { CURRENT_SNDCP_VERSION }; + + OSMO_ASSERT(comp_fields); + OSMO_ASSERT(dst); + OSMO_ASSERT(dst_maxlen >= 2 + sizeof(xid_version_number)); + + /* Bail if there is no input */ + if (llist_empty(comp_fields)) + return -EINVAL; + + /* Prepend header */ + dst = + tlv_put(dst, SNDCP_XID_VERSION_NUMBER, + sizeof(xid_version_number), xid_version_number); + byte_counter += (sizeof(xid_version_number) + 2); + + /* Add data compression fields */ + rc = gprs_sndcp_pack_fields(comp_fields, comp_bytes, + sizeof(comp_bytes), + SNDCP_XID_DATA_COMPRESSION); + OSMO_ASSERT(rc >= 0); + + if (rc > 0) { + dst = tlv_put(dst, SNDCP_XID_DATA_COMPRESSION, rc, comp_bytes); + byte_counter += rc + 2; + } + + /* Add header compression fields */ + rc = gprs_sndcp_pack_fields(comp_fields, comp_bytes, + sizeof(comp_bytes), + SNDCP_XID_PROTOCOL_COMPRESSION); + OSMO_ASSERT(rc >= 0); + + if (rc > 0) { + dst = tlv_put(dst, SNDCP_XID_PROTOCOL_COMPRESSION, rc, + comp_bytes); + byte_counter += rc + 2; + } + + /* Return generated length */ + return byte_counter; +} + +/* FUNCTIONS RELATED TO SNDCP-XID DECODING */ + +/* Decode applicable sapis (works the same in all three compression schemes) */ +static int decode_pcomp_applicable_sapis(uint8_t *nsapis, + uint8_t *nsapis_len, + const uint8_t *src, + unsigned int src_len) +{ + uint16_t blob; + int i; + int nsapi_len = 0; + + OSMO_ASSERT(src); + + /* Exit immediately if no result can be stored */ + if (!nsapis) + return -EINVAL; + + /* Exit immediately if not enough input data is available */ + if (src_len < 2) + return -EINVAL; + + /* Read bitmask */ + blob = *src; + blob = (blob << 8) & 0xFF00; + src++; + blob |= (*src) & 0xFF; + blob = (blob >> 5); + + /* Decode applicable SAPIs */ + for (i = 0; i < 15; i++) { + if ((blob >> i) & 1) { + nsapis[nsapi_len] = i + 5; + nsapi_len++; + } + } + + /* Return consumed length */ + *nsapis_len = nsapi_len; + return 2; +} + +/* Decode 16 bit field */ +static int decode_pcomp_16_bit_field(int *value_int, uint16_t * value_uint16, + const uint8_t *src, + unsigned int src_len, + int value_min, int value_max) +{ + uint16_t blob; + + OSMO_ASSERT(src); + + /* Reset values to zero (just to be sure) */ + if (value_int) + *value_int = -1; + if (value_uint16) + *value_uint16 = 0; + + /* Exit if not enough src are available */ + if (src_len < 2) + return -EINVAL; + + /* Decode bit value */ + blob = *src; + blob = (blob << 8) & 0xFF00; + src++; + blob |= *src; + + /* Check if parsed value is within bounds */ + if (blob < value_min) + return -EINVAL; + if (blob > value_max) + return -EINVAL; + + /* Hand back results to the caller */ + if (value_int) + *value_int = blob; + if (value_uint16) + *value_uint16 = blob; + + /* Return consumed length */ + return 2; +} + +/* Decode 8 bit field */ +static int decode_pcomp_8_bit_field(int *value_int, uint8_t *value_uint8, + const uint8_t *src, + unsigned int src_len, + int value_min, int value_max) +{ + uint8_t blob; + + OSMO_ASSERT(src); + + /* Reset values to invalid (just to be sure) */ + if (value_int) + *value_int = -1; + if (value_uint8) + *value_uint8 = 0; + + /* Exit if not enough src are available */ + if (src_len < 1) + return -EINVAL; + + /* Decode bit value */ + blob = *src; + + /* Check if parsed value is within bounds */ + if (blob < value_min) + return -EINVAL; + if (blob > value_max) + return -EINVAL; + + /* Hand back results to the caller */ + if (value_int) + *value_int = blob; + if (value_uint8) + *value_uint8 = blob; + + /* Return consumed length */ + return 1; +} + +/* Decode rfc1144 parameter field see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */ +static int decode_pcomp_rfc1144_params(struct gprs_sndcp_pcomp_rfc1144_params + *params, const uint8_t *src, + unsigned int src_len) +{ + int rc; + int byte_counter = 0; + + OSMO_ASSERT(params); + OSMO_ASSERT(src); + + /* Mark all optional parameters invalid by default */ + params->s01 = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode parameter S0 -1 + * (see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */ + rc = decode_pcomp_8_bit_field(¶ms->s01, NULL, src, + src_len - byte_counter, 0, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Decode rfc2507 parameter field + * (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ +static int decode_pcomp_rfc2507_params(struct gprs_sndcp_pcomp_rfc2507_params + *params, const uint8_t *src, + unsigned int src_len) +{ + int rc; + int byte_counter = 0; + + OSMO_ASSERT(params); + OSMO_ASSERT(src); + + /* Mark all optional parameters invalid by default */ + params->f_max_period = -1; + params->f_max_time = -1; + params->max_header = -1; + params->tcp_space = -1; + params->non_tcp_space = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode F_MAX_PERIOD (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_16_bit_field(¶ms->f_max_period, NULL, src, + src_len - byte_counter, 1, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode F_MAX_TIME (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_8_bit_field(¶ms->f_max_time, NULL, src, + src_len - byte_counter, 1, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_8_bit_field(¶ms->max_header, NULL, src, + src_len - byte_counter, 60, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_8_bit_field(¶ms->tcp_space, NULL, src, + src_len - byte_counter, 3, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode NON_TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_16_bit_field(¶ms->non_tcp_space, NULL, src, + src_len - byte_counter, 3, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Decode ROHC parameter field (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ +static int decode_pcomp_rohc_params(struct gprs_sndcp_pcomp_rohc_params *params, + const uint8_t *src, unsigned int src_len) +{ + int rc; + int byte_counter = 0; + int i; + + OSMO_ASSERT(params); + OSMO_ASSERT(src); + + /* Mark all optional parameters invalid by default */ + params->max_cid = -1; + params->max_header = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_CID (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + rc = decode_pcomp_16_bit_field(¶ms->max_cid, NULL, src, + src_len - byte_counter, 0, 16383); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + rc = decode_pcomp_16_bit_field(¶ms->max_header, NULL, src, + src_len - byte_counter, 60, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode Profiles (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + for (i = 0; i < 16; i++) { + params->profile_len = 0; + rc = decode_pcomp_16_bit_field(NULL, ¶ms->profile[i], src, + src_len - byte_counter, 0, + 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + params->profile_len = i + 1; + } + + /* Return consumed length */ + return byte_counter; +} + +/* Decode V.42bis parameter field + * (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ +static int decode_dcomp_v42bis_params(struct gprs_sndcp_dcomp_v42bis_params + *params, const uint8_t *src, + unsigned int src_len) +{ + int rc; + int byte_counter = 0; + + OSMO_ASSERT(params); + OSMO_ASSERT(src); + + /* Mark all optional parameters invalid by default */ + params->p0 = -1; + params->p1 = -1; + params->p2 = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode P0 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + rc = decode_pcomp_8_bit_field(¶ms->p0, NULL, src, + src_len - byte_counter, 0, 3); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + rc = decode_pcomp_16_bit_field(¶ms->p1, NULL, src, + src_len - byte_counter, 512, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P2 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + rc = decode_pcomp_8_bit_field(¶ms->p2, NULL, src, + src_len - byte_counter, 6, 250); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Decode V44 parameter field (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ +static int decode_dcomp_v44_params(struct gprs_sndcp_dcomp_v44_params *params, + const uint8_t *src, unsigned int src_len) +{ + int rc; + int byte_counter = 0; + + OSMO_ASSERT(params); + OSMO_ASSERT(src); + + /* Mark all optional parameters invalid by default */ + params->c0 = -1; + params->p0 = -1; + params->p1t = -1; + params->p1r = -1; + params->p3t = -1; + params->p3r = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode C0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_8_bit_field(¶ms->c0, NULL, src, + src_len - byte_counter, 0, 255); + if (rc <= 0) + return byte_counter; + if ((params->c0 != 0x80) && (params->c0 != 0xC0)) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Decode P0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_8_bit_field(¶ms->p0, NULL, src, + src_len - byte_counter, 0, 3); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_16_bit_field(¶ms->p1t, NULL, src, + src_len - byte_counter, 265, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_16_bit_field(¶ms->p1r, NULL, src, + src_len - byte_counter, 265, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P3T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_16_bit_field(¶ms->p3t, NULL, src, + src_len - byte_counter, 265, 65535); + if (rc <= 0) + return byte_counter; + if (params->p3t < 2 * params->p1t) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Decode P3R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_16_bit_field(¶ms->p3r, NULL, src, + src_len - byte_counter, 265, 65535); + if (rc <= 0) + return byte_counter; + if (params->p3r < 2 * params->p1r) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Lookup algorithm identfier by entity ID */ +static int lookup_algorithm_identifier(int entity, const struct + entity_algo_table + *lt, unsigned int lt_len, int compclass) +{ + int i; + + if (!lt) + return -1; + + for (i = 0; i < lt_len; i++) { + if ((lt[i].entity == entity) + && (lt[i].compclass == compclass)) + return lt[i].algo; + } + + return -1; +} + +/* Helper function for decode_comp_field(), decodes + * numeric pcomp/dcomp values */ +static int decode_comp_values(struct gprs_sndcp_comp_field *comp_field, + const uint8_t *src, int compclass) +{ + int src_counter = 0; + int i; + + OSMO_ASSERT(comp_field); + OSMO_ASSERT(src); + + if (comp_field->p) { + /* Determine the number of expected PCOMP/DCOMP values */ + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + /* For protocol compression */ + switch (comp_field->algo) { + case RFC_1144: + comp_field->comp_len = RFC1144_PCOMP_NUM; + break; + case RFC_2507: + comp_field->comp_len = RFC2507_PCOMP_NUM; + break; + case ROHC: + comp_field->comp_len = ROHC_PCOMP_NUM; + break; + + /* Exit if the algorithem type encodes + something unknown / unspecified */ + default: + return -EINVAL; + } + } else { + /* For data compression */ + switch (comp_field->algo) { + case V42BIS: + comp_field->comp_len = V42BIS_DCOMP_NUM; + break; + case V44: + comp_field->comp_len = V44_DCOMP_NUM; + break; + + /* Exit if the algorithem type encodes + something unknown / unspecified */ + default: + return -EINVAL; + } + } + + for (i = 0; i < comp_field->comp_len; i++) { + if (i & 1) { + comp_field->comp[i] = (*src) & 0x0F; + src++; + src_counter++; + } else + comp_field->comp[i] = ((*src) >> 4) & 0x0F; + } + + if (i & 1) { + src++; + src_counter++; + } + } + + return src_counter; +} + +/* Helper function for decode_comp_field(), decodes the parameters + * which are protocol compression specific */ +static int decode_pcomp_params(struct gprs_sndcp_comp_field *comp_field, + const uint8_t *src, int src_len) +{ + int rc; + + OSMO_ASSERT(comp_field); + OSMO_ASSERT(src); + + switch (comp_field->algo) { + case RFC_1144: + comp_field->rfc1144_params = talloc_zero(comp_field, struct + gprs_sndcp_pcomp_rfc1144_params); + rc = decode_pcomp_rfc1144_params(comp_field->rfc1144_params, + src, src_len); + if (rc < 0) + talloc_free(comp_field->rfc1144_params); + break; + case RFC_2507: + comp_field->rfc2507_params = talloc_zero(comp_field, struct + gprs_sndcp_pcomp_rfc2507_params); + rc = decode_pcomp_rfc2507_params(comp_field->rfc2507_params, + src, src_len); + if (rc < 0) + talloc_free(comp_field->rfc1144_params); + break; + case ROHC: + comp_field->rohc_params = talloc_zero(comp_field, struct + gprs_sndcp_pcomp_rohc_params); + rc = decode_pcomp_rohc_params(comp_field->rohc_params, src, + src_len); + if (rc < 0) + talloc_free(comp_field->rohc_params); + break; + + /* If no suitable decoder is detected, + leave the remaining bytes undecoded */ + default: + rc = src_len; + } + + if (rc < 0) { + comp_field->rfc1144_params = NULL; + comp_field->rfc2507_params = NULL; + comp_field->rohc_params = NULL; + } + + return rc; +} + +/* Helper function for decode_comp_field(), decodes the parameters + * which are data compression specific */ +static int decode_dcomp_params(struct gprs_sndcp_comp_field *comp_field, + const uint8_t *src, int src_len) +{ + int rc; + + OSMO_ASSERT(comp_field); + OSMO_ASSERT(src); + + switch (comp_field->algo) { + case V42BIS: + comp_field->v42bis_params = talloc_zero(comp_field, struct + gprs_sndcp_dcomp_v42bis_params); + rc = decode_dcomp_v42bis_params(comp_field->v42bis_params, src, + src_len); + if (rc < 0) + talloc_free(comp_field->v42bis_params); + break; + case V44: + comp_field->v44_params = talloc_zero(comp_field, struct + gprs_sndcp_dcomp_v44_params); + rc = decode_dcomp_v44_params(comp_field->v44_params, src, + src_len); + if (rc < 0) + talloc_free(comp_field->v44_params); + break; + + /* If no suitable decoder is detected, + * leave the remaining bytes undecoded */ + default: + rc = src_len; + } + + if (rc < 0) { + comp_field->v42bis_params = NULL; + comp_field->v44_params = NULL; + } + + return rc; +} + +/* Decode data or protocol control information compression field + * (see also: 3GPP TS 44.065, 6.6.1.1, Figure 9 and + * 3GPP TS 44.065, 6.5.1.1, Figure 7) */ +static int decode_comp_field(struct gprs_sndcp_comp_field *comp_field, + const uint8_t *src, unsigned int src_len, + const struct entity_algo_table *lt, + unsigned int lt_len, int compclass) +{ + int src_counter = 0; + unsigned int len; + int rc; + + OSMO_ASSERT(comp_field); + + /* Exit immediately if it is clear that no + parseable data is present */ + if (src_len < 1 || !src) + return -EINVAL; + + /* Zero out target struct */ + memset(comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + + /* Decode Propose bit and Entity number */ + if ((*src) & 0x80) + comp_field->p = 1; + comp_field->entity = (*src) & 0x1F; + src_counter++; + src++; + + /* Decode algorithm number (if present) */ + if (comp_field->p) { + comp_field->algo = (*src) & 0x1F; + src_counter++; + src++; + } + /* Alternatively take the information from the lookup table */ + else + comp_field->algo = + lookup_algorithm_identifier(comp_field->entity, lt, + lt_len, compclass); + + /* Decode length field */ + len = *src; + src_counter++; + src++; + + /* Decode PCOMP/DCOMP values */ + rc = decode_comp_values(comp_field, src, compclass); + if (rc < 0) + return -EINVAL; + src_counter += rc; + src += rc; + len -= rc; + + /* Decode algorithm specific payload data */ + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + rc = decode_pcomp_params(comp_field, src, len); + else if (compclass == SNDCP_XID_DATA_COMPRESSION) + rc = decode_dcomp_params(comp_field, src, len); + else + return -EINVAL; + + if (rc >= 0) + src_counter += rc; + else + return -EINVAL; + + /* Return consumed length */ + return src_counter; +} + +/* Helper function for gprs_sndcp_decode_xid() to decode XID blocks */ +static int decode_xid_block(struct llist_head *comp_fields, uint8_t tag, + uint16_t tag_len, const uint8_t *val, + const struct entity_algo_table *lt, + unsigned int lt_len) +{ + struct gprs_sndcp_comp_field *comp_field; + int byte_counter = 0; + int comp_field_count = 0; + int rc; + + OSMO_ASSERT(comp_fields); + OSMO_ASSERT(val); + + byte_counter = 0; + do { + /* Bail if more than the maximum number of + comp_fields is generated */ + if (comp_field_count > MAX_ENTITIES * 2) { + return -EINVAL; + } + + /* Parse and add comp_field */ + comp_field = + talloc_zero(comp_fields, struct gprs_sndcp_comp_field); + + rc = decode_comp_field(comp_field, val + byte_counter, + tag_len - byte_counter, lt, lt_len, tag); + + if (rc < 0) { + talloc_free(comp_field); + return -EINVAL; + } + + byte_counter += rc; + llist_add(&comp_field->list, comp_fields); + comp_field_count++; + } + while (tag_len - byte_counter > 0); + + return byte_counter; +} + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +static int gprs_sndcp_decode_xid(struct llist_head *comp_fields, + const uint8_t *src, unsigned int src_len, + const struct + entity_algo_table + *lt, unsigned int lt_len) +{ + int src_pos = 0; + uint8_t tag; + uint16_t tag_len; + const uint8_t *val; + int byte_counter = 0; + int rc; + int tlv_count = 0; + + OSMO_ASSERT(comp_fields); + OSMO_ASSERT(src); + + /* Valid TLV-Tag and types */ + static const struct tlv_definition sndcp_xid_def = { + .def = { + [SNDCP_XID_VERSION_NUMBER] = {TLV_TYPE_TLV,}, + [SNDCP_XID_DATA_COMPRESSION] = {TLV_TYPE_TLV,}, + [SNDCP_XID_PROTOCOL_COMPRESSION] = {TLV_TYPE_TLV,}, + }, + }; + + /* Parse TLV-Encoded SNDCP-XID message and defer payload + to the apporpiate sub-parser functions */ + while (1) { + + /* Bail if an the maximum number of TLV fields + * have been parsed */ + if (tlv_count >= 3) { + talloc_free(comp_fields); + return -EINVAL; + } + + /* Parse TLV field */ + rc = tlv_parse_one(&tag, &tag_len, &val, &sndcp_xid_def, + src + src_pos, src_len - src_pos); + if (rc > 0) + src_pos += rc; + else { + talloc_free(comp_fields); + return -EINVAL; + } + + /* Decode compression parameters */ + if ((tag == SNDCP_XID_PROTOCOL_COMPRESSION) + || (tag == SNDCP_XID_DATA_COMPRESSION)) { + rc = decode_xid_block(comp_fields, tag, tag_len, val, + lt, lt_len); + + if (rc < 0) { + talloc_free(comp_fields); + return -EINVAL; + } else + byte_counter += rc; + } + + /* Stop when no further TLV elements can be expected */ + if (src_len - src_pos <= 2) + break; + + tlv_count++; + } + + return 0; +} + +/* Fill up lookutable from a list with comression entitiy fields */ +static int gprs_sndcp_fill_table(struct + entity_algo_table *lt, + unsigned int lt_len, + const struct llist_head *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field; + int i = 0; + + OSMO_ASSERT(lt); + OSMO_ASSERT(comp_fields); + + if (!comp_fields) + return -EINVAL; + if (!lt) + return -EINVAL; + + memset(lt, 0, lt_len * sizeof(lt)); + + llist_for_each_entry(comp_field, comp_fields, list) { + + lt[i].entity = comp_field->entity; + lt[i].algo = comp_field->algo; + lt[i].compclass = gprs_sndcp_get_compression_class(comp_field); + + if (lt[i].compclass < 0) { + memset(lt, 0, lt_len * sizeof(lt)); + return -EINVAL; + } + + i++; + } + + return i; +} + +/* Complete comp field params + * (if a param (dst) is not valid, it will be copied from source (src) */ +static int complete_comp_field_params(struct gprs_sndcp_comp_field + *comp_field_dst, const struct + gprs_sndcp_comp_field *comp_field_src) +{ + OSMO_ASSERT(comp_field_dst); + OSMO_ASSERT(comp_field_src); + + if (comp_field_dst->algo < 0) + return -EINVAL; + + if (comp_field_dst->rfc1144_params && comp_field_src->rfc1144_params) { + if (comp_field_dst->rfc1144_params->s01 < 0) { + comp_field_dst->rfc1144_params->s01 = + comp_field_src->rfc1144_params->s01; + } + return 0; + } + + if (comp_field_dst->rfc2507_params && comp_field_src->rfc2507_params) { + + if (comp_field_dst->rfc2507_params->f_max_period < 0) { + comp_field_dst->rfc2507_params->f_max_period = + comp_field_src->rfc2507_params->f_max_period; + } + if (comp_field_dst->rfc2507_params->f_max_time < 0) { + comp_field_dst->rfc2507_params->f_max_time = + comp_field_src->rfc2507_params->f_max_time; + } + if (comp_field_dst->rfc2507_params->max_header < 0) { + comp_field_dst->rfc2507_params->max_header = + comp_field_src->rfc2507_params->max_header; + } + if (comp_field_dst->rfc2507_params->tcp_space < 0) { + comp_field_dst->rfc2507_params->tcp_space = + comp_field_src->rfc2507_params->tcp_space; + } + if (comp_field_dst->rfc2507_params->non_tcp_space < 0) { + comp_field_dst->rfc2507_params->non_tcp_space = + comp_field_src->rfc2507_params->non_tcp_space; + } + return 0; + } + + if (comp_field_dst->rohc_params && comp_field_src->rohc_params) { + if (comp_field_dst->rohc_params->max_cid < 0) { + comp_field_dst->rohc_params->max_cid = + comp_field_src->rohc_params->max_cid; + } + if (comp_field_dst->rohc_params->max_header < 0) { + comp_field_dst->rohc_params->max_header = + comp_field_src->rohc_params->max_header; + } + if (comp_field_dst->rohc_params->profile_len > 0) { + memcpy(comp_field_dst->rohc_params->profile, + comp_field_src->rohc_params->profile, + sizeof(comp_field_dst->rohc_params->profile)); + comp_field_dst->rohc_params->profile_len = + comp_field_src->rohc_params->profile_len; + } + + return 0; + } + + if (comp_field_dst->v42bis_params && comp_field_src->v42bis_params) { + if (comp_field_dst->v42bis_params->p0 < 0) { + comp_field_dst->v42bis_params->p0 = + comp_field_src->v42bis_params->p0; + } + if (comp_field_dst->v42bis_params->p1 < 0) { + comp_field_dst->v42bis_params->p1 = + comp_field_src->v42bis_params->p1; + } + if (comp_field_dst->v42bis_params->p2 < 0) { + comp_field_dst->v42bis_params->p2 = + comp_field_src->v42bis_params->p2; + } + return 0; + } + + if (comp_field_dst->v44_params && comp_field_src->v44_params) { + if (comp_field_dst->v44_params->c0 < 0) { + comp_field_dst->v44_params->c0 = + comp_field_src->v44_params->c0; + } + if (comp_field_dst->v44_params->p0 < 0) { + comp_field_dst->v44_params->p0 = + comp_field_src->v44_params->p0; + } + if (comp_field_dst->v44_params->p1t < 0) { + comp_field_dst->v44_params->p1t = + comp_field_src->v44_params->p1t; + } + if (comp_field_dst->v44_params->p1r < 0) { + comp_field_dst->v44_params->p1r = + comp_field_src->v44_params->p1r; + } + if (comp_field_dst->v44_params->p3t < 0) { + comp_field_dst->v44_params->p3t = + comp_field_src->v44_params->p3t; + } + if (comp_field_dst->v44_params->p3r < 0) { + comp_field_dst->v44_params->p3r = + comp_field_src->v44_params->p3r; + } + return 0; + } + + /* There should be at least exist one param set + * in the destination struct, otherwise something + * must be wrong! */ + return -EINVAL; +} + +/* Complete missing parameters in a comp_field */ +static int gprs_sndcp_complete_comp_field(struct gprs_sndcp_comp_field + *comp_field, const struct llist_head + *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field_src; + int rc = 0; + + OSMO_ASSERT(comp_field); + OSMO_ASSERT(comp_fields); + + llist_for_each_entry(comp_field_src, comp_fields, list) { + if (comp_field_src->entity == comp_field->entity) { + + /* Complete header fields */ + if (comp_field_src->comp_len > 0) { + memcpy(comp_field->comp, + comp_field_src->comp, + sizeof(comp_field_src->comp)); + comp_field->comp_len = comp_field_src->comp_len; + } + + /* Complete parameter fields */ + rc = complete_comp_field_params(comp_field, + comp_field_src); + } + } + + return rc; +} + +/* Complete missing parameters of all comp_field in a list */ +static int gprs_sndcp_complete_comp_fields(struct llist_head + *comp_fields_incomplete, + const struct llist_head *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field_incomplete; + int rc; + + OSMO_ASSERT(comp_fields_incomplete); + OSMO_ASSERT(comp_fields); + + llist_for_each_entry(comp_field_incomplete, comp_fields_incomplete, + list) { + + rc = gprs_sndcp_complete_comp_field(comp_field_incomplete, + comp_fields); + if (rc < 0) + return -EINVAL; + + } + + return 0; +} + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +struct llist_head *gprs_sndcp_parse_xid(const void *ctx, + const uint8_t *src, + unsigned int src_len, + const struct llist_head + *comp_fields_req) +{ + int rc; + int lt_len; + struct llist_head *comp_fields; + struct entity_algo_table lt[MAX_ENTITIES * 2]; + + OSMO_ASSERT(src); + + comp_fields = talloc_zero(ctx, struct llist_head); + INIT_LLIST_HEAD(comp_fields); + + if (comp_fields_req) { + /* Generate lookup table */ + lt_len = + gprs_sndcp_fill_table(lt, MAX_ENTITIES * 2, + comp_fields_req); + if (lt_len < 0) { + talloc_free(comp_fields); + return NULL; + } + + /* Parse SNDCP-CID XID-Field */ + rc = gprs_sndcp_decode_xid(comp_fields, src, src_len, lt, + lt_len); + if (rc < 0) { + talloc_free(comp_fields); + return NULL; + } + + rc = gprs_sndcp_complete_comp_fields(comp_fields, + comp_fields_req); + if (rc < 0) { + talloc_free(comp_fields); + return NULL; + } + + } else { + /* Parse SNDCP-CID XID-Field */ + rc = gprs_sndcp_decode_xid(comp_fields, src, src_len, NULL, 0); + if (rc < 0) { + talloc_free(comp_fields); + return NULL; + } + } + + return comp_fields; +} + +/* Helper for gprs_sndcp_dump_comp_fields(), + * dumps protocol compression parameters */ +static void dump_pcomp_params(const struct gprs_sndcp_comp_field + *comp_field, unsigned int logl) +{ + int i; + + OSMO_ASSERT(comp_field); + + switch (comp_field->algo) { + case RFC_1144: + if (comp_field->rfc1144_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_pcomp_rfc1144_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_pcomp_rfc1144_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%d;\n", + comp_field->rfc1144_params->nsapi_len); + if (comp_field->rfc1144_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rfc1144_params->nsapi_len; i++) { + LOGP(DSNDCP, logl, + " nsapi[%d]=%d;\n", i, + comp_field->rfc1144_params->nsapi[i]); + } + LOGP(DSNDCP, logl, " s01=%d;\n", + comp_field->rfc1144_params->s01); + LOGP(DSNDCP, logl, " }\n"); + break; + case RFC_2507: + if (comp_field->rfc2507_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_pcomp_rfc2507_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_pcomp_rfc2507_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%d;\n", + comp_field->rfc2507_params->nsapi_len); + if (comp_field->rfc2507_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rfc2507_params->nsapi_len; i++) { + LOGP(DSNDCP, logl, + " nsapi[%d]=%d;\n", i, + comp_field->rfc2507_params->nsapi[i]); + } + LOGP(DSNDCP, logl, + " f_max_period=%d;\n", + comp_field->rfc2507_params->f_max_period); + LOGP(DSNDCP, logl, + " f_max_time=%d;\n", + comp_field->rfc2507_params->f_max_time); + LOGP(DSNDCP, logl, + " max_header=%d;\n", + comp_field->rfc2507_params->max_header); + LOGP(DSNDCP, logl, + " tcp_space=%d;\n", + comp_field->rfc2507_params->tcp_space); + LOGP(DSNDCP, logl, + " non_tcp_space=%d;\n", + comp_field->rfc2507_params->non_tcp_space); + LOGP(DSNDCP, logl, " }\n"); + break; + case ROHC: + if (comp_field->rohc_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_pcomp_rohc_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_pcomp_rohc_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%d;\n", + comp_field->rohc_params->nsapi_len); + if (comp_field->rohc_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rohc_params->nsapi_len; i++) { + LOGP(DSNDCP, logl, + " nsapi[%d]=%d;\n", i, + comp_field->rohc_params->nsapi[i]); + } + LOGP(DSNDCP, logl, + " max_cid=%d;\n", comp_field->rohc_params->max_cid); + LOGP(DSNDCP, logl, + " max_header=%d;\n", + comp_field->rohc_params->max_header); + LOGP(DSNDCP, logl, + " profile_len=%d;\n", + comp_field->rohc_params->profile_len); + if (comp_field->rohc_params->profile_len == 0) + LOGP(DSNDCP, logl, " profile[] = NULL;\n"); + for (i = 0; i < comp_field->rohc_params->profile_len; i++) + LOGP(DSNDCP, logl, + " profile[%d]=%04x;\n", + i, comp_field->rohc_params->profile[i]); + LOGP(DSNDCP, logl, " }\n"); + break; + } + +} + +/* Helper for gprs_sndcp_dump_comp_fields(), + * data protocol compression parameters */ +static void dump_dcomp_params(const struct gprs_sndcp_comp_field + *comp_field, unsigned int logl) +{ + int i; + + OSMO_ASSERT(comp_field); + + switch (comp_field->algo) { + case V42BIS: + if (comp_field->v42bis_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_dcomp_v42bis_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_dcomp_v42bis_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%d;\n", + comp_field->v42bis_params->nsapi_len); + if (comp_field->v42bis_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->v42bis_params->nsapi_len; i++) + LOGP(DSNDCP, logl, + " nsapi[%d]=%d;\n", i, + comp_field->v42bis_params->nsapi[i]); + LOGP(DSNDCP, logl, " p0=%d;\n", + comp_field->v42bis_params->p0); + LOGP(DSNDCP, logl, " p1=%d;\n", + comp_field->v42bis_params->p1); + LOGP(DSNDCP, logl, " p2=%d;\n", + comp_field->v42bis_params->p2); + LOGP(DSNDCP, logl, " }\n"); + break; + case V44: + if (comp_field->v44_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_dcomp_v44_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_dcomp_v44_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%d;\n", + comp_field->v44_params->nsapi_len); + if (comp_field->v44_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->v44_params->nsapi_len; i++) { + LOGP(DSNDCP, logl, + " nsapi[%d]=%d;\n", i, + comp_field->v44_params->nsapi[i]); + } + LOGP(DSNDCP, logl, " c0=%d;\n", + comp_field->v44_params->c0); + LOGP(DSNDCP, logl, " p0=%d;\n", + comp_field->v44_params->p0); + LOGP(DSNDCP, logl, " p1t=%d;\n", + comp_field->v44_params->p1t); + LOGP(DSNDCP, logl, " p1r=%d;\n", + comp_field->v44_params->p1r); + LOGP(DSNDCP, logl, " p3t=%d;\n", + comp_field->v44_params->p3t); + LOGP(DSNDCP, logl, " p3r=%d;\n", + comp_field->v44_params->p3r); + LOGP(DSNDCP, logl, " }\n"); + break; + } +} + +/* Dump a list with SNDCP-XID fields (Debug) */ +void gprs_sndcp_dump_comp_fields(const struct llist_head *comp_fields, + unsigned int logl) +{ + struct gprs_sndcp_comp_field *comp_field; + int i; + int compclass; + + OSMO_ASSERT(comp_fields); + + llist_for_each_entry(comp_field, comp_fields, list) { + LOGP(DSNDCP, logl, "SNDCP-XID:\n"); + LOGP(DSNDCP, logl, "struct gprs_sndcp_comp_field {\n"); + LOGP(DSNDCP, logl, " entity=%d;\n", comp_field->entity); + LOGP(DSNDCP, logl, " algo=%d;\n", comp_field->algo); + LOGP(DSNDCP, logl, " comp_len=%d;\n", comp_field->comp_len); + if (comp_field->comp_len == 0) + LOGP(DSNDCP, logl, " comp[] = NULL;\n"); + for (i = 0; i < comp_field->comp_len; i++) { + LOGP(DSNDCP, logl, " comp[%d]=%d;\n", i, + comp_field->comp[i]); + } + + compclass = gprs_sndcp_get_compression_class(comp_field); + + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + dump_pcomp_params(comp_field, logl); + } else if (compclass == SNDCP_XID_DATA_COMPRESSION) { + dump_dcomp_params(comp_field, logl); + } + + LOGP(DSNDCP, logl, "}\n"); + } + +} diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index ba5ca28..1debb2d 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 74af159..45d1780 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -31,6 +31,7 @@ $(top_builddir)/src/gprs/oap.o \ $(top_builddir)/src/gprs/oap_messages.o \ $(top_builddir)/src/gprs/gprs_llc_xid.o \ + $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ @@ -38,5 +39,5 @@ $(LIBOSMOGB_LIBS) \ $(LIBCARES_LIBS) \ $(LIBCRYPTO_LIBS) \ - -lgtp -lrt + -lgtp -lrt -lm diff --git a/openbsc/tests/sndcp_xid/Makefile.am b/openbsc/tests/sndcp_xid/Makefile.am new file mode 100644 index 0000000..99b9d1a --- /dev/null +++ b/openbsc/tests/sndcp_xid/Makefile.am @@ -0,0 +1,20 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) + +EXTRA_DIST = sndcp_xid_test.ok + +noinst_PROGRAMS = sndcp_xid_test + +sndcp_xid_test_SOURCES = sndcp_xid_test.c + +sndcp_xid_test_LDADD = \ + $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOGB_LIBS) \ + $(LIBCARES_LIBS) \ + $(LIBCRYPTO_LIBS) \ + -lgtp -lrt -lm + + diff --git a/openbsc/tests/sndcp_xid/sndcp_xid_test.c b/openbsc/tests/sndcp_xid/sndcp_xid_test.c new file mode 100644 index 0000000..3a33619 --- /dev/null +++ b/openbsc/tests/sndcp_xid/sndcp_xid_test.c @@ -0,0 +1,282 @@ +/* Test SNDCP-XID Encoding/Decoding */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include +#include + +#include + +#include +#include + +/* Test SNDCP-XID decoding with a real world sample */ +static void test_xid_decode_realworld(const void *ctx) +{ + struct llist_head *comp_fields; + int rc; + printf("Testing SNDCP XID-Decoder/Encoder (real world data)\n"); + + /* Example of a real world SNDCP-XID message */ + uint8_t xid[] = + { 0x00, 0x01, 0x00, 0x02, 0x31, 0x82, 0x02, 0x27, 0x89, 0xff, 0xe0, + 0x00, 0x0f, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, + 0x01, 0x02, 0x00, 0x03, 0x01, 0x03, 0x00, 0x04, 0x01, 0x04, 0x00, 0x05, + 0x01, 0x05, 0x00, 0x06, 0x00, 0x07, 0x01, 0x07, 0x00, 0x08, 0x01, 0x08, + 0x80, 0x00, 0x04, 0x12, 0x00, 0x40, 0x07 }; + uint8_t xid_r[512]; + + /* Parse and show contained comp fields */ + comp_fields = gprs_sndcp_parse_xid(ctx, xid, sizeof(xid), NULL); + OSMO_ASSERT(comp_fields); + printf("Decoded:\n"); + gprs_sndcp_dump_comp_fields(comp_fields, DSNDCP); + + /* Encode comp-fields again */ + rc = gprs_sndcp_compile_xid(xid_r,sizeof(xid_r), comp_fields); + printf("Result length=%i\n",rc); + printf("Encoded: %s\n", osmo_hexdump_nospc(xid, sizeof(xid))); + printf("Rencoded: %s\n", osmo_hexdump_nospc(xid_r, rc)); + + OSMO_ASSERT(rc == 54); + OSMO_ASSERT(memcmp(xid, xid_r, sizeof(xid)) == 0); + + /* Free comp fields */ + talloc_free(comp_fields); + + printf("\n"); +} + +/* Encode and decode test with artificial test data */ +static void test_xid_encode_decode(const void *ctx) +{ + printf("Testing SNDCP XID-Encoder/Decoder\n"); + + LLIST_HEAD(comp_fields); + struct gprs_sndcp_pcomp_rfc1144_params rfc1144_params; + struct gprs_sndcp_comp_field rfc1144_comp_field; + struct gprs_sndcp_pcomp_rfc2507_params rfc2507_params; + struct gprs_sndcp_comp_field rfc2507_comp_field; + struct gprs_sndcp_pcomp_rohc_params rohc_params; + struct gprs_sndcp_comp_field rohc_comp_field; + struct gprs_sndcp_dcomp_v42bis_params v42bis_params; + struct gprs_sndcp_comp_field v42bis_comp_field; + struct gprs_sndcp_dcomp_v44_params v44_params; + struct gprs_sndcp_comp_field v44_comp_field; + struct llist_head *comp_fields_dec; + + uint8_t xid[512]; + unsigned int xid_len = sizeof(xid); + int rc; + + memset(&rfc1144_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + memset(&rfc2507_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + memset(&rohc_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + memset(&v42bis_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + memset(&v44_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + + /* Setup which NSAPIs shall make use of rfc1144 */ + rfc1144_params.nsapi[0] = 5; + rfc1144_params.nsapi_len = 1; + + /* Setup rfc1144 operating parameters */ + rfc1144_params.s01 = 7; + + /* Setup rfc1144 compression field */ + rfc1144_comp_field.p = 1; + rfc1144_comp_field.entity = 0; + rfc1144_comp_field.algo = RFC_1144; + rfc1144_comp_field.comp[RFC1144_PCOMP1] = 1; + rfc1144_comp_field.comp[RFC1144_PCOMP2] = 2; + rfc1144_comp_field.comp_len = RFC1144_PCOMP_NUM; + rfc1144_comp_field.rfc1144_params = &rfc1144_params; + + /* Setup which NSAPIs shall make use of rfc1144 */ + rfc2507_params.nsapi[0] = 6; + rfc2507_params.nsapi_len = 1; + + /* Setup rfc2507 operating parameters */ + rfc2507_params.f_max_period = 256; + rfc2507_params.f_max_time = 5; + rfc2507_params.max_header = 168; + rfc2507_params.tcp_space = 15; + rfc2507_params.non_tcp_space = 15; + + /* Setup rfc2507 compression field */ + rfc2507_comp_field.p = 1; + rfc2507_comp_field.entity = 1; + rfc2507_comp_field.algo = RFC_2507; + rfc2507_comp_field.comp[RFC2507_PCOMP1] = 3; + rfc2507_comp_field.comp[RFC2507_PCOMP2] = 4; + rfc2507_comp_field.comp[RFC2507_PCOMP3] = 5; + rfc2507_comp_field.comp[RFC2507_PCOMP4] = 6; + rfc2507_comp_field.comp[RFC2507_PCOMP5] = 7; + rfc2507_comp_field.comp_len = RFC2507_PCOMP_NUM; + rfc2507_comp_field.rfc2507_params = &rfc2507_params; + + /* Setup which NSAPIs shall make use of ROHC */ + rohc_params.nsapi[0] = 5; + rohc_params.nsapi[1] = 6; + rohc_params.nsapi[2] = 7; + rohc_params.nsapi[3] = 8; + rohc_params.nsapi[4] = 9; + rohc_params.nsapi[5] = 10; + rohc_params.nsapi[6] = 11; + rohc_params.nsapi[7] = 12; + rohc_params.nsapi[8] = 13; + rohc_params.nsapi[9] = 14; + rohc_params.nsapi[10] = 15; + rohc_params.nsapi_len = 11; + + /* Setup ROHC operating parameters */ + rohc_params.max_cid = 15; /* default */ + rohc_params.max_header = 168; /* default */ + rohc_params.profile[0] = ROHC_UNCOMPRESSED; + rohc_params.profile[1] = ROHC_RTP; + rohc_params.profile[2] = ROHCV2_RTP; + rohc_params.profile[3] = ROHC_UDP; + rohc_params.profile[4] = ROHCv2_UDP; + rohc_params.profile[5] = ROHC_ESP; + rohc_params.profile[6] = ROHCV2_ESP; + rohc_params.profile[7] = ROHC_IP; + rohc_params.profile[8] = ROHCV2_IP; + rohc_params.profile[9] = ROHC_LLA; + rohc_params.profile[10] = ROHC_LLA_WITH_R_MODE; + rohc_params.profile[11] = ROHC_TCP; + rohc_params.profile[12] = ROHC_RTP_UDP_LITE; + rohc_params.profile[13] = ROHCV2_RTP_UDP_LITE; + rohc_params.profile[14] = ROHC_UDP_LITE; + rohc_params.profile[15] = ROHCV2_UDP_LITE; + rohc_params.profile_len = 16; + + /* Setup ROHC compression field */ + rohc_comp_field.p = 1; + rohc_comp_field.entity = 2; + rohc_comp_field.algo = ROHC; + rohc_comp_field.comp[ROHC_PCOMP1] = 8; + rohc_comp_field.comp[ROHC_PCOMP2] = 9; + rohc_comp_field.comp_len = ROHC_PCOMP_NUM; + rohc_comp_field.rohc_params = &rohc_params; + + /* Setup which NSAPIs shall make use of v42bis */ + v42bis_params.nsapi[0] = 5; + v42bis_params.nsapi_len = 1; + + /* Setup v42bis operating parameters */ + v42bis_params.p0 = 3; + v42bis_params.p1 = 2048; + v42bis_params.p2 = 20; + + /* Setup v42bis compression field */ + v42bis_comp_field.p = 1; + v42bis_comp_field.entity = 3; + v42bis_comp_field.algo = V42BIS; + v42bis_comp_field.comp[V42BIS_DCOMP1] = 10; + v42bis_comp_field.comp_len = V42BIS_DCOMP_NUM; + v42bis_comp_field.v42bis_params = &v42bis_params; + + /* Setup which NSAPIs shall make use of v44 */ + v44_params.nsapi[0] = 5; + v44_params.nsapi_len = 1; + + /* Setup v44 operating parameters */ + v44_params.c0 = 0x80; + v44_params.p0 = 3; + v44_params.p1t = 300; + v44_params.p1r = 300; + v44_params.p3t = 600; + v44_params.p3r = 600; + + /* Setup v44 compression field */ + v44_comp_field.p = 1; + v44_comp_field.entity = 3; + v44_comp_field.algo = V44; + v44_comp_field.comp[V44_DCOMP1] = 10; + v44_comp_field.comp[V44_DCOMP2] = 11; + v44_comp_field.comp_len = V44_DCOMP_NUM; + v44_comp_field.v44_params = &v44_params; + + /* Add compression field(s) to list */ + llist_add(&v44_comp_field.list, &comp_fields); + llist_add(&v42bis_comp_field.list, &comp_fields); + llist_add(&rfc1144_comp_field.list, &comp_fields); + llist_add(&rfc2507_comp_field.list, &comp_fields); + llist_add(&rohc_comp_field.list, &comp_fields); + printf("Test input data:\n"); + gprs_sndcp_dump_comp_fields(&comp_fields, DSNDCP); + + /* Encode SNDCP-XID fields */ + rc = gprs_sndcp_compile_xid(xid, xid_len, &comp_fields); + OSMO_ASSERT(rc > 0); + + printf("Encoded: %s (%i bytes)\n", osmo_hexdump_nospc(xid, rc), rc); + + /* Parse and show contained comp fields */ + comp_fields_dec = gprs_sndcp_parse_xid(ctx, xid, rc, NULL); + OSMO_ASSERT(comp_fields_dec); + + printf("Decoded:\n"); + gprs_sndcp_dump_comp_fields(comp_fields_dec, DSNDCP); + + /* Free comp fields */ + talloc_free(comp_fields_dec); +} + +static struct log_info_cat gprs_categories[] = { + [DSNDCP] = { + .name = "DSNDCP", + .description = + "GPRS Sub-Network Dependent Control Protocol (SNDCP)", + .enabled = 1,.loglevel = LOGL_DEBUG, + } +}; + +static struct log_info info = { + .cat = gprs_categories, + .num_cat = ARRAY_SIZE(gprs_categories), +}; + +int main(int argc, char **argv) +{ + void *xid_ctx; + + osmo_init_logging(&info); + + xid_ctx = talloc_named_const(NULL, 0, "xid_ctx"); + + test_xid_decode_realworld(xid_ctx); + test_xid_encode_decode(xid_ctx); + + printf("Done\n"); + + talloc_report_full(xid_ctx, stderr); + OSMO_ASSERT(talloc_total_blocks(xid_ctx) == 1); + return 0; +} + +/* stubs */ +struct osmo_prim_hdr; +int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) +{ + abort(); +} diff --git a/openbsc/tests/sndcp_xid/sndcp_xid_test.ok b/openbsc/tests/sndcp_xid/sndcp_xid_test.ok new file mode 100644 index 0000000..f357282 --- /dev/null +++ b/openbsc/tests/sndcp_xid/sndcp_xid_test.ok @@ -0,0 +1,11 @@ +Testing SNDCP XID-Decoder/Encoder (real world data) +Decoded: +Result length=54 +Encoded: 000100023182022789ffe0000f00a8000000010101000201020003010300040104000501050006000701070008010880000412004007 +Rencoded: 000100023182022789ffe0000f00a8000000010101000201020003010300040104000501050006000701070008010880000412004007 + +Testing SNDCP XID-Encoder/Decoder +Test input data: +Encoded: 000100011a83010dab00208003012c012c02580258830007a000200308001402408000041200200781010c3456700040010005a80f000f82022789ffe0000f00a80000000101010002010200030103000401040005010500060007010700080108 (97 bytes) +Decoded: +Done diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index 6470ab9..85a81d6 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -129,3 +129,10 @@ cat $abs_srcdir/xid/xid_test.ok > expout AT_CHECK([$abs_top_builddir/tests/xid/xid_test], [], [expout], [ignore]) AT_CLEANUP + +AT_SETUP([sndcp_xid]) +AT_KEYWORDS([sndcp_xid]) +cat $abs_srcdir/sndcp_xid/sndcp_xid_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/sndcp_xid/sndcp_xid_test], [], [expout], [ignore]) +AT_CLEANUP + -- To view, visit https://gerrit.osmocom.org/641 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e Gerrit-PatchSet: 12 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Thu Aug 18 17:13:13 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Thu, 18 Aug 2016 17:13:13 +0000 Subject: [PATCH] openbsc[master]: Adding compression control and final fixups In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/642 to look at the new patch set (#18). Adding compression control and final fixups - Add module to handle compression entities - Add module to control compression - Introduce VTY commands for compression configuration Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 --- M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_sndcp_comp.h A openbsc/include/openbsc/gprs_sndcp_pcomp.h M openbsc/include/openbsc/sgsn.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_sndcp_comp.c A openbsc/src/gprs/gprs_sndcp_pcomp.c M openbsc/src/gprs/sgsn_vty.c M openbsc/tests/sgsn/Makefile.am 9 files changed, 753 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/42/642/18 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index f402fea..88a7e2c 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,7 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ - slhc.h + slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_sndcp_comp.h b/openbsc/include/openbsc/gprs_sndcp_comp.h new file mode 100644 index 0000000..69441fb --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_comp.h @@ -0,0 +1,84 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +/* Header / Data compression entity */ +struct gprs_sndcp_comp { + struct llist_head list; + + /* Serves as an ID in case we want to delete this entity later */ + unsigned int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + + /* Specifies to which NSAPIs the compression entity is assigned */ + uint8_t nsapi_len; /* Number of applicable NSAPIs (default 0) */ + uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */ + + /* Assigned pcomp values */ + uint8_t comp_len; /* Number of contained PCOMP / DCOMP values */ + uint8_t comp[MAX_COMP]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */ + + /* Algorithm parameters */ + int algo; /* Algorithm type (see gprs_sndcp_xid.h) */ + int compclass; /* See gprs_sndcp_xid.h/c */ + void *state; /* Algorithm status and parameters */ +}; + +#define MAX_COMP 16 /* Maximum number of possible pcomp/dcomp values */ +#define MAX_NSAPI 11 /* Maximum number usable NSAPIs */ + +/* Allocate a compression enitiy list */ +struct llist_head *gprs_sndcp_comp_alloc(const void *ctx); + +/* Free a compression entitiy list */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities); + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, unsigned int entity); + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_entities_add(const void *ctx, struct + llist_head *comp_entities, + const struct + gprs_sndcp_comp_field + *comp_field); + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head + *comp_entities, uint8_t comp); + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head + *comp_entities, uint8_t nsapi); + +/* Find a comp_index for a given pcomp/dcomp value */ +int gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp *comp_entity, + int comp); + +/* Find a pcomp/dcomp value for a given comp_index */ +int gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp *comp_entity, + int comp_index); + diff --git a/openbsc/include/openbsc/gprs_sndcp_pcomp.h b/openbsc/include/openbsc/gprs_sndcp_pcomp.h new file mode 100644 index 0000000..2528a86 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_pcomp.h @@ -0,0 +1,44 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field); + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity); + +/* Expand packet header */ +int gprs_sndcp_pcomp_expand(uint8_t *data_o, uint8_t *data_i, unsigned int len, + uint8_t pcomp, + const struct llist_head *comp_entities); + +/* Compress packet header */ +int gprs_sndcp_pcomp_compress(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t *pcomp, + const struct llist_head *comp_entities, + int nsapi); diff --git a/openbsc/include/openbsc/sgsn.h b/openbsc/include/openbsc/sgsn.h index 59126fe..acd3e4b 100644 --- a/openbsc/include/openbsc/sgsn.h +++ b/openbsc/include/openbsc/sgsn.h @@ -89,6 +89,12 @@ int dynamic_lookup; struct oap_config oap; + + /* RFC1144 TCP/IP Header compression */ + struct { + int enabled; + int s01; + } pcomp_rfc1144; }; struct sgsn_instance { diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 245636b..2910c02 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -27,7 +27,7 @@ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ - slhc.c + slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/gprs_sndcp_comp.c b/openbsc/src/gprs/gprs_sndcp_comp.c new file mode 100644 index 0000000..19cd7b1 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_comp.c @@ -0,0 +1,319 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +/* Create a new compression entity from a XID-Field */ +static struct gprs_sndcp_comp *gprs_sndcp_comp_create(const void *ctx, + const struct + gprs_sndcp_comp_field + *comp_field) +{ + OSMO_ASSERT(comp_field); + + struct gprs_sndcp_comp *comp_entity; + comp_entity = talloc_zero(ctx, struct gprs_sndcp_comp); + + /* Copy relevant information from the SNDCP-XID field */ + comp_entity->entity = comp_field->entity; + comp_entity->comp_len = comp_field->comp_len; + memcpy(comp_entity->comp, comp_field->comp, sizeof(comp_entity->comp)); + + if (comp_field->rfc1144_params) { + comp_entity->nsapi_len = comp_field->rfc1144_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc1144_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->rfc2507_params) { + comp_entity->nsapi_len = comp_field->rfc2507_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc2507_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->rohc_params) { + comp_entity->nsapi_len = comp_field->rohc_params->nsapi_len; + memcpy(comp_entity->nsapi, comp_field->rohc_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->v42bis_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->v44_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + sizeof(comp_entity->nsapi)); + } else { + /* The caller is expected to check carefully if the all + * data fields required for compression entity creation + * are present. Otherwise we blow an assertion here */ + OSMO_ASSERT(false); + } + comp_entity->algo = comp_field->algo; + + /* Check if an NSAPI is selected, if not, it does not make sense + * to create the compression entity, since the caller should + * have checked the presence of the NSAPI, we blow an assertion + * in case of missing NSAPIs */ + OSMO_ASSERT(comp_entity->nsapi_len > 0) + + /* Determine of which class our compression entity will be + * (Protocol or Data compresson ?) */ + comp_entity->compclass = + gprs_sndcp_get_compression_class(comp_field); + OSMO_ASSERT(comp_entity->compclass != -1); + + /* Create an algorithm specific compression context */ + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + if (gprs_sndcp_pcomp_init(ctx, comp_entity, comp_field) != 0) { + talloc_free(comp_entity); + comp_entity = NULL; + } + } else { + LOGP(DSNDCP, LOGL_ERROR, + "We don't support data compression yet!\n"); + talloc_free(comp_entity); + return NULL; + } + + /* Display info message */ + if (comp_entity == NULL) { + LOGP(DSNDCP, LOGL_ERROR, + "Header compression entity (%d) creation failed!\n", + comp_entity->entity); + return NULL; + } + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "New header compression entity (%d) created.\n", + comp_entity->entity); + } else { + LOGP(DSNDCP, LOGL_INFO, + "New data compression entity (%d) created.\n", + comp_entity->entity); + } + + return comp_entity; +} + +/* Allocate a compression enitiy list */ +struct llist_head *gprs_sndcp_comp_alloc(const void *ctx) +{ + struct llist_head *lh; + + lh = talloc_zero(ctx, struct llist_head); + INIT_LLIST_HEAD(lh); + + return lh; +} + +/* Free a compression entitiy list */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities) +{ + struct gprs_sndcp_comp *comp_entity; + + /* We expect the caller to take care of allocating a + * compression entity list properly. Attempting to + * free a non existing list clearly points out + * a malfunction. */ + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + /* Free compression entity */ + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %d ...\n", + comp_entity->entity); + gprs_sndcp_pcomp_term(comp_entity); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %d ...\n", + comp_entity->entity); + } + } + + talloc_free(comp_entities); +} + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, + unsigned int entity) +{ + struct gprs_sndcp_comp *comp_entity; + struct gprs_sndcp_comp *comp_entity_to_delete = NULL; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) + comp_entity_to_delete = comp_entity; + } + + if (!comp_entity_to_delete) + return; + + if (comp_entity_to_delete->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %d ...\n", + comp_entity_to_delete->entity); + gprs_sndcp_pcomp_term(comp_entity_to_delete); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %d ...\n", + comp_entity_to_delete->entity); + } + + /* Delete compression entity */ + llist_del(&comp_entity_to_delete->list); + talloc_free(comp_entity_to_delete); +} + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_entities_add(const void *ctx, + struct llist_head + *comp_entities, + const struct + gprs_sndcp_comp_field + *comp_field) +{ + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(comp_entities); + OSMO_ASSERT(comp_field); + + /* Just to be sure, if the entity is already in + * the list it will be deleted now */ + gprs_sndcp_comp_delete(comp_entities, comp_field->entity); + + /* Create and add a new entity to the list */ + comp_entity = gprs_sndcp_comp_create(ctx, comp_field); + + if (!comp_entity) + return NULL; + + llist_add(&comp_entity->list, comp_entities); + return comp_entity; +} + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head + *comp_entities, uint8_t comp) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return comp_entity; + } + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given pcomp/dcomp value %d.\n", + comp); + return NULL; +} + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head + *comp_entities, uint8_t nsapi) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->nsapi_len; i++) { + if (comp_entity->nsapi[i] == nsapi) + return comp_entity; + } + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given nsapi value %d\n", + nsapi); + return NULL; +} + +/* Find a comp_index for a given pcomp/dcomp value */ +int gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp *comp_entity, int comp) +{ + int i; + + OSMO_ASSERT(comp_entity); + + /* A pcomp/dcomp field set to zero always disables + * all sort of compression and is assigned fix. So we + * just return zero in this case */ + if (comp == 0) + return 0; + + /* Look in the pcomp/dcomp list for the index */ + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return i + 1; + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching comp_index for given pcomp/dcomp value %d\n", + comp); + return 0; +} + +/* Find a pcomp/dcomp value for a given comp_index */ +int gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp *comp_entity, + int comp_index) +{ + OSMO_ASSERT(comp_entity); + + /* A comp_index of zero translates to zero right away. */ + if (comp_index == 0) + return 0; + + if (comp_index > comp_entity->comp_len) { + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching pcomp/dcomp value for given comp_index value %d.\n", + comp_index); + return 0; + } + + /* Look in the pcomp/dcomp list for the comp_index */ + return comp_entity->comp[comp_index - 1]; +} diff --git a/openbsc/src/gprs/gprs_sndcp_pcomp.c b/openbsc/src/gprs/gprs_sndcp_pcomp.c new file mode 100644 index 0000000..0fb72b6 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_pcomp.c @@ -0,0 +1,264 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a new header compression + * entity is created by gprs_sndcp.c */ + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + comp_entity->state = + slhc_init(ctx, comp_field->rfc1144_params->s01 + 1, + comp_field->rfc1144_params->s01 + 1); + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression initalized.\n"); + return 0; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a header compression + * entity is deleted by gprs_sndcp.c */ + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + if (comp_entity->state) { + slhc_free((struct slcompress *)comp_entity->state); + comp_entity->state = NULL; + } + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression terminated.\n"); + return; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Compress a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_compress(uint8_t *pcomp_index, + uint8_t *data_o, uint8_t *data_i, + unsigned int len, + struct slcompress *comp) +{ + uint8_t *comp_ptr; /* Required by slhc_compress() */ + int compr_len; + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Run compressor */ + compr_len = slhc_compress(comp, data_i, len, data_o, &comp_ptr, 0); + + /* Generate pcomp_index */ + if (data_o[0] & SL_TYPE_COMPRESSED_TCP) { + *pcomp_index = 2; + data_o[0] &= ~SL_TYPE_COMPRESSED_TCP; + } else if ((data_o[0] & SL_TYPE_UNCOMPRESSED_TCP) == + SL_TYPE_UNCOMPRESSED_TCP) { + *pcomp_index = 1; + data_o[0] &= 0x4F; + } else + *pcomp_index = 0; + + return compr_len; +} + +/* Expand a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_expand(uint8_t *data_o, uint8_t *data_i, + unsigned int len, + uint8_t pcomp_index, + struct slcompress *comp) +{ + int data_decompressed_len; + int type = -1; + + /* Note: this function should never be called with pcomp_index=0, + * since this condition is already filtered + * out by gprs_sndcp_pcomp_expand() */ + + /* Determine the data type by the PCOMP index */ + switch (pcomp_index) { + case 1: + type = SL_TYPE_UNCOMPRESSED_TCP; + break; + case 2: + type = SL_TYPE_COMPRESSED_TCP; + break; + } + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Restore the original version nibble on + * marked uncompressed packets */ + if (type == SL_TYPE_UNCOMPRESSED_TCP) { + /* Just in case the phone tags uncompressed tcp-datas + * (normally this is handled by pcomp so there is + * no need for tagging the datas) */ + data_o[0] &= 0x4F; + data_decompressed_len = slhc_remember(comp, data_o, len); + return data_decompressed_len; + } + + /* Uncompress compressed packets */ + else if (type == SL_TYPE_COMPRESSED_TCP) { + data_decompressed_len = slhc_uncompress(comp, data_o, len); + return data_decompressed_len; + } + + /* Regular or unknown packets will not be touched */ + return len; +} + +/* Expand packet header */ +int gprs_sndcp_pcomp_expand(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t pcomp, + const struct llist_head *comp_entities) +{ + int rc; + uint8_t pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data_o); + OSMO_ASSERT(data_i); + OSMO_ASSERT(comp_entities); + + /* Skip on pcomp=0 */ + if (pcomp == 0) { + memcpy(data_o, data_i, len); + return len; + } + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_comp(comp_entities, pcomp); + + /* Skip compression if no suitable compression entity can be found */ + if (comp_entity == NULL) { + memcpy(data_o, data_i, len); + return len; + } + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION); + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144); + + /* Find pcomp_index */ + pcomp_index = gprs_sndcp_comp_get_idx(comp_entity, pcomp); + + /* Run decompression algo */ + rc = gprs_sndcp_pcomp_rfc1144_expand(data_o, data_i, len, pcomp_index, + comp_entity->state); + slhc_i_status(comp_entity->state); + slhc_o_status(comp_entity->state); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header expansion done, old length=%d, new length=%d\n", len, rc); + + return rc; +} + +/* Compress packet header */ +int gprs_sndcp_pcomp_compress(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t *pcomp, + const struct llist_head *comp_entities, int nsapi) +{ + int rc; + uint8_t pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data_o); + OSMO_ASSERT(data_i); + OSMO_ASSERT(pcomp); + OSMO_ASSERT(comp_entities); + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_nsapi(comp_entities, nsapi); + + /* Skip compression if no suitable compression entity can be found */ + if (!comp_entity) { + *pcomp = 0; + memcpy(data_o, data_i, len); + return len; + } + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION); + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144); + + /* Run compression algo */ + rc = gprs_sndcp_pcomp_rfc1144_compress(&pcomp_index, data_o, data_i, + len, comp_entity->state); + slhc_i_status(comp_entity->state); + slhc_o_status(comp_entity->state); + + /* Find pcomp value */ + *pcomp = gprs_sndcp_comp_get_comp(comp_entity, pcomp_index); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header compression done, old length=%d, new length=%d\n", + len, rc); + return rc; +} diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c index e6dc68d..0c07be0 100644 --- a/openbsc/src/gprs/sgsn_vty.c +++ b/openbsc/src/gprs/sgsn_vty.c @@ -269,6 +269,13 @@ vty_out(vty, " timer t3395 %d%s", g_cfg->timers.T3395, VTY_NEWLINE); vty_out(vty, " timer t3397 %d%s", g_cfg->timers.T3397, VTY_NEWLINE); + if (g_cfg->pcomp_rfc1144.enabled) { + vty_out(vty, " compression rfc1144 slots %d%s", + g_cfg->pcomp_rfc1144.s01+1, VTY_NEWLINE); + } else { + vty_out(vty, " no compression rfc1144%s", VTY_NEWLINE); + } + return CMD_SUCCESS; } @@ -1074,6 +1081,28 @@ return CMD_SUCCESS; } +#define COMPRESSION_STR "Configure compression\n" +DEFUN(cfg_no_comp_rfc1144, cfg_no_comp_rfc1144_cmd, + "no compression rfc1144", + COMPRESSION_STR + "disable rfc1144 TCP/IP header compression\n") +{ + g_cfg->pcomp_rfc1144.enabled = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_comp_rfc1144, cfg_comp_rfc1144_cmd, + "compression rfc1144 slots <1-256>", + COMPRESSION_STR + "RFC1144 Header compresion scheme\n" + "Number of compression state slots\n" + "Number of compression state slots\n") +{ + g_cfg->pcomp_rfc1144.enabled = 1; + g_cfg->pcomp_rfc1144.s01 = atoi(argv[0]) - 1; + return CMD_SUCCESS; +} + int sgsn_vty_init(void) { install_element_ve(&show_sgsn_cmd); @@ -1128,6 +1157,9 @@ install_element(SGSN_NODE, &cfg_sgsn_T3395_cmd); install_element(SGSN_NODE, &cfg_sgsn_T3397_cmd); + install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd); + install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd); + return 0; } diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 3e66978..1804280 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -33,6 +33,8 @@ $(top_builddir)/src/gprs/gprs_llc_xid.o \ $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ $(top_builddir)/src/gprs/slhc.o \ + $(top_builddir)/src/gprs/gprs_sndcp_comp.o \ + $(top_builddir)/src/gprs/gprs_sndcp_pcomp.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ -- To view, visit https://gerrit.osmocom.org/642 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 Gerrit-PatchSet: 18 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Thu Aug 18 17:13:13 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Thu, 18 Aug 2016 17:13:13 +0000 Subject: [PATCH] openbsc[master]: V42BIS integration and unit test In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/644 to look at the new patch set (#23). V42BIS integration and unit test The previously committed SPANDSP v42bis implementation has been edited to function outside the SPANDSP library. Debug printf statements were changed into DEBUGP statements. Als removed the assembely code in top_bit(). Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d --- M openbsc/.gitignore M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/debug.h M openbsc/include/openbsc/v42bis.h R openbsc/include/openbsc/v42bis_private.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/sgsn_main.c M openbsc/src/gprs/v42bis.c M openbsc/tests/Makefile.am M openbsc/tests/testsuite.at A openbsc/tests/v42bis/Makefile.am A openbsc/tests/v42bis/v42bis_test.c A openbsc/tests/v42bis/v42bis_test.ok 14 files changed, 261 insertions(+), 28 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/44/644/23 diff --git a/openbsc/.gitignore b/openbsc/.gitignore index e75b9eb..6fbd463 100644 --- a/openbsc/.gitignore +++ b/openbsc/.gitignore @@ -84,6 +84,7 @@ tests/xid/xid_test tests/sndcp_xid/sndcp_xid_test tests/slhc/slhc_test +tests/v42bis/v42bis_test tests/atconfig tests/atlocal diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 18980b0..1df14fe 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -232,6 +232,7 @@ tests/xid/Makefile tests/sndcp_xid/Makefile tests/slhc/Makefile + tests/v42bis/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 88a7e2c..bc56d0d 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,7 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ - slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h + slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h v42bis.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 90ddca5..ca3d4ad 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -37,6 +37,7 @@ DGTPHUB, DRANAP, DSUA, + DV42BIS, Debug_LastEntry, }; diff --git a/openbsc/include/openbsc/v42bis.h b/openbsc/include/openbsc/v42bis.h index f13e5c5..0b97603 100644 --- a/openbsc/include/openbsc/v42bis.h +++ b/openbsc/include/openbsc/v42bis.h @@ -33,8 +33,12 @@ \section v42bis_page_sec_2 How does it work? */ +#include + #if !defined(_SPANDSP_V42BIS_H_) #define _SPANDSP_V42BIS_H_ + +#define SPAN_DECLARE(x) x #define V42BIS_MAX_BITS 12 #define V42BIS_MAX_CODEWORDS 4096 /* 2^V42BIS_MAX_BITS */ @@ -114,7 +118,8 @@ \param data_user_data An opaque pointer passed to the data callback handler. \param max_data_len The maximum length that should be passed to the data handler. \return The V.42bis context. */ -SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, +SPAN_DECLARE(v42bis_state_t *) v42bis_init(const void *ctx, + v42bis_state_t *s, int negotiated_p0, int negotiated_p1, int negotiated_p2, diff --git a/openbsc/include/openbsc/private_v42bis.h b/openbsc/include/openbsc/v42bis_private.h similarity index 100% rename from openbsc/include/openbsc/private_v42bis.h rename to openbsc/include/openbsc/v42bis_private.h diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 2910c02..f479d56 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -27,7 +27,7 @@ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ - slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c + slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c v42bis.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c index 894ce84..f01798b 100644 --- a/openbsc/src/gprs/sgsn_main.c +++ b/openbsc/src/gprs/sgsn_main.c @@ -297,6 +297,11 @@ .description = "RFC1144 TCP/IP Header compression (SLHC)", .enabled = 1, .loglevel = LOGL_DEBUG, }, + [DV42BIS] = { + .name = "DV42BIS", + .description = "V.42bis data compression (SNDCP)", + .enabled = 1, .loglevel = LOGL_DEBUG, + } }; static const struct log_info gprs_log_info = { diff --git a/openbsc/src/gprs/v42bis.c b/openbsc/src/gprs/v42bis.c index 6d38916..b8a886d 100644 --- a/openbsc/src/gprs/v42bis.c +++ b/openbsc/src/gprs/v42bis.c @@ -31,9 +31,8 @@ /*! \file */ -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif +#define FALSE 0 +#define TRUE 1 #include #include @@ -44,13 +43,11 @@ #include #include -#include "spandsp/telephony.h" -#include "spandsp/logging.h" -#include "spandsp/bit_operations.h" -#include "spandsp/v42bis.h" +#include +#include +#include +#include -#include "spandsp/private/logging.h" -#include "spandsp/private/v42bis.h" /* Fixed parameters from the spec. */ #define V42BIS_N3 8 /* Character size (bits) */ @@ -310,7 +307,7 @@ { if (ss->transparent) { - printf("Going compressed\n"); + DEBUGP(DV42BIS,"Going compressed\n"); /* 7.8.1 Transition to compressed mode */ /* Switch out of transparent now, between codes. We need to send the octet which did not match, just before switching. */ @@ -332,7 +329,7 @@ { if (!ss->transparent) { - printf("Going transparent\n"); + DEBUGP(DV42BIS,"Going transparent\n"); /* 7.8.2 Transition to transparent mode */ /* Switch into transparent now, between codes, and the unmatched octet should go out in transparent mode, just below */ @@ -401,7 +398,7 @@ { if (s->compress.dict[i].parent_code != 0xFFFF) { - printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); + DEBUGP(DV42BIS,"Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); } } return 0; @@ -454,13 +451,13 @@ ss->escaped = FALSE; if (code == V42BIS_ECM) { - printf("Hit V42BIS_ECM\n"); + DEBUGP(DV42BIS,"Hit V42BIS_ECM\n"); ss->transparent = FALSE; code_len = ss->v42bis_parm_c2; } else if (code == V42BIS_EID) { - printf("Hit V42BIS_EID\n"); + DEBUGP(DV42BIS,"Hit V42BIS_EID\n"); ss->output_buf[ss->output_octet_count++] = ss->escape_code - 1; if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) { @@ -470,11 +467,11 @@ } else if (code == V42BIS_RESET) { - printf("Hit V42BIS_RESET\n"); + DEBUGP(DV42BIS,"Hit V42BIS_RESET\n"); } else { - printf("Hit V42BIS_???? - %" PRIu32 "\n", code); + DEBUGP(DV42BIS,"Hit V42BIS_???? - %" PRIu32 "\n", code); } } else if (code == ss->escape_code) @@ -500,17 +497,17 @@ switch (new_code) { case V42BIS_ETM: - printf("Hit V42BIS_ETM\n"); + DEBUGP(DV42BIS,"Hit V42BIS_ETM\n"); ss->transparent = TRUE; code_len = 8; break; case V42BIS_FLUSH: - printf("Hit V42BIS_FLUSH\n"); + DEBUGP(DV42BIS,"Hit V42BIS_FLUSH\n"); v42bis_decompress_flush(s); break; case V42BIS_STEPUP: /* We need to increase the codeword size */ - printf("Hit V42BIS_STEPUP\n"); + DEBUGP(DV42BIS,"Hit V42BIS_STEPUP\n"); if (ss->v42bis_parm_c3 >= s->v42bis_parm_n2) { /* Invalid condition */ @@ -547,7 +544,7 @@ /* Trace back through the octets which form the string, and output them. */ while (code >= V42BIS_N5) { -if (code > 4095) {printf("Code is 0x%" PRIu32 "\n", code); exit(2);} +if (code > 4095) {DEBUGP(DV42BIS,"Code is 0x%" PRIu32 "\n", code); exit(2);} *string-- = ss->dict[code].node_octet; code = ss->dict[code].parent_code; } @@ -631,7 +628,7 @@ { if (s->decompress.dict[i].parent_code != 0xFFFF) { - printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); + DEBUGP(DV42BIS,"Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); } } return 0; @@ -654,7 +651,8 @@ } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, +SPAN_DECLARE(v42bis_state_t *) v42bis_init(const void *ctx, + v42bis_state_t *s, int negotiated_p0, int negotiated_p1, int negotiated_p2, @@ -673,7 +671,7 @@ return NULL; if (s == NULL) { - if ((s = (v42bis_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (v42bis_state_t *) talloc_zero_size(ctx,sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -735,7 +733,7 @@ SPAN_DECLARE(int) v42bis_free(v42bis_state_t *s) { - free(s); + talloc_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index d5aa356..7acebc0 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid slhc +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid slhc v42bis if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index 5f37b8e..f18b734 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -141,3 +141,9 @@ cat $abs_srcdir/slhc/slhc_test.ok > expout AT_CHECK([$abs_top_builddir/tests/slhc/slhc_test], [], [expout], [ignore]) AT_CLEANUP + +AT_SETUP([v42bis]) +AT_KEYWORDS([v42bis]) +cat $abs_srcdir/v42bis/v42bis_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/v42bis/v42bis_test], [], [expout], [ignore]) +AT_CLEANUP diff --git a/openbsc/tests/v42bis/Makefile.am b/openbsc/tests/v42bis/Makefile.am new file mode 100644 index 0000000..9001c0f --- /dev/null +++ b/openbsc/tests/v42bis/Makefile.am @@ -0,0 +1,21 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) + +EXTRA_DIST = v42bis_test.ok + +noinst_PROGRAMS = v42bis_test + +v42bis_test_SOURCES = v42bis_test.c + +v42bis_test_LDADD = \ + $(top_builddir)/src/gprs/v42bis.o \ + $(top_builddir)/src/libcommon/libcommon.a \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOGB_LIBS) \ + $(LIBCARES_LIBS) \ + $(LIBCRYPTO_LIBS) \ + -lgtp -lrt -lm + + diff --git a/openbsc/tests/v42bis/v42bis_test.c b/openbsc/tests/v42bis/v42bis_test.c new file mode 100644 index 0000000..9270139 --- /dev/null +++ b/openbsc/tests/v42bis/v42bis_test.c @@ -0,0 +1,191 @@ +/* Test v42bis Compression/Decompression */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#define BLOCK_SIZE 100 +#define MAX_BLOCK_SIZE 2048 + +/* A struct to capture the output data of compressor and decompressor */ +struct v42bis_output_buffer { + uint8_t *buf; + uint8_t *buf_pointer; + int len; +}; + +/* A simple testpattern generator */ +static void gen_test_pattern(uint8_t *data, int len) +{ + int i; + for (i = 0; i < len; i++) + data[i] = i & 0xF0; +} + +/* Handler to capture the output data from the compressor */ +void tx_v42bis_frame_handler(void *user_data, const uint8_t *pkt, int len) +{ + struct v42bis_output_buffer *output_buffer = + (struct v42bis_output_buffer *)user_data; + memcpy(output_buffer->buf_pointer, pkt, len); + output_buffer->buf_pointer += len; + output_buffer->len += len; + return; +} + +/* Handler to capture the output data from the decompressor */ +void tx_v42bis_data_handler(void *user_data, const uint8_t *buf, int len) +{ + /* stub */ + return; +} + +/* Handler to capture the output data from the compressor */ +void rx_v42bis_frame_handler(void *user_data, const uint8_t *pkt, int len) +{ + /* stub */ + return; +} + +/* Handler to capture the output data from the decompressor */ +void rx_v42bis_data_handler(void *user_data, const uint8_t *buf, int len) +{ + struct v42bis_output_buffer *output_buffer = + (struct v42bis_output_buffer *)user_data; + memcpy(output_buffer->buf_pointer, buf, len); + output_buffer->buf_pointer += len; + output_buffer->len += len; + return; +} + +/* Test V.42bis compression and decompression */ +static void test_v42bis(const void *ctx) +{ + v42bis_state_t *tx_state; + v42bis_state_t *rx_state; + + uint8_t uncompressed_original[BLOCK_SIZE]; + uint8_t compressed[BLOCK_SIZE]; + uint8_t uncompressed[BLOCK_SIZE]; + + int rc; + struct v42bis_output_buffer compressed_data; + struct v42bis_output_buffer uncompressed_data; + + /* Initalize */ + tx_state = + v42bis_init(ctx, NULL, 3, MAX_BLOCK_SIZE, 6, + &tx_v42bis_frame_handler, NULL, MAX_BLOCK_SIZE, + &tx_v42bis_data_handler, NULL, MAX_BLOCK_SIZE); + OSMO_ASSERT(tx_state); + rx_state = + v42bis_init(ctx, NULL, 3, MAX_BLOCK_SIZE, 6, + &rx_v42bis_frame_handler, NULL, MAX_BLOCK_SIZE, + &rx_v42bis_data_handler, NULL, MAX_BLOCK_SIZE); + OSMO_ASSERT(rx_state); + v42bis_compression_control(tx_state, V42BIS_COMPRESSION_MODE_ALWAYS); + v42bis_compression_control(rx_state, V42BIS_COMPRESSION_MODE_ALWAYS); + + /* Generate test pattern for input */ + gen_test_pattern(uncompressed_original, sizeof(uncompressed_original)); + + /* Run compressor */ + compressed_data.buf = compressed; + compressed_data.buf_pointer = compressed; + compressed_data.len = 0; + tx_state->compress.user_data = (&compressed_data); + rc = v42bis_compress(tx_state, uncompressed_original, + sizeof(uncompressed_original)); + OSMO_ASSERT(rc == 0); + rc = v42bis_compress_flush(tx_state); + OSMO_ASSERT(rc == 0); + + /* Decompress again */ + uncompressed_data.buf = uncompressed; + uncompressed_data.buf_pointer = uncompressed; + uncompressed_data.len = 0; + rx_state->decompress.user_data = (&uncompressed_data); + rc = v42bis_decompress(rx_state, compressed_data.buf, + compressed_data.len); + OSMO_ASSERT(rc == 0); + rc = v42bis_decompress_flush(rx_state); + OSMO_ASSERT(rc == 0); + + /* Check results */ + printf("uncompressed_original= %s\n", + osmo_hexdump_nospc(uncompressed_original, + sizeof(uncompressed_original))); + printf("uncompressed= %s\n", + osmo_hexdump_nospc(uncompressed_data.buf, + uncompressed_data.len)); + printf("compressed= %s\n", + osmo_hexdump_nospc(compressed_data.buf, compressed_data.len)); + rc = memcmp(uncompressed, uncompressed_original, BLOCK_SIZE); + OSMO_ASSERT(rc == 0); + + v42bis_free(tx_state); + v42bis_free(rx_state); +} + +static struct log_info_cat gprs_categories[] = { + [DV42BIS] = { + .name = "DV42BIS", + .description = "V.42bis data compression (SNDCP)", + .enabled = 1,.loglevel = LOGL_DEBUG, + } +}; + +static struct log_info info = { + .cat = gprs_categories, + .num_cat = ARRAY_SIZE(gprs_categories), +}; + +int main(int argc, char **argv) +{ + void *v42bis_ctx; + + osmo_init_logging(&info); + + v42bis_ctx = talloc_named_const(NULL, 0, "v42bis_ctx"); + + test_v42bis(v42bis_ctx); + printf("Done\n"); + + talloc_report_full(v42bis_ctx, stderr); + OSMO_ASSERT(talloc_total_blocks(v42bis_ctx) == 1); + return 0; +} + +/* stubs */ +struct osmo_prim_hdr; +int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) +{ + abort(); +} diff --git a/openbsc/tests/v42bis/v42bis_test.ok b/openbsc/tests/v42bis/v42bis_test.ok new file mode 100644 index 0000000..16c8612 --- /dev/null +++ b/openbsc/tests/v42bis/v42bis_test.ok @@ -0,0 +1,4 @@ +uncompressed_original= 00000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060 +uncompressed= 00000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060 +compressed= 0180e0703824120a1309c1e0f0884424462385c2e190c868cc670f87c4221112190e27138a4522a5329c5e2f188c464c6638d804 +Done -- To view, visit https://gerrit.osmocom.org/644 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d Gerrit-PatchSet: 23 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Thu Aug 18 17:13:13 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Thu, 18 Aug 2016 17:13:13 +0000 Subject: [PATCH] openbsc[master]: SLHC (RFC1144 header compression) integration and unit-test In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/635 to look at the new patch set (#12). SLHC (RFC1144 header compression) integration and unit-test The previously pushed slhc implementation has been modified to compile and function outside of the kernel. Also debug log messages were added and datatypes ware matched. The implementation is now ready to be used Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 --- M openbsc/.gitignore M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/debug.h R openbsc/include/openbsc/slhc.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/slhc.c M openbsc/tests/Makefile.am M openbsc/tests/sgsn/Makefile.am A openbsc/tests/slhc/Makefile.am A openbsc/tests/slhc/slhc_test.c A openbsc/tests/slhc/slhc_test.ok M openbsc/tests/testsuite.at 13 files changed, 546 insertions(+), 91 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/35/635/12 diff --git a/openbsc/.gitignore b/openbsc/.gitignore index 8ce3b70..e75b9eb 100644 --- a/openbsc/.gitignore +++ b/openbsc/.gitignore @@ -83,6 +83,7 @@ tests/mm_auth/mm_auth_test tests/xid/xid_test tests/sndcp_xid/sndcp_xid_test +tests/slhc/slhc_test tests/atconfig tests/atlocal diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 53072bd..18980b0 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -231,6 +231,7 @@ tests/mm_auth/Makefile tests/xid/Makefile tests/sndcp_xid/Makefile + tests/slhc/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index e200b05..f402fea 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,8 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h + gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ + slhc.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 43ebb19..90ddca5 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -29,6 +29,7 @@ DBSSGP, DLLC, DSNDCP, + DSLHC, DNAT, DCTRL, DSMPP, diff --git a/openbsc/include/openbsc/slhc_vj.h b/openbsc/include/openbsc/slhc.h similarity index 97% rename from openbsc/include/openbsc/slhc_vj.h rename to openbsc/include/openbsc/slhc.h index 8716d59..cd5a47c 100644 --- a/openbsc/include/openbsc/slhc_vj.h +++ b/openbsc/include/openbsc/slhc.h @@ -171,7 +171,8 @@ #define NULLSLCOMPR (struct slcompress *)0 /* In slhc.c: */ -struct slcompress *slhc_init(int rslots, int tslots); +struct slcompress *slhc_init(const void *ctx, int rslots, int tslots); + void slhc_free(struct slcompress *comp); int slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, @@ -180,4 +181,7 @@ int slhc_remember(struct slcompress *comp, unsigned char *icp, int isize); int slhc_toss(struct slcompress *comp); +void slhc_i_status(struct slcompress *comp); +void slhc_o_status(struct slcompress *comp); + #endif /* _SLHC_H */ diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index fa4a3dd..245636b 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -26,7 +26,8 @@ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ - oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c + oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ + slhc.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/slhc.c b/openbsc/src/gprs/slhc.c index 27ed252..cbdf8db 100644 --- a/openbsc/src/gprs/slhc.c +++ b/openbsc/src/gprs/slhc.c @@ -50,61 +50,77 @@ * driver code belonging close to PPP and SLIP */ -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#ifdef CONFIG_INET -/* Entire module is for IP only */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#define ERR_PTR(x) x + static unsigned char *encode(unsigned char *cp, unsigned short n); static long decode(unsigned char **cpp); static unsigned char * put16(unsigned char *cp, unsigned short x); static unsigned short pull16(unsigned char **cpp); +/* Replacement for kernel space function ip_fast_csum() */ +static uint16_t ip_fast_csum(uint8_t *iph, int ihl) +{ + int i; + uint16_t temp; + uint32_t accumulator = 0xFFFF; + + for(i=0;i0xFFFF) + { + accumulator++; + accumulator&=0xFFFF; + } + } + + return (uint16_t)(htons(~accumulator)&0xFFFF); +} + +/* Replacement for kernel space function put_unaligned() */ +static void put_unaligned(uint16_t val, void *ptr) +{ + memcpy(ptr,&val,sizeof(val)); +} + + /* Allocate compression data structure * slots must be in range 0 to 255 (zero meaning no compression) * Returns pointer to structure or ERR_PTR() on error. */ struct slcompress * -slhc_init(int rslots, int tslots) +slhc_init(const void *ctx, int rslots, int tslots) { register short i; register struct cstate *ts; struct slcompress *comp; if (rslots < 0 || rslots > 255 || tslots < 0 || tslots > 255) - return ERR_PTR(-EINVAL); + return NULL; - comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL); + comp = (struct slcompress *)talloc_zero_size(ctx,sizeof(struct slcompress)); if (! comp) goto out_fail; if (rslots > 0) { size_t rsize = rslots * sizeof(struct cstate); - comp->rstate = kzalloc(rsize, GFP_KERNEL); + comp->rstate = (struct cstate *) talloc_zero_size(ctx, rsize); if (! comp->rstate) goto out_free; comp->rslot_limit = rslots - 1; @@ -112,7 +128,7 @@ if (tslots > 0) { size_t tsize = tslots * sizeof(struct cstate); - comp->tstate = kzalloc(tsize, GFP_KERNEL); + comp->tstate = (struct cstate *) talloc_zero_size(ctx, tsize); if (! comp->tstate) goto out_free2; comp->tslot_limit = tslots - 1; @@ -141,11 +157,11 @@ return comp; out_free2: - kfree(comp->rstate); + talloc_free(comp->rstate); out_free: - kfree(comp); + talloc_free(comp); out_fail: - return ERR_PTR(-ENOMEM); + return NULL; } @@ -153,16 +169,18 @@ void slhc_free(struct slcompress *comp) { + DEBUGP(DSLHC, "slhc_free(): Freeing compression states...\n"); + if ( comp == NULLSLCOMPR ) return; if ( comp->tstate != NULLSLSTATE ) - kfree( comp->tstate ); + talloc_free(comp->tstate ); if ( comp->rstate != NULLSLSTATE ) - kfree( comp->rstate ); + talloc_free( comp->rstate ); - kfree( comp ); + talloc_free( comp ); } @@ -187,6 +205,8 @@ } else { *cp++ = n; } + + DEBUGP(DSLHC, "encode(): n=%04x\n",n); return cp; } @@ -256,6 +276,7 @@ comp->sls_o_nontcp++; else comp->sls_o_tcp++; + DEBUGP(DSLHC, "slhc_compress(): Not a TCP packat, will not touch...\n"); return isize; } /* Extract TCP header */ @@ -271,6 +292,7 @@ ! (th->ack)){ /* TCP connection stuff; send as regular IP */ comp->sls_o_tcp++; + DEBUGP(DSLHC, "slhc_compress(): Packet is part of a TCP connection, will not touch...\n"); return isize; } /* @@ -287,6 +309,9 @@ * states via linear search. If we don't find a state * for the datagram, the oldest state is (re-)used. */ + + DEBUGP(DSLHC, "slhc_compress(): Compressible packet detected!\n"); + for ( ; ; ) { if( ip->saddr == cs->cs_ip.saddr && ip->daddr == cs->cs_ip.daddr @@ -310,11 +335,14 @@ * state points to the newest and we only need to set * xmit_oldest to update the lru linkage. */ + + DEBUGP(DSLHC, "slhc_compress(): Header not yet seen, will memorize header for the next turn...\n"); comp->sls_o_misses++; comp->xmit_oldest = lcs->cs_this; goto uncompressed; found: + DEBUGP(DSLHC, "slhc_compress(): Header already seen, trying to compress...\n"); /* * Found it -- move to the front on the connection list. */ @@ -344,6 +372,39 @@ */ oth = &cs->cs_tcp; + /* Display a little more debug information about which of the + * header fields changed unexpectedly */ + if(ip->version != cs->cs_ip.version) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->version != cs->cs_ip.version\n"); + if(ip->ihl != cs->cs_ip.ihl) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->ihl != cs->cs_ip.ihl\n"); + if(ip->tos != cs->cs_ip.tos) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->tos != cs->cs_ip.tos\n"); + if((ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))\n"); + if(ip->ttl != cs->cs_ip.ttl) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->ttl != cs->cs_ip.ttl\n"); + if(th->doff != cs->cs_tcp.doff) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: th->doff != cs->cs_tcp.doff\n"); + if(ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) { + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0)\n"); + DEBUGP(DSLHC, "slhc_compress(): ip->ihl = %i\n", ip->ihl); + DEBUGP(DSLHC, "slhc_compress(): ip+1 = %s\n", + osmo_hexdump_nospc((uint8_t*)(ip+1),((ip->ihl)-5)*4)); + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: cs->cs_ipopt = %s\n", + osmo_hexdump_nospc((uint8_t*)(cs->cs_ipopt),((ip->ihl)-5)*4)); + } + if(th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0) { + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)\n"); + DEBUGP(DSLHC, "slhc_compress(): th->doff = %i\n", th->doff); + DEBUGP(DSLHC, "slhc_compress(): th+1 = %s\n", + osmo_hexdump_nospc((uint8_t*)(th+1),((th->doff)-5)*4)); + DEBUGP(DSLHC, "slhc_compress(): cs->cs_tcpopt = %s\n", + osmo_hexdump_nospc((uint8_t*)cs->cs_tcpopt, + ((th->doff)-5)*4)); + } + + if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl || ip->tos != cs->cs_ip.tos || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000)) @@ -351,6 +412,7 @@ || th->doff != cs->cs_tcp.doff || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){ + DEBUGP(DSLHC, "slhc_compress(): The header contains unexpected changes, can't compress...\n"); goto uncompressed; } @@ -362,6 +424,7 @@ */ if(th->urg){ deltaS = ntohs(th->urg_ptr); + DEBUGP(DSLHC, "slhc_compress(): flag: Urgent Pointer (U) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_U; } else if(th->urg_ptr != oth->urg_ptr){ @@ -369,21 +432,29 @@ * implementation should never do this but RFC793 * doesn't prohibit the change so we have to deal * with it. */ + DEBUGP(DSLHC, "slhc_compress(): URG not set but urp changed, can't compress...\n"); goto uncompressed; } if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){ + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Window (W) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_W; } if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){ - if(deltaA > 0x0000ffff) + if(deltaA > 0x0000ffff) { + DEBUGP(DSLHC, "slhc_compress(): (deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L, can't compress...\n"); goto uncompressed; + } + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Ack (A) = 1\n"); cp = encode(cp,deltaA); changes |= NEW_A; } if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){ - if(deltaS > 0x0000ffff) + if(deltaS > 0x0000ffff) { + DEBUGP(DSLHC, "slhc_compress(): (deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L, can't compress...\n"); goto uncompressed; + } + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_S; } @@ -399,17 +470,21 @@ if(ip->tot_len != cs->cs_ip.tot_len && ntohs(cs->cs_ip.tot_len) == hlen) break; + DEBUGP(DSLHC, "slhc_compress(): Retransmitted packet detected, can't compress...\n"); goto uncompressed; case SPECIAL_I: case SPECIAL_D: /* actual changes match one of our special case encodings -- * send packet uncompressed. */ + DEBUGP(DSLHC, "slhc_compress(): Special case detected, can't compress...\n"); goto uncompressed; case NEW_S|NEW_A: if(deltaS == deltaA && deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ /* special case for echoed terminal traffic */ + DEBUGP(DSLHC, "slhc_compress(): Special case for echoed terminal traffic detected...\n"); + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1, Delta Window (W) = 1, Urgent Pointer (U) = 1\n"); changes = SPECIAL_I; cp = new_seq; } @@ -417,6 +492,8 @@ case NEW_S: if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ /* special case for data xfer */ + DEBUGP(DSLHC, "slhc_compress(): Special case for data xfer detected...\n"); + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1, Delta Ack (A) = 1, Delta Window (W) = 1, Urgent Pointer (U) = 1\n"); changes = SPECIAL_D; cp = new_seq; } @@ -424,11 +501,14 @@ } deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id); if(deltaS != 1){ + DEBUGP(DSLHC, "slhc_compress(): flag: Delta IP ID (I) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_I; } - if(th->psh) + if(th->psh) { + DEBUGP(DSLHC, "slhc_compress(): flag: Push (P) = 1\n"); changes |= TCP_PUSH_BIT; + } /* Grab the cksum before we overwrite it below. Then update our * state with this packet's header. */ @@ -445,6 +525,7 @@ if(compress_cid == 0 || comp->xmit_current != cs->cs_this){ cp = ocp; *cpp = ocp; + DEBUGP(DSLHC, "slhc_compress(): flag: Connection number (C) = 1\n"); *cp++ = changes | NEW_C; *cp++ = cs->cs_this; comp->xmit_current = cs->cs_this; @@ -456,6 +537,10 @@ *(__sum16 *)cp = csum; cp += 2; /* deltaS is now the size of the change section of the compressed header */ + + DEBUGP(DSLHC, "slhc_compress(): Delta-list length (deltaS) = %li\n",deltaS); + DEBUGP(DSLHC, "slhc_compress(): Original header len (hlen) = %i\n",hlen); + memcpy(cp,new_seq,deltaS); /* Write list of deltas */ memcpy(cp+deltaS,icp+hlen,isize-hlen); comp->sls_o_compressed++; @@ -467,6 +552,7 @@ * to use on future compressed packets in the protocol field). */ uncompressed: + DEBUGP(DSLHC, "slhc_compress(): Packet will be sent uncompressed...\n"); memcpy(&cs->cs_ip,ip,20); memcpy(&cs->cs_tcp,th,20); if (ip->ihl > 5) @@ -538,6 +624,8 @@ switch(changes & SPECIALS_MASK){ case SPECIAL_I: /* Echoed terminal traffic */ + DEBUGP(DSLHC, "slhc_uncompress(): Echoed terminal traffic detected\n"); + { register short i; i = ntohs(ip->tot_len) - hdrlen; @@ -547,11 +635,13 @@ break; case SPECIAL_D: /* Unidirectional data */ + DEBUGP(DSLHC, "slhc_uncompress(): Unidirectional data detected\n"); thp->seq = htonl( ntohl(thp->seq) + ntohs(ip->tot_len) - hdrlen); break; default: + DEBUGP(DSLHC, "slhc_uncompress(): default packet type detected\n"); if(changes & NEW_U){ thp->urg = 1; if((x = decode(&cp)) == -1) { @@ -601,6 +691,7 @@ ip->tot_len = htons(len); ip->check = 0; + DEBUGP(DSLHC, "slhc_uncompress(): making space for the reconstructed header...\n"); memmove(icp + hdrlen, cp, len - hdrlen); cp = icp; @@ -625,6 +716,7 @@ return len; bad: + DEBUGP(DSLHC, "slhc_uncompress(): bad packet detected!\n"); comp->sls_i_error++; return slhc_toss( comp ); } @@ -641,6 +733,7 @@ if(isize < 20) { /* The packet is shorter than a legal IP header */ comp->sls_i_runt++; + DEBUGP(DSLHC, "slhc_remember(): The packet is shorter than a legal IP header ==> slhc_toss()\n"); return slhc_toss( comp ); } /* Peek at the IP header's IHL field to find its length */ @@ -648,6 +741,7 @@ if(ihl < 20 / 4){ /* The IP header length field is too small */ comp->sls_i_runt++; + DEBUGP(DSLHC, "slhc_remember(): The IP header length field is too small ==> slhc_toss()\n"); return slhc_toss( comp ); } index = icp[9]; @@ -656,10 +750,12 @@ if (ip_fast_csum(icp, ihl)) { /* Bad IP header checksum; discard */ comp->sls_i_badcheck++; + DEBUGP(DSLHC, "slhc_remember(): Bad IP header checksum; discard ==> slhc_toss()\n"); return slhc_toss( comp ); } if(index > comp->rslot_limit) { comp->sls_i_error++; + DEBUGP(DSLHC, "slhc_remember(): index > comp->rslot_limit ==> slhc_toss()\n"); return slhc_toss(comp); } @@ -683,6 +779,7 @@ int slhc_toss(struct slcompress *comp) { + DEBUGP(DSLHC, "slhc_toss(): Reset compression state...\n"); if ( comp == NULLSLCOMPR ) return 0; @@ -690,55 +787,27 @@ return 0; } -#else /* CONFIG_INET */ - -int -slhc_toss(struct slcompress *comp) +void slhc_i_status(struct slcompress *comp) { - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss"); - return -EINVAL; -} -int -slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress"); - return -EINVAL; -} -int -slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, - unsigned char *ocp, unsigned char **cpp, int compress_cid) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress"); - return -EINVAL; + if (comp != NULLSLCOMPR) { + DEBUGP(DSLHC, "slhc_i_status(): %d Cmp, %d Uncmp, %d Bad, %d Tossed\n", + comp->sls_i_compressed, + comp->sls_i_uncompressed, + comp->sls_i_error, + comp->sls_i_tossed); + } } -int -slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +void slhc_o_status(struct slcompress *comp) { - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember"); - return -EINVAL; + if (comp != NULLSLCOMPR) { + DEBUGP(DSLHC, "slhc_o_status(): %d Cmp, %d Uncmp, %d AsIs, %d NotTCP %d Searches, %d Misses\n", + comp->sls_o_compressed, + comp->sls_o_uncompressed, + comp->sls_o_tcp, + comp->sls_o_nontcp, + comp->sls_o_searches, + comp->sls_o_misses); + } } -void -slhc_free(struct slcompress *comp) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free"); -} -struct slcompress * -slhc_init(int rslots, int tslots) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init"); - return NULL; -} - -#endif /* CONFIG_INET */ - -/* VJ header compression */ -EXPORT_SYMBOL(slhc_init); -EXPORT_SYMBOL(slhc_free); -EXPORT_SYMBOL(slhc_remember); -EXPORT_SYMBOL(slhc_compress); -EXPORT_SYMBOL(slhc_uncompress); -EXPORT_SYMBOL(slhc_toss); - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index 1debb2d..d5aa356 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid slhc if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 45d1780..3e66978 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -32,6 +32,7 @@ $(top_builddir)/src/gprs/oap_messages.o \ $(top_builddir)/src/gprs/gprs_llc_xid.o \ $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ + $(top_builddir)/src/gprs/slhc.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ diff --git a/openbsc/tests/slhc/Makefile.am b/openbsc/tests/slhc/Makefile.am new file mode 100644 index 0000000..d21990f --- /dev/null +++ b/openbsc/tests/slhc/Makefile.am @@ -0,0 +1,21 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) + +EXTRA_DIST = slhc_test.ok + +noinst_PROGRAMS = slhc_test + +slhc_test_SOURCES = slhc_test.c + +slhc_test_LDADD = \ + $(top_builddir)/src/gprs/slhc.o \ + $(top_builddir)/src/libcommon/libcommon.a \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOGB_LIBS) \ + $(LIBCARES_LIBS) \ + $(LIBCRYPTO_LIBS) \ + -lgtp -lrt -lm + + diff --git a/openbsc/tests/slhc/slhc_test.c b/openbsc/tests/slhc/slhc_test.c new file mode 100644 index 0000000..9880bd8 --- /dev/null +++ b/openbsc/tests/slhc/slhc_test.c @@ -0,0 +1,298 @@ +/* Test SLHC/RFC1144 TCP/IP Header compression/decompression */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include +#include + +#include + +#include +#include +#include + +/* Number of compression slots (S0-1) */ +#define SLOTS 8 + +/* Maximum packet bytes to display */ +#define DISP_MAX_BYTES 100 + +/* Sample packets to test with */ +#define PACKETS_LEN 6 +char *packets[] = { + "4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27", + "4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0", + "4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01", + "4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01", + "4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a", + "4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20" +}; + +/* Compress a packet using Van Jacobson RFC1144 header compression */ +static int compress(uint8_t *data_o, uint8_t *data_i, int len, + struct slcompress *comp) +{ + uint8_t *comp_ptr; /* Not used */ + int compr_len; + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Run compressor */ + compr_len = slhc_compress(comp, data_i, len, data_o, &comp_ptr, 0); + return compr_len; +} + +/* Expand a packet using Van Jacobson RFC1144 header compression */ +static int expand(uint8_t *data_o, uint8_t *data_i, int len, + struct slcompress *comp) +{ + int data_decompressed_len; + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Handle an uncompressed packet (learn header information */ + if ((data_i[0] & SL_TYPE_UNCOMPRESSED_TCP) == SL_TYPE_UNCOMPRESSED_TCP) { + data_o[0] &= 0x4F; + data_decompressed_len = slhc_remember(comp, data_o, len); + return data_decompressed_len; + } + + /* Uncompress compressed packets */ + else if (data_o[0] & SL_TYPE_COMPRESSED_TCP) { + data_decompressed_len = slhc_uncompress(comp, data_o, len); + return data_decompressed_len; + } + + /* Regular or unknown packets will not be touched */ + return len; +} + +/* Calculate TCP/IP checksum */ +static uint16_t calc_ip_csum(uint8_t *data, int len) +{ + int i; + uint32_t accumulator = 0; + uint16_t *pointer = (uint16_t *) data; + + for (i = len; i > 1; i -= 2) { + accumulator += *pointer; + pointer++; + } + + if (len % 2) + accumulator += *pointer; + + accumulator = (accumulator & 0xffff) + ((accumulator >> 16) & 0xffff); + accumulator += (accumulator >> 16) & 0xffff; + return (~accumulator); +} + +/* Calculate TCP/IP checksum */ +static uint16_t calc_tcpip_csum(const void *ctx, uint8_t *packet, int len) +{ + uint8_t *buf; + uint16_t csum; + + buf = talloc_zero_size(ctx, len); + memset(buf, 0, len); + memcpy(buf, packet + 12, 8); + buf[9] = packet[9]; + buf[11] = (len - 20) & 0xFF; + buf[10] = (len - 20) >> 8 & 0xFF; + memcpy(buf + 12, packet + 20, len - 20); + csum = calc_ip_csum(buf, len - 20 + 12); + talloc_free(buf); + return csum; +} + +/* Check TCP/IP packet */ +static void check_packet(const void *ctx, uint8_t *packet, int len) +{ + /* Check IP header */ + OSMO_ASSERT(len > 20); + OSMO_ASSERT(calc_ip_csum(packet, 20) == 0); + + /* Check TCP packet */ + if (packet[9] != 0x06) + return; + OSMO_ASSERT(len > 40); + OSMO_ASSERT(calc_tcpip_csum(ctx, packet, len) == 0); +} + +/* Strip TCP options from TCP/IP packet */ +static int strip_tcp_options(const void *ctx, uint8_t *packet, int len) +{ + uint8_t doff; + uint16_t csum; + + /* Check if the packet can be handled here */ + if (len < 37) + return len; + if (packet[9] != 0x06) + return len; + + /* Strip TCP/IP options from packet */ + doff = ((packet[32] >> 4) & 0x0F) * 4; + memmove(packet + 40, packet + doff + 20, len - 40 - (doff - 20)); + len = len - (doff - 20); + + /* Repair data offset (TCP header length) */ + packet[32] &= 0x0F; + packet[32] |= 0x50; + + /* Repair checksum */ + packet[36] = 0; + packet[37] = 0; + csum = calc_tcpip_csum(ctx, packet, len); + packet[36] = csum & 0xFF; + packet[37] = csum >> 8 & 0xFF; + + /* Repair total length */ + packet[3] = len & 0xFF; + packet[2] = len >> 8 & 0xFF; + + /* Repair IP header checksum */ + packet[10] = 0; + packet[11] = 0; + csum = calc_ip_csum(packet, 20); + packet[10] = csum & 0xFF; + packet[11] = csum >> 8 & 0xFF; + printf("csum=%04x\n", csum); + + return len; +} + +/* Compress / Decompress packets */ +static void test_slhc(const void *ctx) +{ + char packet_ascii[2048]; + int i; + + struct slcompress *comp; + uint8_t packet[1024]; + int packet_len; + uint8_t packet_compr[1024]; + int packet_compr_len; + uint8_t packet_decompr[1024]; + int packet_decompr_len; + + printf("Allocating compression state...\n"); + comp = slhc_init(ctx, SLOTS, SLOTS); + OSMO_ASSERT(comp); + + for(i=0;i DISP_MAX_BYTES) + packet_compr_len = DISP_MAX_BYTES; + if (packet_len > DISP_MAX_BYTES) + packet_len = DISP_MAX_BYTES; + if (packet_decompr_len > DISP_MAX_BYTES) + packet_decompr_len = DISP_MAX_BYTES; + printf("Original Packet: (%i bytes) %s\n", packet_len, + osmo_hexdump_nospc(packet, packet_len)); + printf("DecompressedPacket: (%i bytes) %s\n", + packet_decompr_len, osmo_hexdump_nospc(packet_decompr, + packet_decompr_len)); + printf("CompressedPacket: (%i bytes) %s\n", packet_compr_len, + osmo_hexdump_nospc(packet_compr, packet_compr_len)); + slhc_o_status(comp); + slhc_o_status(comp); + + printf("\n"); + } + + printf("Freeing compression state...\n"); + slhc_free(comp); + printf("\n"); +} + +static struct log_info_cat gprs_categories[] = { + [DSNDCP] = { + .name = "DSNDCP", + .description = + "GPRS Sub-Network Dependent Control Protocol (SNDCP)", + .enabled = 1,.loglevel = LOGL_DEBUG, + }, + [DSLHC] = { + .name = "DSLHC", + .description = + "Van Jacobson RFC1144 TCP/IP header compression (SLHC)", + .enabled = 1,.loglevel = LOGL_DEBUG, + } +}; + +static struct log_info info = { + .cat = gprs_categories, + .num_cat = ARRAY_SIZE(gprs_categories), +}; + +int main(int argc, char **argv) +{ + void *ctx; + + osmo_init_logging(&info); + + ctx = talloc_named_const(NULL, 0, "slhc_ctx"); + + test_slhc(ctx); + + printf("Done\n"); + + talloc_report_full(ctx, stderr); + OSMO_ASSERT(talloc_total_blocks(ctx) == 1); + return 0; +} + +/* stubs */ +struct osmo_prim_hdr; +int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) +{ + abort(); +} diff --git a/openbsc/tests/slhc/slhc_test.ok b/openbsc/tests/slhc/slhc_test.ok new file mode 100644 index 0000000..636241d --- /dev/null +++ b/openbsc/tests/slhc/slhc_test.ok @@ -0,0 +1,52 @@ +Allocating compression state... +csum=b3a9 +Compressing... +Decompressing... +Results: +Original Packet: (52 bytes) 4510003446dd40004006a9b3c0a8646ec0a864640017ad8b81980100f3ac984d501800e371410000fffd18fffd20fffd23fffd27 +DecompressedPacket: (52 bytes) 4510003446dd40004006a9b3c0a8646ec0a864640017ad8b81980100f3ac984d501800e371410000fffd18fffd20fffd23fffd27 +CompressedPacket: (52 bytes) 7510003446dd40004000a9b3c0a8646ec0a864640017ad8b81980100f3ac984d501800e371410000fffd18fffd20fffd23fffd27 + +csum=97a9 +Compressing... +Decompressing... +Results: +Original Packet: (79 bytes) 4510004f46de40004006a997c0a8646ec0a864640017ad8b8198010cf3ac984d501800e3cda40000fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 +DecompressedPacket: (79 bytes) 4510004f46de40004006a997c0a8646ec0a864640017ad8b8198010cf3ac984d501800e3cda40000fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 +CompressedPacket: (43 bytes) df00cda4fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 + +csum=baa9 +Compressing... +Decompressing... +Results: +Original Packet: (43 bytes) 4510002b46df40004006a9bac0a8646ec0a864640017ad8b81980133f3ac989f501800e3a70a0000fffd01 +DecompressedPacket: (43 bytes) 4510002b46df40004006a9bac0a8646ec0a864640017ad8b81980133f3ac989f501800e3a70a0000fffd01 +CompressedPacket: (9 bytes) dc00a70a5227fffd01 + +csum=b9a9 +Compressing... +Decompressing... +Results: +Original Packet: (43 bytes) 4510002b46e040004006a9b9c0a8646ec0a864640017ad8b81980136f3ac98a2501800e3a7060000fffb01 +DecompressedPacket: (43 bytes) 4510002b46e040004006a9b9c0a8646ec0a864640017ad8b81980136f3ac98a2501800e3a7060000fffb01 +CompressedPacket: (7 bytes) db00a706fffb01 + +csum=7ba9 +Compressing... +Decompressing... +Results: +Original Packet: (100 bytes) 4510006846e140004006a97bc0a8646ec0a864640017ad8b81980139f3ac98a5501800e3c2d000000d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d +DecompressedPacket: (100 bytes) 4510006846e140004006a97bc0a8646ec0a864640017ad8b81980139f3ac98a5501800e3c2d000000d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d +CompressedPacket: (68 bytes) db00c2d00d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a + +csum=aca9 +Compressing... +Decompressing... +Results: +Original Packet: (54 bytes) 4510003646e240004006a9acc0a8646ec0a864640017ad8b81980179f3ac98a5501800e321fb0000706f6c6c7578206c6f67696e3a20 +DecompressedPacket: (54 bytes) 4510003646e240004006a9acc0a8646ec0a864640017ad8b81980179f3ac98a5501800e321fb0000706f6c6c7578206c6f67696e3a20 +CompressedPacket: (18 bytes) df0021fb706f6c6c7578206c6f67696e3a20 + +Freeing compression state... + +Done diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index 85a81d6..5f37b8e 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -136,3 +136,8 @@ AT_CHECK([$abs_top_builddir/tests/sndcp_xid/sndcp_xid_test], [], [expout], [ignore]) AT_CLEANUP +AT_SETUP([slhc]) +AT_KEYWORDS([slhc]) +cat $abs_srcdir/slhc/slhc_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/slhc/slhc_test], [], [expout], [ignore]) +AT_CLEANUP -- To view, visit https://gerrit.osmocom.org/635 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 Gerrit-PatchSet: 12 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Thu Aug 18 17:13:13 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Thu, 18 Aug 2016 17:13:13 +0000 Subject: [PATCH] openbsc[master]: Adding LLC-XID related modifications in LLC In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/652 to look at the new patch set (#13). Adding LLC-XID related modifications in LLC With this commit the already existing XID mechanism has been modified to suit the needs for the upcomming SNDCP-XID patches. This commit should not break anything since it does not alter the current behaviour (incoming XID is still just echoed, on GMM-Reset a basic XID message is still echoed) Change-Id: I65b9d625e72d3d61c99abdc7041773701d694d52 --- M openbsc/include/openbsc/gprs_llc.h M openbsc/src/gprs/gprs_llc.c M openbsc/tests/sgsn/Makefile.am 3 files changed, 309 insertions(+), 57 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/52/652/13 diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h index 0e497a0..c3b82b1 100644 --- a/openbsc/include/openbsc/gprs_llc.h +++ b/openbsc/include/openbsc/gprs_llc.h @@ -4,6 +4,7 @@ #include #include #include +#include /* Section 4.7 LLC Layer Structure */ enum gprs_llc_sapi { @@ -166,6 +167,13 @@ uint16_t nsei; struct gprs_llc_lle lle[NUM_SAPIS]; + /* Copy of the XID fields we have sent with the last + * network originated XID-Request. Since the phone + * may strip the optional fields in the confirmation + * we need to remeber those fields in order to be + * able to create the compression entity. */ + struct llist_head *xid; + /* Internal management */ uint32_t age_timestamp; }; @@ -219,6 +227,10 @@ int gprs_llgmm_reset_oldmsg(struct msgb* oldmsg, uint8_t sapi, struct gprs_llc_llme *llme); +/* Set of LL-XID negotiation (See also: TS 101 351, Section 7.2.2.4) */ +int gprs_ll_xid_req(struct gprs_llc_lle *lle, + struct gprs_llc_xid_field *l3_xid_field); + /* 04.64 Chapter 7.2.1.1 LLGMM-ASSIGN */ int gprs_llgmm_assign(struct gprs_llc_llme *llme, uint32_t old_tlli, uint32_t new_tlli); diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c index 7724ebb..79795d6 100644 --- a/openbsc/src/gprs/gprs_llc.c +++ b/openbsc/src/gprs/gprs_llc.c @@ -38,8 +38,280 @@ #include #include #include +#include +#include static struct gprs_llc_llme *llme_alloc(uint32_t tlli); +static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg, + int command); +static int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi, + int command, enum gprs_llc_u_cmd u_cmd, int pf_bit); + +/* BEGIN XID RELATED */ + +/* Generate XID message */ +static int gprs_llc_generate_xid(uint8_t *bytes, int bytes_len, + struct gprs_llc_xid_field *l3_xid_field, + struct gprs_llc_llme *llme) +{ + /* Note: Called by gprs_ll_xid_req() */ + + LLIST_HEAD(xid_fields); + + struct gprs_llc_xid_field xid_version; + struct gprs_llc_xid_field xid_n201u; + struct gprs_llc_xid_field xid_n201i; + + xid_version.type = GPRS_LLC_XID_T_VERSION; + xid_version.data = (uint8_t *) "\x00"; + xid_version.data_len = 1; + + xid_n201u.type = GPRS_LLC_XID_T_N201_U; + xid_n201u.data = (uint8_t *) "\x05\xf0"; + xid_n201u.data_len = 2; + + xid_n201i.type = GPRS_LLC_XID_T_N201_I; + xid_n201i.data = (uint8_t *) "\x05\xf0"; + xid_n201i.data_len = 2; + + /* Add locally managed XID Fields */ + llist_add(&xid_n201i.list, &xid_fields); + llist_add(&xid_n201u.list, &xid_fields); + llist_add(&xid_version.list, &xid_fields); + + /* Append layer 3 XID field (if present) */ + if (l3_xid_field) { + /* Enforce layer 3 XID type (just to be sure) */ + l3_xid_field->type = GPRS_LLC_XID_T_L3_PAR; + + /* Add Layer 3 XID field to the list */ + llist_add(&l3_xid_field->list, &xid_fields); + } + + llme->xid = gprs_llc_copy_xid(llme->xid, &xid_fields); + + return gprs_llc_compile_xid(bytes, bytes_len, &xid_fields); +} + +/* Generate XID message that will cause the GMM to reset */ +static int gprs_llc_generate_xid_for_gmm_reset(uint8_t *bytes, + int bytes_len, uint32_t iov_ui, + struct gprs_llc_llme *llme) +{ + /* Called by gprs_llgmm_reset() and + * gprs_llgmm_reset_oldmsg() */ + + LLIST_HEAD(xid_fields); + + struct gprs_llc_xid_field xid_reset; + struct gprs_llc_xid_field xid_iovui; + + /* First XID component must be RESET */ + xid_reset.type = GPRS_LLC_XID_T_RESET; + xid_reset.data = NULL; + xid_reset.data_len = 0; + + /* Add new IOV-UI */ + xid_iovui.type = GPRS_LLC_XID_T_IOV_UI; + xid_iovui.data = (uint8_t *) & iov_ui; + xid_iovui.data_len = 4; + + /* Add locally managed XID Fields */ + llist_add(&xid_iovui.list, &xid_fields); + llist_add(&xid_reset.list, &xid_fields); + + llme->xid = gprs_llc_copy_xid(llme->xid, &xid_fields); + + return gprs_llc_compile_xid(bytes, bytes_len, &xid_fields); +} + +/* Process an incoming XID confirmation */ +static int gprs_llc_process_xid_conf(uint8_t *bytes, int bytes_len, + struct gprs_llc_lle *lle) +{ + /* Note: This function handles the response of a network originated + * XID-Request. There XID messages reflected by the phone are analyzed + * and processed here. The caller is called by rx_llc_xid(). */ + + struct llist_head *xid_fields; + struct gprs_llc_xid_field *xid_field; + + /* Parse and analyze XID-Response */ + xid_fields = gprs_llc_parse_xid(NULL, bytes, bytes_len); + + if (xid_fields) { + + gprs_llc_dump_xid_fields(xid_fields, LOGL_DEBUG); + llist_for_each_entry(xid_field, xid_fields, list) { + + /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { + LOGP(DLLC, LOGL_NOTICE, + "Ignoring SNDCP-XID-Field: XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + xid_field->data); + } + + /* Process LLC-XID fields: */ + else { + + /* FIXME: Do something more useful with the + * echoed XID-Information. Currently we + * just ignore the response completely and + * by doing so we blindly accept any changes + * the MS might have done to the our XID + * inquiry. There is a remainig risk of + * malfunction! */ + LOGP(DLLC, LOGL_NOTICE, + "Ignoring XID-Field: XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + xid_field->data); + } + } + talloc_free(xid_fields); + } + + /* Flush pending XID fields */ + talloc_free(lle->llme->xid); + lle->llme->xid = NULL; + + return 0; +} + +/* Process an incoming XID indication and generate an appropiate response */ +static int gprs_llc_process_xid_ind(uint8_t *bytes_request, + int bytes_request_len, + uint8_t *bytes_response, + int bytes_response_maxlen, + struct gprs_llc_lle *lle) +{ + /* Note: This function computes the response that is sent back to the + * phone when a phone originated XID is received. The function is + * called by rx_llc_xid() */ + + int rc = -EINVAL; + + struct llist_head *xid_fields; + struct llist_head *xid_fields_response; + + struct gprs_llc_xid_field *xid_field; + struct gprs_llc_xid_field *xid_field_response; + + /* Flush eventually pending XID fields */ + talloc_free(lle->llme->xid); + lle->llme->xid = NULL; + + /* Parse and analyze XID-Request */ + xid_fields = + gprs_llc_parse_xid(lle->llme, bytes_request, bytes_request_len); + if (xid_fields) { + xid_fields_response = talloc_zero(lle->llme, struct llist_head); + INIT_LLIST_HEAD(xid_fields_response); + gprs_llc_dump_xid_fields(xid_fields, LOGL_DEBUG); + + /* Process LLC-XID fields: */ + llist_for_each_entry(xid_field, xid_fields, list) { + + if (xid_field->type != GPRS_LLC_XID_T_L3_PAR) { + /* FIXME: Check the incoming XID parameters for + * for validity. Currently we just blindly + * accept all XID fields by just echoing them. + * There is a remaining risk of malfunction + * when a phone submits values which defer from + * the default! */ + LOGP(DLLC, LOGL_NOTICE, + "Echoing XID-Field: XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + osmo_hexdump_nospc(xid_field->data, + xid_field->data_len)); + xid_field_response = + gprs_llc_dup_xid_field + (lle->llme, xid_field); + llist_add(&xid_field_response->list, + xid_fields_response); + } + } + + rc = gprs_llc_compile_xid(bytes_response, + bytes_response_maxlen, + xid_fields_response); + talloc_free(xid_fields_response); + talloc_free(xid_fields); + } + + return rc; +} + +/* Dispatch XID indications and responses comming from the Phone */ +static void rx_llc_xid(struct gprs_llc_lle *lle, + struct gprs_llc_hdr_parsed *gph) +{ + uint8_t response[1024]; + int response_len; + + /* FIXME: 8.5.3.3: check if XID is invalid */ + if (gph->is_cmd) { + LOGP(DLLC, LOGL_NOTICE, + "Received XID indication from phone.\n"); + + struct msgb *resp; + uint8_t *xid; + resp = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + + response_len = + gprs_llc_process_xid_ind(gph->data, gph->data_len, + response, sizeof(response), + lle); + xid = msgb_put(resp, response_len); + memcpy(xid, response, response_len); + + gprs_llc_tx_xid(lle, resp, 0); + } else { + LOGP(DLLC, LOGL_NOTICE, + "Received XID confirmation from phone.\n"); + gprs_llc_process_xid_conf(gph->data, gph->data_len, lle); + /* FIXME: if we had sent a XID reset, send + * LLGMM-RESET.conf to GMM */ + } +} + + +/* Set of LL-XID negotiation (See also: TS 101 351, Section 7.2.2.4) */ +int gprs_ll_xid_req(struct gprs_llc_lle *lle, + struct gprs_llc_xid_field *l3_xid_field) +{ + /* Note: This functions is calle from gprs_sndcp.c */ + + uint8_t xid_bytes[1024];; + int xid_bytes_len; + uint8_t *xid; + struct msgb *msg; + + /* Generate XID */ + xid_bytes_len = + gprs_llc_generate_xid(xid_bytes, sizeof(xid_bytes), + l3_xid_field, lle->llme); + + /* Only perform XID sending if the XID message contains something */ + if (xid_bytes_len > 0) { + /* Transmit XID bytes */ + msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); + LOGP(DLLC, LOGL_NOTICE, "Sending XID request to phone...\n"); + gprs_llc_tx_xid(lle, msg, 1); + } else { + LOGP(DLLC, LOGL_ERROR, + "XID-Message generation failed, XID not sent!\n"); + return -EINVAL; + } + + return 0; +} +/* END XID RELATED */ + + + /* Entry function from upper level (LLC), asking us to transmit a BSSGP PDU * to a remote MS (identified by TLLI) at a BTS identified by its BVCI and NSEI */ @@ -51,7 +323,7 @@ memset(&dup, 0, sizeof(dup)); /* before we have received some identity from the MS, we might * not yet have a MMC context (e.g. XID negotiation of primarly - * LLC connection fro GMM sapi). */ + * LLC connection from GMM sapi). */ if (mmctx) { dup.imsi = mmctx->imsi; dup.drx_parms = mmctx->drx_parms; @@ -251,6 +523,7 @@ static void llme_free(struct gprs_llc_llme *llme) { + talloc_free(llme->xid); llist_del(&llme->list); talloc_free(llme); } @@ -464,54 +737,6 @@ /* Send BSSGP-DL-UNITDATA.req */ return _bssgp_tx_dl_ud(msg, mmctx); -} - -/* According to 6.4.1.6 / Figure 11 */ -static int msgb_put_xid_par(struct msgb *msg, uint8_t type, uint8_t length, uint8_t *data) -{ - uint8_t header_len = 1; - uint8_t *cur; - - /* type is a 5-bit field... */ - if (type > 0x1f) - return -EINVAL; - - if (length > 3) - header_len = 2; - - cur = msgb_put(msg, length + header_len); - - /* build the header without or with XL bit */ - if (length <= 3) { - *cur++ = (type << 2) | (length & 3); - } else { - *cur++ = 0x80 | (type << 2) | (length >> 6); - *cur++ = (length << 2); - } - - /* copy over the payload of the parameter*/ - memcpy(cur, data, length); - - return length + header_len; -} - -static void rx_llc_xid(struct gprs_llc_lle *lle, - struct gprs_llc_hdr_parsed *gph) -{ - /* FIXME: 8.5.3.3: check if XID is invalid */ - if (gph->is_cmd) { - /* FIXME: implement XID negotiation using SNDCP */ - struct msgb *resp; - uint8_t *xid; - resp = msgb_alloc_headroom(4096, 1024, "LLC_XID"); - xid = msgb_put(resp, gph->data_len); - memcpy(xid, gph->data, gph->data_len); - gprs_llc_tx_xid(lle, resp, 0); - } else { - /* FIXME: if we had sent a XID reset, send - * LLGMM-RESET.conf to GMM */ - /* FIXME: implement XID negotiation using SNDCP */ - } } static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph, @@ -784,17 +1009,24 @@ { struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); struct gprs_llc_lle *lle = &llme->lle[1]; + uint8_t xid_bytes[1024]; + int xid_bytes_len; + uint8_t *xid; + LOGP(DLLC, LOGL_NOTICE, "LLGM Reset\n"); if (RAND_bytes((uint8_t *) &llme->iov_ui, 4) != 1) { LOGP(DLLC, LOGL_NOTICE, "RAND_bytes failed for LLC XID reset, " "falling back to rand()\n"); llme->iov_ui = rand(); } - /* First XID component must be RESET */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL); - /* randomly select new IOV-UI */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &llme->iov_ui); + /* Generate XID message */ + xid_bytes_len = gprs_llc_generate_xid_for_gmm_reset(xid_bytes, + sizeof(xid_bytes),llme->iov_ui,llme); + if(xid_bytes_len < 0) + return -EINVAL; + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); /* Reset some of the LLC parameters. See GSM 04.64, 8.5.3.1 */ lle->vu_recv = 0; @@ -810,17 +1042,24 @@ struct gprs_llc_llme *llme) { struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + uint8_t xid_bytes[1024]; + int xid_bytes_len; + uint8_t *xid; + LOGP(DLLC, LOGL_NOTICE, "LLGM Reset\n"); if (RAND_bytes((uint8_t *) &llme->iov_ui, 4) != 1) { LOGP(DLLC, LOGL_NOTICE, "RAND_bytes failed for LLC XID reset, " "falling back to rand()\n"); llme->iov_ui = rand(); } - /* First XID component must be RESET */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL); - /* randomly select new IOV-UI */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &llme->iov_ui); + /* Generate XID message */ + xid_bytes_len = gprs_llc_generate_xid_for_gmm_reset(xid_bytes, + sizeof(xid_bytes),llme->iov_ui,llme); + if(xid_bytes_len < 0) + return -EINVAL; + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); /* FIXME: Start T200, wait for XID response */ diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index b6036c7..74af159 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -30,6 +30,7 @@ $(top_builddir)/src/gprs/gprs_gb_parse.o \ $(top_builddir)/src/gprs/oap.o \ $(top_builddir)/src/gprs/oap_messages.o \ + $(top_builddir)/src/gprs/gprs_llc_xid.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ -- To view, visit https://gerrit.osmocom.org/652 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I65b9d625e72d3d61c99abdc7041773701d694d52 Gerrit-PatchSet: 13 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max From gerrit-no-reply at lists.osmocom.org Thu Aug 18 17:13:13 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Thu, 18 Aug 2016 17:13:13 +0000 Subject: [PATCH] openbsc[master]: Adding LLC-XID encoder / decoder and unit test In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/638 to look at the new patch set (#9). Adding LLC-XID encoder / decoder and unit test The lle-xid encoder/decoder is needed to encode and decode llc xid parameter messages. We need this to exchange sndcp-parameters (SNDCP-XID) and also simple parameters such as encryption IOVs Change-Id: Ia06e4cb08bf9b48c2a4682606d1b1a91d19a9d37 --- M openbsc/.gitignore M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_llc_xid.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_llc_xid.c M openbsc/tests/Makefile.am M openbsc/tests/testsuite.at A openbsc/tests/xid/Makefile.am A openbsc/tests/xid/xid_test.c A openbsc/tests/xid/xid_test.ok 11 files changed, 532 insertions(+), 3 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/38/638/9 diff --git a/openbsc/.gitignore b/openbsc/.gitignore index 0a2965d..518a960 100644 --- a/openbsc/.gitignore +++ b/openbsc/.gitignore @@ -81,6 +81,7 @@ tests/oap/oap_test tests/gtphub/gtphub_test tests/mm_auth/mm_auth_test +tests/xid/xid_test tests/atconfig tests/atlocal diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 0980413..fbf2930 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -229,6 +229,7 @@ tests/oap/Makefile tests/gtphub/Makefile tests/mm_auth/Makefile + tests/xid/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index c272b14..11f650d 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,7 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h + gtphub.h gprs_llc_xid.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_llc_xid.h b/openbsc/include/openbsc/gprs_llc_xid.h new file mode 100644 index 0000000..d340d40 --- /dev/null +++ b/openbsc/include/openbsc/gprs_llc_xid.h @@ -0,0 +1,57 @@ +/* GPRS LLC XID field encoding/decoding as per 3GPP TS 44.064 */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include + +/* 3GPP TS 44.064 6.4.1.6 Exchange Identification (XID) + command/response parameter field */ +struct gprs_llc_xid_field { + struct llist_head list; + uint8_t type; /* See also Table 6: LLC layer parameter + negotiation */ + uint8_t *data; /* Payload data (memory is owned by the + * creator of the struct) */ + unsigned int data_len; /* Payload length */ +}; + +/* Transform a list with XID fields into a XID message (dst) */ +int gprs_llc_compile_xid(uint8_t *dst, int dst_maxlen, + const struct llist_head *xid_fields); + +/* Transform a XID message (dst) into a list of XID fields */ +struct llist_head *gprs_llc_parse_xid(const void *ctx, const uint8_t *src, + int src_len); + +/* Create a duplicate of an XID-Field */ +struct gprs_llc_xid_field *gprs_llc_dup_xid_field(const void *ctx, + const struct gprs_llc_xid_field *xid_field); + +/* Copy an llist with xid fields */ +struct llist_head *gprs_llc_copy_xid(const void *ctx, + const struct llist_head *xid_fields); + +/* Dump a list with XID fields (Debug) */ +void gprs_llc_dump_xid_fields(const struct llist_head *xid_fields, + unsigned int logl); + diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 6dc7e16..8cbdd91 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -28,7 +28,7 @@ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ - oap.c oap_messages.c + oap.c oap_messages.c gprs_llc_xid.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/gprs_llc_xid.c b/openbsc/src/gprs/gprs_llc_xid.c new file mode 100644 index 0000000..1e6ddf3 --- /dev/null +++ b/openbsc/src/gprs/gprs_llc_xid.c @@ -0,0 +1,268 @@ +/* GPRS LLC XID field encoding/decoding as per 3GPP TS 44.064 */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Parse XID parameter field */ +static int decode_xid_field(struct gprs_llc_xid_field *xid_field, + const uint8_t *src, uint8_t src_len) +{ + uint8_t xl; + uint8_t type; + uint8_t len; + int src_counter = 0; + + OSMO_ASSERT(xid_field); + OSMO_ASSERT(src); + + /* Exit immediately if it is clear that no + * parseable data is present */ + if (src_len < 1 || !src) + return -EINVAL; + + /* Extract header info */ + xl = (*src >> 7) & 1; + type = (*src >> 2) & 0x1F; + + /* Extract length field */ + len = (*src) & 0x3; + src++; + src_counter++; + if (xl) { + if (src_len < 2) + return -EINVAL; + len = (len << 6) & 0xC0; + len |= ((*src) >> 2) & 0x3F; + src++; + src_counter++; + } + + /* Fill out struct */ + xid_field->type = type; + xid_field->data_len = len; + if (len > 0) { + if (src_len < src_counter + len) + return -EINVAL; + xid_field->data = + talloc_memdup(xid_field,src,xid_field->data_len); + } else + xid_field->data = NULL; + + /* Return consumed length */ + return src_counter + len; +} + +/* Encode XID parameter field */ +static int encode_xid_field(uint8_t *dst, int dst_maxlen, + const struct gprs_llc_xid_field *xid_field) +{ + int xl = 0; + + OSMO_ASSERT(xid_field); + OSMO_ASSERT(dst); + + /* When the length does not fit into 2 bits, + * we need extended length fields */ + if (xid_field->data_len > 3) + xl = 1; + + /* Exit immediately if it is clear that no + * encoding result can be stored */ + if (dst_maxlen < xid_field->data_len + 1 + xl) + return -EINVAL; + + /* There are only 5 bits reserved for the type, exit on exceed */ + if (xid_field->type > 31) + return -EINVAL; + + /* Encode header */ + memset(dst, 0, dst_maxlen); + if (xl) + dst[0] |= 0x80; + dst[0] |= (((xid_field->type) & 0x1F) << 2); + + if (xl) { + dst[0] |= (((xid_field->data_len) >> 6) & 0x03); + dst[1] = ((xid_field->data_len) << 2) & 0xFC; + } else + dst[0] |= ((xid_field->data_len) & 0x03); + + /* Append payload data */ + if (xid_field->data && xid_field->data_len) + memcpy(dst + 1 + xl, xid_field->data, xid_field->data_len); + + /* Return generated length */ + return xid_field->data_len + 1 + xl; +} + +/* Transform a list with XID fields into a XID message (dst) */ +int gprs_llc_compile_xid(uint8_t *dst, int dst_maxlen, + const struct llist_head *xid_fields) +{ + struct gprs_llc_xid_field *xid_field; + int rc; + int byte_counter = 0; + + OSMO_ASSERT(xid_fields); + OSMO_ASSERT(dst); + + llist_for_each_entry_reverse(xid_field, xid_fields, list) { + /* Encode XID-Field */ + rc = encode_xid_field(dst, dst_maxlen, xid_field); + if (rc < 0) + return -EINVAL; + + /* Advance pointer and lower maxlen for the + * next encoding round */ + dst += rc; + byte_counter += rc; + dst_maxlen -= rc; + } + + /* Return generated length */ + return byte_counter; +} + +/* Transform a XID message (dst) into a list of XID fields */ +struct llist_head *gprs_llc_parse_xid(const void *ctx, const uint8_t *src, + int src_len) +{ + struct gprs_llc_xid_field *xid_field; + struct llist_head *xid_fields; + + int rc; + int max_loops = src_len; + + OSMO_ASSERT(src); + + xid_fields = talloc_zero(ctx, struct llist_head); + INIT_LLIST_HEAD(xid_fields); + + while (1) { + /* Bail in case decode_xid_field() constantly returns zero */ + if (max_loops <= 0) { + talloc_free(xid_fields); + return NULL; + } + + /* Decode XID field */ + xid_field = talloc_zero(xid_fields, struct gprs_llc_xid_field); + rc = decode_xid_field(xid_field, src, src_len); + + /* Immediately stop on error */ + if (rc < 0) { + talloc_free(xid_fields); + return NULL; + } + + /* Add parsed XID field to list */ + llist_add(&xid_field->list, xid_fields); + + /* Advance pointer and lower dst_len for the next + * decoding round */ + src += rc; + src_len -= rc; + + /* We are (scuccessfully) done when no further byes are left */ + if (src_len == 0) + return xid_fields; + + max_loops--; + } +} + +/* Create a duplicate of an XID-Field */ +struct gprs_llc_xid_field *gprs_llc_dup_xid_field(const void *ctx, const struct + gprs_llc_xid_field + *xid_field) +{ + struct gprs_llc_xid_field *dup; + + OSMO_ASSERT(xid_field); + + /* Create a copy of the XID field in memory */ + dup = talloc_memdup(ctx, xid_field, sizeof(*xid_field)); + dup->data = talloc_memdup(ctx, xid_field->data, xid_field->data_len); + + /* Unlink duplicate from source list */ + INIT_LLIST_HEAD(&dup->list); + + return dup; +} + +/* Copy an llist with xid fields */ +struct llist_head *gprs_llc_copy_xid(const void *ctx, + const struct llist_head *xid_fields) +{ + struct gprs_llc_xid_field *xid_field; + struct llist_head *xid_fields_copy; + + OSMO_ASSERT(xid_fields); + + xid_fields_copy = talloc_zero(ctx, struct llist_head); + INIT_LLIST_HEAD(xid_fields_copy); + + /* Create duplicates and add them to the target list */ + llist_for_each_entry(xid_field, xid_fields, list) { + llist_add(&gprs_llc_dup_xid_field(ctx, xid_field)->list, + xid_fields_copy); + } + + return xid_fields_copy; +} + +/* Dump a list with XID fields (Debug) */ +void gprs_llc_dump_xid_fields(const struct llist_head *xid_fields, + unsigned int logl) +{ + struct gprs_llc_xid_field *xid_field; + + OSMO_ASSERT(xid_fields); + + llist_for_each_entry(xid_field, xid_fields, list) { + if (xid_field->data_len) { + OSMO_ASSERT(xid_field->data); + LOGP(DLLC, logl, + "XID: type=%d, data_len=%d, data=%s\n", + xid_field->type, xid_field->data_len, + osmo_hexdump_nospc(xid_field->data, + xid_field->data_len)); + } else { + LOGP(DLLC, logl, + "XID: type=%d, data_len=%d, data=NULL\n", + xid_field->type, xid_field->data_len); + } + } +} diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index 09298a3..ba5ca28 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index dab9568..6470ab9 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -124,3 +124,8 @@ AT_CHECK([$abs_top_builddir/tests/mm_auth/mm_auth_test], [], [expout], [ignore]) AT_CLEANUP +AT_SETUP([xid]) +AT_KEYWORDS([xid]) +cat $abs_srcdir/xid/xid_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/xid/xid_test], [], [expout], [ignore]) +AT_CLEANUP diff --git a/openbsc/tests/xid/Makefile.am b/openbsc/tests/xid/Makefile.am new file mode 100644 index 0000000..9b64965 --- /dev/null +++ b/openbsc/tests/xid/Makefile.am @@ -0,0 +1,21 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) + +EXTRA_DIST = xid_test.ok + +noinst_PROGRAMS = xid_test + +xid_test_SOURCES = xid_test.c + +xid_test_LDADD = \ + $(top_builddir)/src/gprs/gprs_llc_xid.o \ + $(top_builddir)/src/libcommon/libcommon.a \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOGB_LIBS) \ + $(LIBCARES_LIBS) \ + $(LIBCRYPTO_LIBS) \ + -lgtp -lrt -lm + + diff --git a/openbsc/tests/xid/xid_test.c b/openbsc/tests/xid/xid_test.c new file mode 100644 index 0000000..b77a4ae --- /dev/null +++ b/openbsc/tests/xid/xid_test.c @@ -0,0 +1,164 @@ +/* Test LLC-XID Encoding/Decoding */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include +#include + +#include + +#include +#include + +/* Test XID encoding */ +static void test_xid_encode(const void *ctx) +{ + struct gprs_llc_xid_field xid_field_1; + struct gprs_llc_xid_field xid_field_2; + struct gprs_llc_xid_field xid_field_3; + struct gprs_llc_xid_field xid_field_4; + LLIST_HEAD(xid_fields); + uint8_t xid[255]; + uint8_t xid_expected[] = + { 0x10, 0x8c, 0x14, 0x43, 0x43, 0x43, 0x43, 0x43, 0x0b, 0x42, 0x42, + 0x42, 0x05, 0x41 }; + int rc; + + printf("Testing LLC XID-Encoder\n"); + + /* Setup some simple XID data */ + xid_field_1.type = 1; + xid_field_2.type = 2; + xid_field_3.type = 3; + xid_field_4.type = 4; + + xid_field_1.data = (uint8_t *) "A"; + xid_field_2.data = (uint8_t *) "BBB"; + xid_field_3.data = (uint8_t *) "CCCCC"; + xid_field_4.data = NULL; + + xid_field_1.data_len = 1; + xid_field_2.data_len = 3; + xid_field_3.data_len = 5; + xid_field_4.data_len = 0; + + llist_add(&xid_field_4.list, &xid_fields); + llist_add(&xid_field_3.list, &xid_fields); + llist_add(&xid_field_2.list, &xid_fields); + llist_add(&xid_field_1.list, &xid_fields); + + printf("Data to encode:\n"); + gprs_llc_dump_xid_fields(&xid_fields, DSNDCP); + + /* Encode data */ + rc = gprs_llc_compile_xid(xid, sizeof(xid), &xid_fields); + OSMO_ASSERT(rc == 14); + printf("Encoded: %s (%i bytes)\n", osmo_hexdump_nospc(xid, rc), rc); + printf("Expected: %s (%i bytes)\n", + osmo_hexdump_nospc(xid_expected, sizeof(xid_expected)), + (int)sizeof(xid_expected)); + + OSMO_ASSERT(memcmp(xid_expected, xid, sizeof(xid_expected)) == 0); + + printf("\n"); +} + +/* Test XID decoding */ +static void test_xid_decode(const void *ctx) +{ + struct llist_head *xid_fields; + int rc; + + printf("Testing LLC XID-Decoder/Encoder\n"); + + /* Example of a real world LLC-XID message */ + uint8_t xid[] = + { 0x01, 0x00, 0x16, 0x05, 0xf0, 0x1a, 0x05, 0xf0, 0xac, 0xd8, 0x00, + 0x01, 0x00, 0x02, 0x31, 0x82, 0x02, 0x27, 0x89, 0xff, 0xe0, 0x00, 0x0f, + 0x00, 0xa8, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x01, 0x02, + 0x00, 0x03, 0x01, 0x03, 0x00, 0x04, 0x01, 0x04, 0x00, 0x05, 0x01, 0x05, + 0x00, 0x06, 0x00, 0x07, 0x01, 0x07, 0x00, 0x08, 0x01, 0x08, 0x80, 0x00, + 0x04, 0x12, 0x00, 0x40, 0x07 }; + + uint8_t xid_r[512]; + + /* Decode and display XID fields */ + xid_fields = gprs_llc_parse_xid(ctx, xid, sizeof(xid)); + OSMO_ASSERT(xid_fields); + + printf("Decoded:\n"); + gprs_llc_dump_xid_fields(xid_fields, DSNDCP); + + + /* Encode xid-fields again */ + rc = gprs_llc_compile_xid(xid_r, sizeof(xid_r), xid_fields); + printf("Result length=%i\n",rc); + printf("Encoded: %s\n", osmo_hexdump_nospc(xid, sizeof(xid))); + printf("Rencoded: %s\n", osmo_hexdump_nospc(xid_r, rc)); + + OSMO_ASSERT(rc == 64); + OSMO_ASSERT(memcmp(xid, xid_r, sizeof(xid)) == 0); + + /* Free xid fields */ + talloc_free(xid_fields); + + printf("\n"); +} + +static struct log_info_cat gprs_categories[] = { + [DSNDCP] = { + .name = "DSNDCP", + .description = + "GPRS Sub-Network Dependent Control Protocol (SNDCP)", + .enabled = 1,.loglevel = LOGL_DEBUG, + } +}; + +static struct log_info info = { + .cat = gprs_categories, + .num_cat = ARRAY_SIZE(gprs_categories), +}; + +int main(int argc, char **argv) +{ + void *xid_ctx; + + osmo_init_logging(&info); + + xid_ctx = talloc_named_const(NULL, 0, "xid_ctx"); + + test_xid_decode(xid_ctx); + test_xid_encode(xid_ctx); + printf("Done\n"); + + talloc_report_full(xid_ctx, stderr); + OSMO_ASSERT(talloc_total_blocks(xid_ctx) == 1); + return 0; +} + +/* stubs */ +struct osmo_prim_hdr; +int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) +{ + abort(); +} diff --git a/openbsc/tests/xid/xid_test.ok b/openbsc/tests/xid/xid_test.ok new file mode 100644 index 0000000..4cf825c --- /dev/null +++ b/openbsc/tests/xid/xid_test.ok @@ -0,0 +1,12 @@ +Testing LLC XID-Decoder/Encoder +Decoded: +Result length=64 +Encoded: 01001605f01a05f0acd8000100023182022789ffe0000f00a8000000010101000201020003010300040104000501050006000701070008010880000412004007 +Rencoded: 01001605f01a05f0acd8000100023182022789ffe0000f00a8000000010101000201020003010300040104000501050006000701070008010880000412004007 + +Testing LLC XID-Encoder +Data to encode: +Encoded: 108c1443434343430b4242420541 (14 bytes) +Expected: 108c1443434343430b4242420541 (14 bytes) + +Done -- To view, visit https://gerrit.osmocom.org/638 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia06e4cb08bf9b48c2a4682606d1b1a91d19a9d37 Gerrit-PatchSet: 9 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Thu Aug 18 21:12:33 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 18 Aug 2016 21:12:33 +0000 Subject: openbsc[master]: Adding LLC-XID encoder / decoder and unit test In-Reply-To: References: Message-ID: Patch Set 9: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/638 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia06e4cb08bf9b48c2a4682606d1b1a91d19a9d37 Gerrit-PatchSet: 9 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 18 21:13:40 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 18 Aug 2016 21:13:40 +0000 Subject: openbsc[master]: Adding LLC-XID related modifications in LLC In-Reply-To: References: Message-ID: Patch Set 13: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/652 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I65b9d625e72d3d61c99abdc7041773701d694d52 Gerrit-PatchSet: 13 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 18 21:15:21 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 18 Aug 2016 21:15:21 +0000 Subject: openbsc[master]: Adding SNDCP-XID encoder / decoder and unit test In-Reply-To: References: Message-ID: Patch Set 12: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/641 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e Gerrit-PatchSet: 12 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 18 21:16:02 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 18 Aug 2016 21:16:02 +0000 Subject: openbsc[master]: Adding SLHC (RFC1144 header compression) code from linux kernel In-Reply-To: References: Message-ID: Patch Set 11: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/634 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ied69c143678dc4a64cecc671f5c4dfebe19d8519 Gerrit-PatchSet: 11 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 18 21:16:39 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 18 Aug 2016 21:16:39 +0000 Subject: openbsc[master]: SLHC (RFC1144 header compression) integration and unit-test In-Reply-To: References: Message-ID: Patch Set 12: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/635 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 Gerrit-PatchSet: 12 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Fri Aug 19 05:39:39 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Fri, 19 Aug 2016 05:39:39 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 20: Hi Neels and Harald, Any updates on these patches? Thanks, Aravind Sirsikar -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 20 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Fri Aug 19 05:40:18 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Fri, 19 Aug 2016 05:40:18 +0000 Subject: osmo-pcu[master]: Describe the issue with EGPRS PUAN encoding In-Reply-To: References: Message-ID: Patch Set 1: Hi All, Any updates on this patch series? Thanks, Aravind Sirsikar -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Fri Aug 19 05:40:30 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Fri, 19 Aug 2016 05:40:30 +0000 Subject: osmo-pcu[master]: Remove warning while using 'egprs only' command in VTY In-Reply-To: References: Message-ID: Patch Set 1: Hi All, Any updates on this patch series? Thanks, Aravind Sirsikar -- To view, visit https://gerrit.osmocom.org/704 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I62278f998adc691b9a3563ac2a46d756e7bfb66c Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Fri Aug 19 08:01:23 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Fri, 19 Aug 2016 08:01:23 +0000 Subject: [PATCH] openbsc[master]: Adding compression control and final fixups In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/642 to look at the new patch set (#19). Adding compression control and final fixups - Add module to handle compression entities - Add module to control compression - Introduce VTY commands for compression configuration Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 --- M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_sndcp_comp.h A openbsc/include/openbsc/gprs_sndcp_pcomp.h M openbsc/include/openbsc/sgsn.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_sndcp_comp.c A openbsc/src/gprs/gprs_sndcp_pcomp.c M openbsc/src/gprs/sgsn_vty.c M openbsc/tests/sgsn/Makefile.am 9 files changed, 753 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/42/642/19 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index f402fea..88a7e2c 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,7 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ - slhc.h + slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_sndcp_comp.h b/openbsc/include/openbsc/gprs_sndcp_comp.h new file mode 100644 index 0000000..69441fb --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_comp.h @@ -0,0 +1,84 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +/* Header / Data compression entity */ +struct gprs_sndcp_comp { + struct llist_head list; + + /* Serves as an ID in case we want to delete this entity later */ + unsigned int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + + /* Specifies to which NSAPIs the compression entity is assigned */ + uint8_t nsapi_len; /* Number of applicable NSAPIs (default 0) */ + uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */ + + /* Assigned pcomp values */ + uint8_t comp_len; /* Number of contained PCOMP / DCOMP values */ + uint8_t comp[MAX_COMP]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */ + + /* Algorithm parameters */ + int algo; /* Algorithm type (see gprs_sndcp_xid.h) */ + int compclass; /* See gprs_sndcp_xid.h/c */ + void *state; /* Algorithm status and parameters */ +}; + +#define MAX_COMP 16 /* Maximum number of possible pcomp/dcomp values */ +#define MAX_NSAPI 11 /* Maximum number usable NSAPIs */ + +/* Allocate a compression enitiy list */ +struct llist_head *gprs_sndcp_comp_alloc(const void *ctx); + +/* Free a compression entitiy list */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities); + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, unsigned int entity); + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_entities_add(const void *ctx, struct + llist_head *comp_entities, + const struct + gprs_sndcp_comp_field + *comp_field); + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head + *comp_entities, uint8_t comp); + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head + *comp_entities, uint8_t nsapi); + +/* Find a comp_index for a given pcomp/dcomp value */ +int gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp *comp_entity, + int comp); + +/* Find a pcomp/dcomp value for a given comp_index */ +int gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp *comp_entity, + int comp_index); + diff --git a/openbsc/include/openbsc/gprs_sndcp_pcomp.h b/openbsc/include/openbsc/gprs_sndcp_pcomp.h new file mode 100644 index 0000000..2528a86 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_pcomp.h @@ -0,0 +1,44 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field); + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity); + +/* Expand packet header */ +int gprs_sndcp_pcomp_expand(uint8_t *data_o, uint8_t *data_i, unsigned int len, + uint8_t pcomp, + const struct llist_head *comp_entities); + +/* Compress packet header */ +int gprs_sndcp_pcomp_compress(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t *pcomp, + const struct llist_head *comp_entities, + int nsapi); diff --git a/openbsc/include/openbsc/sgsn.h b/openbsc/include/openbsc/sgsn.h index 59126fe..acd3e4b 100644 --- a/openbsc/include/openbsc/sgsn.h +++ b/openbsc/include/openbsc/sgsn.h @@ -89,6 +89,12 @@ int dynamic_lookup; struct oap_config oap; + + /* RFC1144 TCP/IP Header compression */ + struct { + int enabled; + int s01; + } pcomp_rfc1144; }; struct sgsn_instance { diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 245636b..2910c02 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -27,7 +27,7 @@ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ - slhc.c + slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/gprs_sndcp_comp.c b/openbsc/src/gprs/gprs_sndcp_comp.c new file mode 100644 index 0000000..19cd7b1 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_comp.c @@ -0,0 +1,319 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +/* Create a new compression entity from a XID-Field */ +static struct gprs_sndcp_comp *gprs_sndcp_comp_create(const void *ctx, + const struct + gprs_sndcp_comp_field + *comp_field) +{ + OSMO_ASSERT(comp_field); + + struct gprs_sndcp_comp *comp_entity; + comp_entity = talloc_zero(ctx, struct gprs_sndcp_comp); + + /* Copy relevant information from the SNDCP-XID field */ + comp_entity->entity = comp_field->entity; + comp_entity->comp_len = comp_field->comp_len; + memcpy(comp_entity->comp, comp_field->comp, sizeof(comp_entity->comp)); + + if (comp_field->rfc1144_params) { + comp_entity->nsapi_len = comp_field->rfc1144_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc1144_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->rfc2507_params) { + comp_entity->nsapi_len = comp_field->rfc2507_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc2507_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->rohc_params) { + comp_entity->nsapi_len = comp_field->rohc_params->nsapi_len; + memcpy(comp_entity->nsapi, comp_field->rohc_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->v42bis_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->v44_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + sizeof(comp_entity->nsapi)); + } else { + /* The caller is expected to check carefully if the all + * data fields required for compression entity creation + * are present. Otherwise we blow an assertion here */ + OSMO_ASSERT(false); + } + comp_entity->algo = comp_field->algo; + + /* Check if an NSAPI is selected, if not, it does not make sense + * to create the compression entity, since the caller should + * have checked the presence of the NSAPI, we blow an assertion + * in case of missing NSAPIs */ + OSMO_ASSERT(comp_entity->nsapi_len > 0) + + /* Determine of which class our compression entity will be + * (Protocol or Data compresson ?) */ + comp_entity->compclass = + gprs_sndcp_get_compression_class(comp_field); + OSMO_ASSERT(comp_entity->compclass != -1); + + /* Create an algorithm specific compression context */ + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + if (gprs_sndcp_pcomp_init(ctx, comp_entity, comp_field) != 0) { + talloc_free(comp_entity); + comp_entity = NULL; + } + } else { + LOGP(DSNDCP, LOGL_ERROR, + "We don't support data compression yet!\n"); + talloc_free(comp_entity); + return NULL; + } + + /* Display info message */ + if (comp_entity == NULL) { + LOGP(DSNDCP, LOGL_ERROR, + "Header compression entity (%d) creation failed!\n", + comp_entity->entity); + return NULL; + } + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "New header compression entity (%d) created.\n", + comp_entity->entity); + } else { + LOGP(DSNDCP, LOGL_INFO, + "New data compression entity (%d) created.\n", + comp_entity->entity); + } + + return comp_entity; +} + +/* Allocate a compression enitiy list */ +struct llist_head *gprs_sndcp_comp_alloc(const void *ctx) +{ + struct llist_head *lh; + + lh = talloc_zero(ctx, struct llist_head); + INIT_LLIST_HEAD(lh); + + return lh; +} + +/* Free a compression entitiy list */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities) +{ + struct gprs_sndcp_comp *comp_entity; + + /* We expect the caller to take care of allocating a + * compression entity list properly. Attempting to + * free a non existing list clearly points out + * a malfunction. */ + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + /* Free compression entity */ + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %d ...\n", + comp_entity->entity); + gprs_sndcp_pcomp_term(comp_entity); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %d ...\n", + comp_entity->entity); + } + } + + talloc_free(comp_entities); +} + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, + unsigned int entity) +{ + struct gprs_sndcp_comp *comp_entity; + struct gprs_sndcp_comp *comp_entity_to_delete = NULL; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) + comp_entity_to_delete = comp_entity; + } + + if (!comp_entity_to_delete) + return; + + if (comp_entity_to_delete->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %d ...\n", + comp_entity_to_delete->entity); + gprs_sndcp_pcomp_term(comp_entity_to_delete); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %d ...\n", + comp_entity_to_delete->entity); + } + + /* Delete compression entity */ + llist_del(&comp_entity_to_delete->list); + talloc_free(comp_entity_to_delete); +} + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_entities_add(const void *ctx, + struct llist_head + *comp_entities, + const struct + gprs_sndcp_comp_field + *comp_field) +{ + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(comp_entities); + OSMO_ASSERT(comp_field); + + /* Just to be sure, if the entity is already in + * the list it will be deleted now */ + gprs_sndcp_comp_delete(comp_entities, comp_field->entity); + + /* Create and add a new entity to the list */ + comp_entity = gprs_sndcp_comp_create(ctx, comp_field); + + if (!comp_entity) + return NULL; + + llist_add(&comp_entity->list, comp_entities); + return comp_entity; +} + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head + *comp_entities, uint8_t comp) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return comp_entity; + } + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given pcomp/dcomp value %d.\n", + comp); + return NULL; +} + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head + *comp_entities, uint8_t nsapi) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->nsapi_len; i++) { + if (comp_entity->nsapi[i] == nsapi) + return comp_entity; + } + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given nsapi value %d\n", + nsapi); + return NULL; +} + +/* Find a comp_index for a given pcomp/dcomp value */ +int gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp *comp_entity, int comp) +{ + int i; + + OSMO_ASSERT(comp_entity); + + /* A pcomp/dcomp field set to zero always disables + * all sort of compression and is assigned fix. So we + * just return zero in this case */ + if (comp == 0) + return 0; + + /* Look in the pcomp/dcomp list for the index */ + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return i + 1; + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching comp_index for given pcomp/dcomp value %d\n", + comp); + return 0; +} + +/* Find a pcomp/dcomp value for a given comp_index */ +int gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp *comp_entity, + int comp_index) +{ + OSMO_ASSERT(comp_entity); + + /* A comp_index of zero translates to zero right away. */ + if (comp_index == 0) + return 0; + + if (comp_index > comp_entity->comp_len) { + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching pcomp/dcomp value for given comp_index value %d.\n", + comp_index); + return 0; + } + + /* Look in the pcomp/dcomp list for the comp_index */ + return comp_entity->comp[comp_index - 1]; +} diff --git a/openbsc/src/gprs/gprs_sndcp_pcomp.c b/openbsc/src/gprs/gprs_sndcp_pcomp.c new file mode 100644 index 0000000..0fb72b6 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_pcomp.c @@ -0,0 +1,264 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a new header compression + * entity is created by gprs_sndcp.c */ + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + comp_entity->state = + slhc_init(ctx, comp_field->rfc1144_params->s01 + 1, + comp_field->rfc1144_params->s01 + 1); + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression initalized.\n"); + return 0; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a header compression + * entity is deleted by gprs_sndcp.c */ + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + if (comp_entity->state) { + slhc_free((struct slcompress *)comp_entity->state); + comp_entity->state = NULL; + } + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression terminated.\n"); + return; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Compress a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_compress(uint8_t *pcomp_index, + uint8_t *data_o, uint8_t *data_i, + unsigned int len, + struct slcompress *comp) +{ + uint8_t *comp_ptr; /* Required by slhc_compress() */ + int compr_len; + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Run compressor */ + compr_len = slhc_compress(comp, data_i, len, data_o, &comp_ptr, 0); + + /* Generate pcomp_index */ + if (data_o[0] & SL_TYPE_COMPRESSED_TCP) { + *pcomp_index = 2; + data_o[0] &= ~SL_TYPE_COMPRESSED_TCP; + } else if ((data_o[0] & SL_TYPE_UNCOMPRESSED_TCP) == + SL_TYPE_UNCOMPRESSED_TCP) { + *pcomp_index = 1; + data_o[0] &= 0x4F; + } else + *pcomp_index = 0; + + return compr_len; +} + +/* Expand a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_expand(uint8_t *data_o, uint8_t *data_i, + unsigned int len, + uint8_t pcomp_index, + struct slcompress *comp) +{ + int data_decompressed_len; + int type = -1; + + /* Note: this function should never be called with pcomp_index=0, + * since this condition is already filtered + * out by gprs_sndcp_pcomp_expand() */ + + /* Determine the data type by the PCOMP index */ + switch (pcomp_index) { + case 1: + type = SL_TYPE_UNCOMPRESSED_TCP; + break; + case 2: + type = SL_TYPE_COMPRESSED_TCP; + break; + } + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Restore the original version nibble on + * marked uncompressed packets */ + if (type == SL_TYPE_UNCOMPRESSED_TCP) { + /* Just in case the phone tags uncompressed tcp-datas + * (normally this is handled by pcomp so there is + * no need for tagging the datas) */ + data_o[0] &= 0x4F; + data_decompressed_len = slhc_remember(comp, data_o, len); + return data_decompressed_len; + } + + /* Uncompress compressed packets */ + else if (type == SL_TYPE_COMPRESSED_TCP) { + data_decompressed_len = slhc_uncompress(comp, data_o, len); + return data_decompressed_len; + } + + /* Regular or unknown packets will not be touched */ + return len; +} + +/* Expand packet header */ +int gprs_sndcp_pcomp_expand(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t pcomp, + const struct llist_head *comp_entities) +{ + int rc; + uint8_t pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data_o); + OSMO_ASSERT(data_i); + OSMO_ASSERT(comp_entities); + + /* Skip on pcomp=0 */ + if (pcomp == 0) { + memcpy(data_o, data_i, len); + return len; + } + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_comp(comp_entities, pcomp); + + /* Skip compression if no suitable compression entity can be found */ + if (comp_entity == NULL) { + memcpy(data_o, data_i, len); + return len; + } + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION); + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144); + + /* Find pcomp_index */ + pcomp_index = gprs_sndcp_comp_get_idx(comp_entity, pcomp); + + /* Run decompression algo */ + rc = gprs_sndcp_pcomp_rfc1144_expand(data_o, data_i, len, pcomp_index, + comp_entity->state); + slhc_i_status(comp_entity->state); + slhc_o_status(comp_entity->state); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header expansion done, old length=%d, new length=%d\n", len, rc); + + return rc; +} + +/* Compress packet header */ +int gprs_sndcp_pcomp_compress(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t *pcomp, + const struct llist_head *comp_entities, int nsapi) +{ + int rc; + uint8_t pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data_o); + OSMO_ASSERT(data_i); + OSMO_ASSERT(pcomp); + OSMO_ASSERT(comp_entities); + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_nsapi(comp_entities, nsapi); + + /* Skip compression if no suitable compression entity can be found */ + if (!comp_entity) { + *pcomp = 0; + memcpy(data_o, data_i, len); + return len; + } + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION); + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144); + + /* Run compression algo */ + rc = gprs_sndcp_pcomp_rfc1144_compress(&pcomp_index, data_o, data_i, + len, comp_entity->state); + slhc_i_status(comp_entity->state); + slhc_o_status(comp_entity->state); + + /* Find pcomp value */ + *pcomp = gprs_sndcp_comp_get_comp(comp_entity, pcomp_index); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header compression done, old length=%d, new length=%d\n", + len, rc); + return rc; +} diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c index e6dc68d..c7cc268 100644 --- a/openbsc/src/gprs/sgsn_vty.c +++ b/openbsc/src/gprs/sgsn_vty.c @@ -269,6 +269,13 @@ vty_out(vty, " timer t3395 %d%s", g_cfg->timers.T3395, VTY_NEWLINE); vty_out(vty, " timer t3397 %d%s", g_cfg->timers.T3397, VTY_NEWLINE); + if (g_cfg->pcomp_rfc1144.enabled) { + vty_out(vty, " compression rfc1144 slots %d%s", + g_cfg->pcomp_rfc1144.s01+1, VTY_NEWLINE); + } else { + vty_out(vty, " no compression rfc1144%s", VTY_NEWLINE); + } + return CMD_SUCCESS; } @@ -1074,6 +1081,28 @@ return CMD_SUCCESS; } +#define COMPRESSION_STR "Configure compression\n" +DEFUN(cfg_no_comp_rfc1144, cfg_no_comp_rfc1144_cmd, + "no compression rfc1144", + NO_STR COMPRESSION_STR + "disable rfc1144 TCP/IP header compression\n") +{ + g_cfg->pcomp_rfc1144.enabled = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_comp_rfc1144, cfg_comp_rfc1144_cmd, + "compression rfc1144 slots <1-256>", + COMPRESSION_STR + "RFC1144 Header compresion scheme\n" + "Number of compression state slots\n" + "Number of compression state slots\n") +{ + g_cfg->pcomp_rfc1144.enabled = 1; + g_cfg->pcomp_rfc1144.s01 = atoi(argv[0]) - 1; + return CMD_SUCCESS; +} + int sgsn_vty_init(void) { install_element_ve(&show_sgsn_cmd); @@ -1128,6 +1157,9 @@ install_element(SGSN_NODE, &cfg_sgsn_T3395_cmd); install_element(SGSN_NODE, &cfg_sgsn_T3397_cmd); + install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd); + install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd); + return 0; } diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 3e66978..1804280 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -33,6 +33,8 @@ $(top_builddir)/src/gprs/gprs_llc_xid.o \ $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ $(top_builddir)/src/gprs/slhc.o \ + $(top_builddir)/src/gprs/gprs_sndcp_comp.o \ + $(top_builddir)/src/gprs/gprs_sndcp_pcomp.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ -- To view, visit https://gerrit.osmocom.org/642 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 Gerrit-PatchSet: 19 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Fri Aug 19 08:42:14 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Fri, 19 Aug 2016 08:42:14 +0000 Subject: [PATCH] openbsc[master]: V42BIS integration and unit test In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/644 to look at the new patch set (#25). V42BIS integration and unit test The previously committed SPANDSP v42bis implementation has been edited to function outside the SPANDSP library. Debug printf statements were changed into DEBUGP statements. Als removed the assembely code in top_bit(). Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d --- M openbsc/.gitignore M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/debug.h M openbsc/include/openbsc/v42bis.h R openbsc/include/openbsc/v42bis_private.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/sgsn_main.c M openbsc/src/gprs/v42bis.c M openbsc/tests/Makefile.am M openbsc/tests/testsuite.at A openbsc/tests/v42bis/Makefile.am A openbsc/tests/v42bis/v42bis_test.c A openbsc/tests/v42bis/v42bis_test.ok 14 files changed, 262 insertions(+), 28 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/44/644/25 diff --git a/openbsc/.gitignore b/openbsc/.gitignore index e75b9eb..6fbd463 100644 --- a/openbsc/.gitignore +++ b/openbsc/.gitignore @@ -84,6 +84,7 @@ tests/xid/xid_test tests/sndcp_xid/sndcp_xid_test tests/slhc/slhc_test +tests/v42bis/v42bis_test tests/atconfig tests/atlocal diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 18980b0..1df14fe 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -232,6 +232,7 @@ tests/xid/Makefile tests/sndcp_xid/Makefile tests/slhc/Makefile + tests/v42bis/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 88a7e2c..b3403dd 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,8 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ - slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h + slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h v42bis.h \ + v42bis_private.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 90ddca5..ca3d4ad 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -37,6 +37,7 @@ DGTPHUB, DRANAP, DSUA, + DV42BIS, Debug_LastEntry, }; diff --git a/openbsc/include/openbsc/v42bis.h b/openbsc/include/openbsc/v42bis.h index f13e5c5..0b97603 100644 --- a/openbsc/include/openbsc/v42bis.h +++ b/openbsc/include/openbsc/v42bis.h @@ -33,8 +33,12 @@ \section v42bis_page_sec_2 How does it work? */ +#include + #if !defined(_SPANDSP_V42BIS_H_) #define _SPANDSP_V42BIS_H_ + +#define SPAN_DECLARE(x) x #define V42BIS_MAX_BITS 12 #define V42BIS_MAX_CODEWORDS 4096 /* 2^V42BIS_MAX_BITS */ @@ -114,7 +118,8 @@ \param data_user_data An opaque pointer passed to the data callback handler. \param max_data_len The maximum length that should be passed to the data handler. \return The V.42bis context. */ -SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, +SPAN_DECLARE(v42bis_state_t *) v42bis_init(const void *ctx, + v42bis_state_t *s, int negotiated_p0, int negotiated_p1, int negotiated_p2, diff --git a/openbsc/include/openbsc/private_v42bis.h b/openbsc/include/openbsc/v42bis_private.h similarity index 100% rename from openbsc/include/openbsc/private_v42bis.h rename to openbsc/include/openbsc/v42bis_private.h diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 2910c02..f479d56 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -27,7 +27,7 @@ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ - slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c + slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c v42bis.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c index 894ce84..f01798b 100644 --- a/openbsc/src/gprs/sgsn_main.c +++ b/openbsc/src/gprs/sgsn_main.c @@ -297,6 +297,11 @@ .description = "RFC1144 TCP/IP Header compression (SLHC)", .enabled = 1, .loglevel = LOGL_DEBUG, }, + [DV42BIS] = { + .name = "DV42BIS", + .description = "V.42bis data compression (SNDCP)", + .enabled = 1, .loglevel = LOGL_DEBUG, + } }; static const struct log_info gprs_log_info = { diff --git a/openbsc/src/gprs/v42bis.c b/openbsc/src/gprs/v42bis.c index 6d38916..b8a886d 100644 --- a/openbsc/src/gprs/v42bis.c +++ b/openbsc/src/gprs/v42bis.c @@ -31,9 +31,8 @@ /*! \file */ -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif +#define FALSE 0 +#define TRUE 1 #include #include @@ -44,13 +43,11 @@ #include #include -#include "spandsp/telephony.h" -#include "spandsp/logging.h" -#include "spandsp/bit_operations.h" -#include "spandsp/v42bis.h" +#include +#include +#include +#include -#include "spandsp/private/logging.h" -#include "spandsp/private/v42bis.h" /* Fixed parameters from the spec. */ #define V42BIS_N3 8 /* Character size (bits) */ @@ -310,7 +307,7 @@ { if (ss->transparent) { - printf("Going compressed\n"); + DEBUGP(DV42BIS,"Going compressed\n"); /* 7.8.1 Transition to compressed mode */ /* Switch out of transparent now, between codes. We need to send the octet which did not match, just before switching. */ @@ -332,7 +329,7 @@ { if (!ss->transparent) { - printf("Going transparent\n"); + DEBUGP(DV42BIS,"Going transparent\n"); /* 7.8.2 Transition to transparent mode */ /* Switch into transparent now, between codes, and the unmatched octet should go out in transparent mode, just below */ @@ -401,7 +398,7 @@ { if (s->compress.dict[i].parent_code != 0xFFFF) { - printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); + DEBUGP(DV42BIS,"Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); } } return 0; @@ -454,13 +451,13 @@ ss->escaped = FALSE; if (code == V42BIS_ECM) { - printf("Hit V42BIS_ECM\n"); + DEBUGP(DV42BIS,"Hit V42BIS_ECM\n"); ss->transparent = FALSE; code_len = ss->v42bis_parm_c2; } else if (code == V42BIS_EID) { - printf("Hit V42BIS_EID\n"); + DEBUGP(DV42BIS,"Hit V42BIS_EID\n"); ss->output_buf[ss->output_octet_count++] = ss->escape_code - 1; if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) { @@ -470,11 +467,11 @@ } else if (code == V42BIS_RESET) { - printf("Hit V42BIS_RESET\n"); + DEBUGP(DV42BIS,"Hit V42BIS_RESET\n"); } else { - printf("Hit V42BIS_???? - %" PRIu32 "\n", code); + DEBUGP(DV42BIS,"Hit V42BIS_???? - %" PRIu32 "\n", code); } } else if (code == ss->escape_code) @@ -500,17 +497,17 @@ switch (new_code) { case V42BIS_ETM: - printf("Hit V42BIS_ETM\n"); + DEBUGP(DV42BIS,"Hit V42BIS_ETM\n"); ss->transparent = TRUE; code_len = 8; break; case V42BIS_FLUSH: - printf("Hit V42BIS_FLUSH\n"); + DEBUGP(DV42BIS,"Hit V42BIS_FLUSH\n"); v42bis_decompress_flush(s); break; case V42BIS_STEPUP: /* We need to increase the codeword size */ - printf("Hit V42BIS_STEPUP\n"); + DEBUGP(DV42BIS,"Hit V42BIS_STEPUP\n"); if (ss->v42bis_parm_c3 >= s->v42bis_parm_n2) { /* Invalid condition */ @@ -547,7 +544,7 @@ /* Trace back through the octets which form the string, and output them. */ while (code >= V42BIS_N5) { -if (code > 4095) {printf("Code is 0x%" PRIu32 "\n", code); exit(2);} +if (code > 4095) {DEBUGP(DV42BIS,"Code is 0x%" PRIu32 "\n", code); exit(2);} *string-- = ss->dict[code].node_octet; code = ss->dict[code].parent_code; } @@ -631,7 +628,7 @@ { if (s->decompress.dict[i].parent_code != 0xFFFF) { - printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); + DEBUGP(DV42BIS,"Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); } } return 0; @@ -654,7 +651,8 @@ } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, +SPAN_DECLARE(v42bis_state_t *) v42bis_init(const void *ctx, + v42bis_state_t *s, int negotiated_p0, int negotiated_p1, int negotiated_p2, @@ -673,7 +671,7 @@ return NULL; if (s == NULL) { - if ((s = (v42bis_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (v42bis_state_t *) talloc_zero_size(ctx,sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -735,7 +733,7 @@ SPAN_DECLARE(int) v42bis_free(v42bis_state_t *s) { - free(s); + talloc_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index d5aa356..7acebc0 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid slhc +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid slhc v42bis if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index 5f37b8e..f18b734 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -141,3 +141,9 @@ cat $abs_srcdir/slhc/slhc_test.ok > expout AT_CHECK([$abs_top_builddir/tests/slhc/slhc_test], [], [expout], [ignore]) AT_CLEANUP + +AT_SETUP([v42bis]) +AT_KEYWORDS([v42bis]) +cat $abs_srcdir/v42bis/v42bis_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/v42bis/v42bis_test], [], [expout], [ignore]) +AT_CLEANUP diff --git a/openbsc/tests/v42bis/Makefile.am b/openbsc/tests/v42bis/Makefile.am new file mode 100644 index 0000000..9001c0f --- /dev/null +++ b/openbsc/tests/v42bis/Makefile.am @@ -0,0 +1,21 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) + +EXTRA_DIST = v42bis_test.ok + +noinst_PROGRAMS = v42bis_test + +v42bis_test_SOURCES = v42bis_test.c + +v42bis_test_LDADD = \ + $(top_builddir)/src/gprs/v42bis.o \ + $(top_builddir)/src/libcommon/libcommon.a \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOGB_LIBS) \ + $(LIBCARES_LIBS) \ + $(LIBCRYPTO_LIBS) \ + -lgtp -lrt -lm + + diff --git a/openbsc/tests/v42bis/v42bis_test.c b/openbsc/tests/v42bis/v42bis_test.c new file mode 100644 index 0000000..9270139 --- /dev/null +++ b/openbsc/tests/v42bis/v42bis_test.c @@ -0,0 +1,191 @@ +/* Test v42bis Compression/Decompression */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#define BLOCK_SIZE 100 +#define MAX_BLOCK_SIZE 2048 + +/* A struct to capture the output data of compressor and decompressor */ +struct v42bis_output_buffer { + uint8_t *buf; + uint8_t *buf_pointer; + int len; +}; + +/* A simple testpattern generator */ +static void gen_test_pattern(uint8_t *data, int len) +{ + int i; + for (i = 0; i < len; i++) + data[i] = i & 0xF0; +} + +/* Handler to capture the output data from the compressor */ +void tx_v42bis_frame_handler(void *user_data, const uint8_t *pkt, int len) +{ + struct v42bis_output_buffer *output_buffer = + (struct v42bis_output_buffer *)user_data; + memcpy(output_buffer->buf_pointer, pkt, len); + output_buffer->buf_pointer += len; + output_buffer->len += len; + return; +} + +/* Handler to capture the output data from the decompressor */ +void tx_v42bis_data_handler(void *user_data, const uint8_t *buf, int len) +{ + /* stub */ + return; +} + +/* Handler to capture the output data from the compressor */ +void rx_v42bis_frame_handler(void *user_data, const uint8_t *pkt, int len) +{ + /* stub */ + return; +} + +/* Handler to capture the output data from the decompressor */ +void rx_v42bis_data_handler(void *user_data, const uint8_t *buf, int len) +{ + struct v42bis_output_buffer *output_buffer = + (struct v42bis_output_buffer *)user_data; + memcpy(output_buffer->buf_pointer, buf, len); + output_buffer->buf_pointer += len; + output_buffer->len += len; + return; +} + +/* Test V.42bis compression and decompression */ +static void test_v42bis(const void *ctx) +{ + v42bis_state_t *tx_state; + v42bis_state_t *rx_state; + + uint8_t uncompressed_original[BLOCK_SIZE]; + uint8_t compressed[BLOCK_SIZE]; + uint8_t uncompressed[BLOCK_SIZE]; + + int rc; + struct v42bis_output_buffer compressed_data; + struct v42bis_output_buffer uncompressed_data; + + /* Initalize */ + tx_state = + v42bis_init(ctx, NULL, 3, MAX_BLOCK_SIZE, 6, + &tx_v42bis_frame_handler, NULL, MAX_BLOCK_SIZE, + &tx_v42bis_data_handler, NULL, MAX_BLOCK_SIZE); + OSMO_ASSERT(tx_state); + rx_state = + v42bis_init(ctx, NULL, 3, MAX_BLOCK_SIZE, 6, + &rx_v42bis_frame_handler, NULL, MAX_BLOCK_SIZE, + &rx_v42bis_data_handler, NULL, MAX_BLOCK_SIZE); + OSMO_ASSERT(rx_state); + v42bis_compression_control(tx_state, V42BIS_COMPRESSION_MODE_ALWAYS); + v42bis_compression_control(rx_state, V42BIS_COMPRESSION_MODE_ALWAYS); + + /* Generate test pattern for input */ + gen_test_pattern(uncompressed_original, sizeof(uncompressed_original)); + + /* Run compressor */ + compressed_data.buf = compressed; + compressed_data.buf_pointer = compressed; + compressed_data.len = 0; + tx_state->compress.user_data = (&compressed_data); + rc = v42bis_compress(tx_state, uncompressed_original, + sizeof(uncompressed_original)); + OSMO_ASSERT(rc == 0); + rc = v42bis_compress_flush(tx_state); + OSMO_ASSERT(rc == 0); + + /* Decompress again */ + uncompressed_data.buf = uncompressed; + uncompressed_data.buf_pointer = uncompressed; + uncompressed_data.len = 0; + rx_state->decompress.user_data = (&uncompressed_data); + rc = v42bis_decompress(rx_state, compressed_data.buf, + compressed_data.len); + OSMO_ASSERT(rc == 0); + rc = v42bis_decompress_flush(rx_state); + OSMO_ASSERT(rc == 0); + + /* Check results */ + printf("uncompressed_original= %s\n", + osmo_hexdump_nospc(uncompressed_original, + sizeof(uncompressed_original))); + printf("uncompressed= %s\n", + osmo_hexdump_nospc(uncompressed_data.buf, + uncompressed_data.len)); + printf("compressed= %s\n", + osmo_hexdump_nospc(compressed_data.buf, compressed_data.len)); + rc = memcmp(uncompressed, uncompressed_original, BLOCK_SIZE); + OSMO_ASSERT(rc == 0); + + v42bis_free(tx_state); + v42bis_free(rx_state); +} + +static struct log_info_cat gprs_categories[] = { + [DV42BIS] = { + .name = "DV42BIS", + .description = "V.42bis data compression (SNDCP)", + .enabled = 1,.loglevel = LOGL_DEBUG, + } +}; + +static struct log_info info = { + .cat = gprs_categories, + .num_cat = ARRAY_SIZE(gprs_categories), +}; + +int main(int argc, char **argv) +{ + void *v42bis_ctx; + + osmo_init_logging(&info); + + v42bis_ctx = talloc_named_const(NULL, 0, "v42bis_ctx"); + + test_v42bis(v42bis_ctx); + printf("Done\n"); + + talloc_report_full(v42bis_ctx, stderr); + OSMO_ASSERT(talloc_total_blocks(v42bis_ctx) == 1); + return 0; +} + +/* stubs */ +struct osmo_prim_hdr; +int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) +{ + abort(); +} diff --git a/openbsc/tests/v42bis/v42bis_test.ok b/openbsc/tests/v42bis/v42bis_test.ok new file mode 100644 index 0000000..16c8612 --- /dev/null +++ b/openbsc/tests/v42bis/v42bis_test.ok @@ -0,0 +1,4 @@ +uncompressed_original= 00000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060 +uncompressed= 00000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060 +compressed= 0180e0703824120a1309c1e0f0884424462385c2e190c868cc670f87c4221112190e27138a4522a5329c5e2f188c464c6638d804 +Done -- To view, visit https://gerrit.osmocom.org/644 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d Gerrit-PatchSet: 25 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Fri Aug 19 10:46:31 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Fri, 19 Aug 2016 10:46:31 +0000 Subject: [PATCH] openbsc[master]: Adding compression control and final fixups In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/642 to look at the new patch set (#20). Adding compression control and final fixups - Add module to handle compression entities - Add module to control header compression - Introduce VTY commands for heade compression configuration - Add changes in sndcp and llc to integrate header compression Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 --- M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/gprs_llc.h M openbsc/include/openbsc/gprs_sndcp.h A openbsc/include/openbsc/gprs_sndcp_comp.h A openbsc/include/openbsc/gprs_sndcp_pcomp.h M openbsc/include/openbsc/sgsn.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/gprs_llc.c M openbsc/src/gprs/gprs_sndcp.c A openbsc/src/gprs/gprs_sndcp_comp.c A openbsc/src/gprs/gprs_sndcp_pcomp.c M openbsc/src/gprs/sgsn_libgtp.c M openbsc/src/gprs/sgsn_vty.c M openbsc/tests/sgsn/Makefile.am 14 files changed, 1,342 insertions(+), 37 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/42/642/20 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index f402fea..88a7e2c 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,7 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ - slhc.h + slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h index c3b82b1..4cd6c2e 100644 --- a/openbsc/include/openbsc/gprs_llc.h +++ b/openbsc/include/openbsc/gprs_llc.h @@ -174,6 +174,15 @@ * able to create the compression entity. */ struct llist_head *xid; + /* Compression entities */ + struct { + /* In this two list_heads we will store the + * data and protocol compression entities, + * together with their compression states */ + struct llist_head *proto; + struct llist_head *data; + } comp; + /* Internal management */ uint32_t age_timestamp; }; diff --git a/openbsc/include/openbsc/gprs_sndcp.h b/openbsc/include/openbsc/gprs_sndcp.h index fef871a..426e2bb 100644 --- a/openbsc/include/openbsc/gprs_sndcp.h +++ b/openbsc/include/openbsc/gprs_sndcp.h @@ -46,8 +46,29 @@ enum sndcp_rx_state rx_state; /* The defragmentation queue */ struct defrag_state defrag; + + /* Holds state to know which compression is used + * when the packet is re-assembled */ + uint8_t pcomp; + uint8_t dcomp; }; extern struct llist_head gprs_sndcp_entities; +/* Set of SNDCP-XID negotiation (See also: TS 144 065, + * Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_req(struct gprs_llc_lle *lle, uint8_t nsapi); + +/* Process SNDCP-XID indication (See also: TS 144 065, + * Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_ind(struct gprs_llc_xid_field *xid_field_indication, + struct gprs_llc_xid_field *xid_field_response, + struct gprs_llc_lle *lle); + +/* Process SNDCP-XID indication + * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_conf(struct gprs_llc_xid_field *xid_field_confirmation, + struct gprs_llc_xid_field *xid_field_request, + struct gprs_llc_lle *lle); + #endif /* INT_SNDCP_H */ diff --git a/openbsc/include/openbsc/gprs_sndcp_comp.h b/openbsc/include/openbsc/gprs_sndcp_comp.h new file mode 100644 index 0000000..69441fb --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_comp.h @@ -0,0 +1,84 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +/* Header / Data compression entity */ +struct gprs_sndcp_comp { + struct llist_head list; + + /* Serves as an ID in case we want to delete this entity later */ + unsigned int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + + /* Specifies to which NSAPIs the compression entity is assigned */ + uint8_t nsapi_len; /* Number of applicable NSAPIs (default 0) */ + uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */ + + /* Assigned pcomp values */ + uint8_t comp_len; /* Number of contained PCOMP / DCOMP values */ + uint8_t comp[MAX_COMP]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */ + + /* Algorithm parameters */ + int algo; /* Algorithm type (see gprs_sndcp_xid.h) */ + int compclass; /* See gprs_sndcp_xid.h/c */ + void *state; /* Algorithm status and parameters */ +}; + +#define MAX_COMP 16 /* Maximum number of possible pcomp/dcomp values */ +#define MAX_NSAPI 11 /* Maximum number usable NSAPIs */ + +/* Allocate a compression enitiy list */ +struct llist_head *gprs_sndcp_comp_alloc(const void *ctx); + +/* Free a compression entitiy list */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities); + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, unsigned int entity); + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_entities_add(const void *ctx, struct + llist_head *comp_entities, + const struct + gprs_sndcp_comp_field + *comp_field); + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head + *comp_entities, uint8_t comp); + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head + *comp_entities, uint8_t nsapi); + +/* Find a comp_index for a given pcomp/dcomp value */ +int gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp *comp_entity, + int comp); + +/* Find a pcomp/dcomp value for a given comp_index */ +int gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp *comp_entity, + int comp_index); + diff --git a/openbsc/include/openbsc/gprs_sndcp_pcomp.h b/openbsc/include/openbsc/gprs_sndcp_pcomp.h new file mode 100644 index 0000000..2528a86 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_pcomp.h @@ -0,0 +1,44 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field); + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity); + +/* Expand packet header */ +int gprs_sndcp_pcomp_expand(uint8_t *data_o, uint8_t *data_i, unsigned int len, + uint8_t pcomp, + const struct llist_head *comp_entities); + +/* Compress packet header */ +int gprs_sndcp_pcomp_compress(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t *pcomp, + const struct llist_head *comp_entities, + int nsapi); diff --git a/openbsc/include/openbsc/sgsn.h b/openbsc/include/openbsc/sgsn.h index 59126fe..acd3e4b 100644 --- a/openbsc/include/openbsc/sgsn.h +++ b/openbsc/include/openbsc/sgsn.h @@ -89,6 +89,12 @@ int dynamic_lookup; struct oap_config oap; + + /* RFC1144 TCP/IP Header compression */ + struct { + int enabled; + int s01; + } pcomp_rfc1144; }; struct sgsn_instance { diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 245636b..2910c02 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -27,7 +27,7 @@ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ - slhc.c + slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c index 79795d6..34b7afe 100644 --- a/openbsc/src/gprs/gprs_llc.c +++ b/openbsc/src/gprs/gprs_llc.c @@ -39,6 +39,7 @@ #include #include #include +#include #include static struct gprs_llc_llme *llme_alloc(uint32_t tlli); @@ -88,7 +89,9 @@ llist_add(&l3_xid_field->list, &xid_fields); } - llme->xid = gprs_llc_copy_xid(llme->xid, &xid_fields); + /* Store generated XID for later reference */ + talloc_free(llme->xid); + llme->xid = gprs_llc_copy_xid(llme, &xid_fields); return gprs_llc_compile_xid(bytes, bytes_len, &xid_fields); } @@ -120,7 +123,9 @@ llist_add(&xid_iovui.list, &xid_fields); llist_add(&xid_reset.list, &xid_fields); - llme->xid = gprs_llc_copy_xid(llme->xid, &xid_fields); + /* Store generated XID for later reference */ + talloc_free(llme->xid); + llme->xid = gprs_llc_copy_xid(llme, &xid_fields); return gprs_llc_compile_xid(bytes, bytes_len, &xid_fields); } @@ -135,6 +140,16 @@ struct llist_head *xid_fields; struct gprs_llc_xid_field *xid_field; + struct gprs_llc_xid_field *xid_field_request; + struct gprs_llc_xid_field *xid_field_request_l3 = NULL; + + /* Pick layer3 XID from the XID request we have sent last */ + if (lle->llme->xid) { + llist_for_each_entry(xid_field_request, lle->llme->xid, list) { + if (xid_field_request->type == GPRS_LLC_XID_T_L3_PAR) + xid_field_request_l3 = xid_field_request; + } + } /* Parse and analyze XID-Response */ xid_fields = gprs_llc_parse_xid(NULL, bytes, bytes_len); @@ -145,11 +160,10 @@ llist_for_each_entry(xid_field, xid_fields, list) { /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ - if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { - LOGP(DLLC, LOGL_NOTICE, - "Ignoring SNDCP-XID-Field: XID: type=%i, data_len=%i, data=%s\n", - xid_field->type, xid_field->data_len, - xid_field->data); + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR && + xid_field_request_l3) { + sndcp_sn_xid_conf(xid_field, + xid_field_request_l3, lle); } /* Process LLC-XID fields: */ @@ -163,9 +177,10 @@ * inquiry. There is a remainig risk of * malfunction! */ LOGP(DLLC, LOGL_NOTICE, - "Ignoring XID-Field: XID: type=%i, data_len=%i, data=%s\n", + "Ignoring XID-Field: XID: type=%d, data_len=%d, data=%s\n", xid_field->type, xid_field->data_len, - xid_field->data); + osmo_hexdump_nospc(xid_field->data, + xid_field->data_len)); } } talloc_free(xid_fields); @@ -197,10 +212,6 @@ struct gprs_llc_xid_field *xid_field; struct gprs_llc_xid_field *xid_field_response; - /* Flush eventually pending XID fields */ - talloc_free(lle->llme->xid); - lle->llme->xid = NULL; - /* Parse and analyze XID-Request */ xid_fields = gprs_llc_parse_xid(lle->llme, bytes_request, bytes_request_len); @@ -220,7 +231,7 @@ * when a phone submits values which defer from * the default! */ LOGP(DLLC, LOGL_NOTICE, - "Echoing XID-Field: XID: type=%i, data_len=%i, data=%s\n", + "Echoing XID-Field: XID: type=%d, data_len=%d, data=%s\n", xid_field->type, xid_field->data_len, osmo_hexdump_nospc(xid_field->data, xid_field->data_len)); @@ -229,6 +240,23 @@ (lle->llme, xid_field); llist_add(&xid_field_response->list, xid_fields_response); + } + } + + /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ + llist_for_each_entry(xid_field, xid_fields, list) { + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { + + xid_field_response = + talloc_zero(lle->llme, + struct gprs_llc_xid_field); + rc = sndcp_sn_xid_ind(xid_field, + xid_field_response, lle); + if (rc == 0) + llist_add(&xid_field_response->list, + xid_fields_response); + else + talloc_free(xid_field_response); } } @@ -518,11 +546,16 @@ llist_add(&llme->list, &gprs_llc_llmes); + llme->comp.proto = gprs_sndcp_comp_alloc(llme); + llme->comp.data = gprs_sndcp_comp_alloc(llme); + return llme; } static void llme_free(struct gprs_llc_llme *llme) { + gprs_sndcp_comp_free(llme->comp.proto); + gprs_sndcp_comp_free(llme->comp.data); talloc_free(llme->xid); llist_del(&llme->list); talloc_free(llme); diff --git a/openbsc/src/gprs/gprs_sndcp.c b/openbsc/src/gprs/gprs_sndcp.c index 4f71121..0c46b6b 100644 --- a/openbsc/src/gprs/gprs_sndcp.c +++ b/openbsc/src/gprs/gprs_sndcp.c @@ -35,6 +35,59 @@ #include #include #include +#include +#include +#include +#include + +#define DEBUG_IP_PACKETS 0 /* 0=Disabled, 1=Enabled */ + +#if DEBUG_IP_PACKETS == 1 +/* Show some ip packet details */ +static void debug_ip_packet(uint8_t *data, int len, int dir, char *info) +{ + uint8_t tcp_flags; + char flags_debugmsg[256]; + int len_short; + + if(len > 90) + len_short = 90; + else + len_short = len; + + if (dir) + DEBUGP(DSNDCP,"%s: PHONE => NETWORK: %s\n", info, + osmo_hexdump_nospc(data, len_short)); + else + DEBUGP(DSNDCP,"%s: PHONE <= NETWORK: %s\n", info, + osmo_hexdump_nospc(data, len_short)); + + DEBUGP(DSNDCP,"%s: length: %d\n", info, len); + if (data[9] == 0x06) { + DEBUGP(DSNDCP,"%s: Protocol type: TCP\n", info); + tcp_flags = data[33]; + + memset(flags_debugmsg,0,sizeof(flags_debugmsg)); + if (tcp_flags & 1) + strcat(flags_debugmsg,"FIN "); + if (tcp_flags & 2) + strcat(flags_debugmsg,"SYN "); + if (tcp_flags & 4) + strcat(flags_debugmsg,"RST "); + if (tcp_flags & 8) + strcat(flags_debugmsg,"PSH "); + if (tcp_flags & 16) + strcat(flags_debugmsg,"ACK "); + if (tcp_flags & 32) + strcat(flags_debugmsg,"URG "); + DEBUGP(DSNDCP,"%s: FLAGS: %s\n", info, flags_debugmsg); + } else if (data[9] == 0x11) { + DEBUGP(DSNDCP,"%s: Protocol type: UDP\n", info); + } else { + DEBUGP(DSNDCP,"%s: Protocol type: (%02x)\n", info, data[9]); + } +} +#endif /* Chapter 7.2: SN-PDU Formats */ struct sndcp_common_hdr { @@ -138,11 +191,15 @@ } /* Perform actual defragmentation and create an output packet */ -static int defrag_segments(struct gprs_sndcp_entity *sne) +static int defrag_segments(struct gprs_sndcp_entity *sne, + struct llist_head *comp_entities) { struct msgb *msg; unsigned int seg_nr; uint8_t *npdu; + int npdu_len; + int rc; + uint8_t *expnd; LOGP(DSNDCP, LOGL_DEBUG, "TLLI=0x%08x NSAPI=%u: Defragment output PDU %u " "num_seg=%u tot_len=%u\n", sne->lle->llme->tlli, sne->nsapi, @@ -173,16 +230,48 @@ talloc_free(dqe); } + npdu_len = sne->defrag.tot_len; + /* FIXME: cancel timer */ /* actually send the N-PDU to the SGSN core code, which then * hands it off to the correct GTP tunnel + GGSN via gtp_data_req() */ - return sgsn_rx_sndcp_ud_ind(&sne->ra_id, sne->lle->llme->tlli, - sne->nsapi, msg, sne->defrag.tot_len, npdu); + + /* Decompress packet */ +#if DEBUG_IP_PACKETS == 1 + DEBUGP(DSNDCP," \n"); + DEBUGP(DSNDCP,"::::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP,"====================================================\n"); + debug_ip_packet(npdu, npdu_len,1,"defrag_segments()"); +#endif + expnd = talloc_zero_size(msg,msg->len + 64); + rc = gprs_sndcp_pcomp_expand(expnd, npdu, npdu_len, + sne->pcomp, comp_entities); + sne->pcomp = 0; + if (rc < 0) { + talloc_free(expnd); + return -EIO; + } + else + npdu_len = rc; +#if DEBUG_IP_PACKETS == 1 + debug_ip_packet(expnd, npdu_len,1,"defrag_segments()"); + DEBUGP(DSNDCP,"====================================================\n"); + DEBUGP(DSNDCP,"::::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP," \n"); +#endif + + /* Hand off packet to gtp */ + rc = sgsn_rx_sndcp_ud_ind(&sne->ra_id, sne->lle->llme->tlli, + sne->nsapi, msg, npdu_len, expnd); + + talloc_free(expnd); + return rc; } -static int defrag_input(struct gprs_sndcp_entity *sne, struct msgb *msg, uint8_t *hdr, - unsigned int len) +static int defrag_input(struct gprs_sndcp_entity *sne, struct msgb *msg, + uint8_t *hdr, unsigned int len, + struct llist_head *comp_entities) { struct sndcp_common_hdr *sch; struct sndcp_udata_hdr *suh; @@ -249,7 +338,7 @@ /* we have already received the last segment before, let's check * if all the previous segments exist */ if (defrag_have_all_segments(sne)) - return defrag_segments(sne); + return defrag_segments(sne,comp_entities); } return 0; @@ -343,7 +432,8 @@ }; /* returns '1' if there are more fragments to send, '0' if none */ -static int sndcp_send_ud_frag(struct sndcp_frag_state *fs) +static int sndcp_send_ud_frag(struct sndcp_frag_state *fs, + uint8_t pcomp, uint8_t dcomp) { struct gprs_sndcp_entity *sne = fs->sne; struct gprs_llc_lle *lle = sne->lle; @@ -380,8 +470,8 @@ if (sch->first) { scomph = (struct sndcp_comp_hdr *) msgb_put(fmsg, sizeof(*scomph)); - scomph->pcomp = 0; - scomph->dcomp = 0; + scomph->pcomp = pcomp; + scomph->dcomp = dcomp; } /* append the user-data header */ @@ -446,8 +536,38 @@ struct sndcp_comp_hdr *scomph; struct sndcp_udata_hdr *suh; struct sndcp_frag_state fs; + uint8_t pcomp = 0; + uint8_t dcomp = 0; + int rc; + uint8_t *compr; /* Identifiers from UP: (TLLI, SAPI) + (BVCI, NSEI) */ + + /* Compress packet */ +#if DEBUG_IP_PACKETS == 1 + DEBUGP(DSNDCP," \n"); + DEBUGP(DSNDCP,"::::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP,"====================================================\n"); + debug_ip_packet(msg->data, msg->len,0,"sndcp_initdata_req()"); +#endif + compr = talloc_zero_size(msg, msg->len); + rc = gprs_sndcp_pcomp_compress(compr,msg->data, msg->len,&pcomp, + lle->llme->comp.proto, nsapi); + if (rc < 0) { + talloc_free(compr); + return -EIO; + } + else { + msg->len = rc; + memcpy(msg->data,compr,rc); + } + talloc_free(compr); +#if DEBUG_IP_PACKETS == 1 + debug_ip_packet(msg->data, msg->len,0,"sndcp_initdata_req()"); + DEBUGP(DSNDCP,"====================================================\n"); + DEBUGP(DSNDCP,"::::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP," \n"); +#endif sne = gprs_sndcp_entity_by_lle(lle, nsapi); if (!sne) { @@ -469,7 +589,7 @@ /* call function to generate and send fragments until all * of the N-PDU has been sent */ while (1) { - int rc = sndcp_send_ud_frag(&fs); + int rc = sndcp_send_ud_frag(&fs,pcomp,dcomp); if (rc == 0) return 0; if (rc < 0) @@ -489,8 +609,8 @@ sne->tx_npdu_nr = (sne->tx_npdu_nr + 1) % 0xfff; scomph = (struct sndcp_comp_hdr *) msgb_push(msg, sizeof(*scomph)); - scomph->pcomp = 0; - scomph->dcomp = 0; + scomph->pcomp = pcomp; + scomph->dcomp = dcomp; /* prepend common SNDCP header */ sch = (struct sndcp_common_hdr *) msgb_push(msg, sizeof(*sch)); @@ -512,6 +632,8 @@ uint8_t *npdu; uint16_t npdu_num __attribute__((unused)); int npdu_len; + int rc; + uint8_t *expnd; sch = (struct sndcp_common_hdr *) hdr; if (sch->first) { @@ -540,26 +662,57 @@ /* FIXME: move this RA_ID up to the LLME or even higher */ bssgp_parse_cell_id(&sne->ra_id, msgb_bcid(msg)); + if(scomph) { + sne->pcomp = scomph->pcomp; + sne->dcomp = scomph->dcomp; + } + /* any non-first segment is by definition something to defragment * as is any segment that tells us there are more segments */ if (!sch->first || sch->more) - return defrag_input(sne, msg, hdr, len); - - if (scomph && (scomph->pcomp || scomph->dcomp)) { - LOGP(DSNDCP, LOGL_ERROR, "We don't support compression yet\n"); - return -EIO; - } + return defrag_input(sne, msg, hdr, len, lle->llme->comp.proto); npdu_num = (suh->npdu_high << 8) | suh->npdu_low; npdu = (uint8_t *)suh + sizeof(*suh); - npdu_len = (msg->data + msg->len) - npdu; + npdu_len = (msg->data + msg->len) - npdu - 3; /* -3 'removes' the FCS */ + if (npdu_len <= 0) { LOGP(DSNDCP, LOGL_ERROR, "Short SNDCP N-PDU: %d\n", npdu_len); return -EIO; } /* actually send the N-PDU to the SGSN core code, which then * hands it off to the correct GTP tunnel + GGSN via gtp_data_req() */ - return sgsn_rx_sndcp_ud_ind(&sne->ra_id, lle->llme->tlli, sne->nsapi, msg, npdu_len, npdu); + + /* Decompress packet */ +#if DEBUG_IP_PACKETS == 1 + DEBUGP(DSNDCP," \n"); + DEBUGP(DSNDCP,"::::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP,"====================================================\n"); + debug_ip_packet(npdu, npdu_len,1,"sndcp_llunitdata_ind()"); +#endif + expnd = talloc_zero_size(msg,npdu_len + 64); + rc = gprs_sndcp_pcomp_expand(expnd, npdu, npdu_len, + sne->pcomp, lle->llme->comp.proto); + sne->pcomp = 0; + if (rc < 0) { + talloc_free(expnd); + return -EIO; + } + else + npdu_len = rc; +#if DEBUG_IP_PACKETS == 1 + debug_ip_packet(expnd, npdu_len,1,"sndcp_llunitdata_ind()"); + DEBUGP(DSNDCP,"====================================================\n"); + DEBUGP(DSNDCP,"::::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP," \n"); +#endif + + /* Hand off packet to gtp */ + rc = sgsn_rx_sndcp_ud_ind(&sne->ra_id, lle->llme->tlli, + sne->nsapi, msg, npdu_len, expnd); + + talloc_free(expnd); + return rc; } #if 0 @@ -619,3 +772,328 @@ case LL_STATUS_IND: } #endif + +/* Generate SNDCP-XID message */ +static int gprs_llc_generate_sndcp_xid(uint8_t *bytes, int bytes_len, + uint8_t nsapi) +{ + LLIST_HEAD(comp_fields); + struct gprs_sndcp_pcomp_rfc1144_params rfc1144_params; + struct gprs_sndcp_comp_field rfc1144_comp_field; + + memset(&rfc1144_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + + /* Setup which NSAPIs shall make use of rfc1144 */ + rfc1144_params.nsapi[0] = nsapi; + rfc1144_params.nsapi_len = 1; + + /* Setup rfc1144 operating parameters */ + rfc1144_params.s01 = sgsn->cfg.pcomp_rfc1144.s01; + + /* Setup rfc1144 compression field */ + rfc1144_comp_field.p = 1; + rfc1144_comp_field.entity = 0; + rfc1144_comp_field.algo = RFC_1144; + rfc1144_comp_field.comp[RFC1144_PCOMP1] = 1; + rfc1144_comp_field.comp[RFC1144_PCOMP2] = 2; + rfc1144_comp_field.comp_len = RFC1144_PCOMP_NUM; + rfc1144_comp_field.rfc1144_params = &rfc1144_params; + + /* Add compression field(s) to list */ + if (sgsn->cfg.pcomp_rfc1144.enabled) + llist_add(&rfc1144_comp_field.list, &comp_fields); + + /* Comile bytestream */ + return gprs_sndcp_compile_xid(bytes, bytes_len, &comp_fields); +} + +/* Set of SNDCP-XID bnegotiation (See also: TS 144 065, + * Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_req(struct gprs_llc_lle *lle, uint8_t nsapi) +{ + /* Note: The specification requires the SNDCP-User to set of an + * SNDCP xid request. See also 3GPP TS 44.065, 6.8 XID parameter + * negotiation, Figure 11: SNDCP XID negotiation procedure. In + * our case the SNDCP-User is sgsn_libgtp.c, which calls + * sndcp_sn_xid_req directly. */ + + uint8_t l3params_bytes[1024]; + int sndcp_xid_bytes_len; + struct gprs_llc_xid_field xid_field_request; + + /* Generate compression parameter bytestream */ + sndcp_xid_bytes_len = gprs_llc_generate_sndcp_xid(l3params_bytes, + sizeof + (l3params_bytes), + nsapi); + + /* Send XID with the SNDCP-XID bytetsream included */ + if (sndcp_xid_bytes_len > 0) { + xid_field_request.type = GPRS_LLC_XID_T_L3_PAR; + xid_field_request.data = l3params_bytes; + xid_field_request.data_len = sndcp_xid_bytes_len; + return gprs_ll_xid_req(lle, &xid_field_request); + } + + /* When bytestream can not be generated, proceed without SNDCP-XID */ + else { + return gprs_ll_xid_req(lle, NULL); + } +} + +/* Hanle header compression entites */ +static int handle_pcomp_entities(struct gprs_sndcp_comp_field *comp_field, + struct gprs_llc_lle *lle) +{ + /* Note: This functions also transforms the comp_field into its + * echo form (strips comp values, resets propose bit etc...) + * the processed comp_fields can then be sent back as XID- + * Response without further modification. */ + + /* Delete propose bit */ + comp_field->p = 0; + + /* Process proposed parameters */ + switch (comp_field->algo) { + case RFC_1144: + if (sgsn->cfg.pcomp_rfc1144.enabled && + comp_field->rfc1144_params->nsapi_len > 0) { + LOGP(DSNDCP, LOGL_DEBUG, + "Accepting RFC1144 header conpression...\n"); + gprs_sndcp_comp_entities_add(lle->llme, + lle->llme->comp.proto, + comp_field); + } else { + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting RFC1144 header conpression...\n"); + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + comp_field->rfc1144_params->nsapi_len = 0; + } + break; + case RFC_2507: + /* RFC 2507 is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting RFC2507 header conpression...\n"); + comp_field->rfc2507_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + break; + case ROHC: + /* ROHC is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting ROHC header conpression...\n"); + comp_field->rohc_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + break; + } + + return 0; +} + +/* Hanle data compression entites */ +static int handle_dcomp_entities(struct gprs_sndcp_comp_field *comp_field, + struct gprs_llc_lle *lle) +{ + /* Note: This functions also transforms the comp_field into its + * echo form (strips comp values, resets propose bit etc...) + * the processed comp_fields can then be sent back as XID- + * Response without further modification. */ + + /* Delete propose bit */ + comp_field->p = 0; + + /* Process proposed parameters */ + switch (comp_field->algo) { + case V42BIS: + /* V42BIS is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting V42BIS data conpression...\n"); + comp_field->rfc2507_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + break; + case V44: + /* V44 is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, "Rejecting V44 data conpression...\n"); + comp_field->rohc_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + break; + } + + return 0; + +} + +/* Process SNDCP-XID indication + * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_ind(struct gprs_llc_xid_field *xid_field_indication, + struct gprs_llc_xid_field *xid_field_response, + struct gprs_llc_lle *lle) +{ + /* Note: This function computes the SNDCP-XID response that is sent + * back to the phone when a phone originated XID is received. The + * Input XID fields are directly processed and the result is directly + * handed back. */ + + int rc; + int compclass; + + struct llist_head *comp_fields; + struct gprs_sndcp_comp_field *comp_field; + + OSMO_ASSERT(xid_field_indication); + OSMO_ASSERT(xid_field_response); + OSMO_ASSERT(lle); + + /* Parse SNDCP-CID XID-Field */ + comp_fields = + gprs_sndcp_parse_xid(lle->llme, xid_field_indication->data, + xid_field_indication->data_len, NULL); + if (!comp_fields) + return -EINVAL; + + /* Don't bother with empty indications */ + if (llist_empty(comp_fields)) { + xid_field_response->data = NULL; + xid_field_response->data_len = 0; + DEBUGP(DSNDCP, + "SNDCP-XID indication did not contain any parameters!\n"); + return 0; + } + + /* Handle compression entites */ + DEBUGP(DSNDCP, "Unmodified SNDCP-XID received from the phone:\n"); + gprs_sndcp_dump_comp_fields(comp_fields, LOGL_DEBUG); + + llist_for_each_entry(comp_field, comp_fields, list) { + compclass = gprs_sndcp_get_compression_class(comp_field); + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + rc = handle_pcomp_entities(comp_field, lle); + else if (compclass == SNDCP_XID_DATA_COMPRESSION) + rc = handle_dcomp_entities(comp_field, lle); + else { + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + rc = 0; + } + + if (rc < 0) { + talloc_free(comp_fields); + return -EINVAL; + } + } + + DEBUGP(DSNDCP, + "Modified version of received SNDCP-XID to be sent back from the ggsn:\n"); + gprs_sndcp_dump_comp_fields(comp_fields, LOGL_DEBUG); + + /* Reserve some memory to store the modified SNDCP-XID bytes */ + xid_field_response->data = + talloc_zero_size(lle->llme, xid_field_indication->data_len); + + /* Set Type flag for response */ + xid_field_response->type = GPRS_LLC_XID_T_L3_PAR; + + /* Compile modified SNDCP-XID bytes */ + rc = gprs_sndcp_compile_xid(xid_field_response->data, + xid_field_indication->data_len, + comp_fields); + + if (rc > 0) + xid_field_response->data_len = rc; + else { + talloc_free(xid_field_response->data); + xid_field_response->data = NULL; + xid_field_response->data_len = 0; + return -EINVAL; + } + + talloc_free(comp_fields); + + return 0; +} + +/* Process SNDCP-XID indication + * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_conf(struct gprs_llc_xid_field *xid_field_confirmation, + struct gprs_llc_xid_field *xid_field_request, + struct gprs_llc_lle *lle) +{ + /* Note: This function handles an incomming SNDCP-XID confirmiation. + * Since the confirmation fields may lack important parameters we + * will reconstruct these missing fields using the original request + * we have sent. After that we will create (or delete) the + * compression entites */ + + struct llist_head *comp_fields_req; + struct llist_head *comp_fields_conf; + struct gprs_sndcp_comp_field *comp_field; + int rc; + int compclass; + + /* We need both, the confirmation that is sent back by the phone, + * and the original request we have sent. If one of this is missing + * we can not process the confirmation, the caller must check if + * request and confirmation fields are available. */ + OSMO_ASSERT(xid_field_confirmation); + OSMO_ASSERT(xid_field_request); + + /* Parse SNDCP-CID XID-Field */ + comp_fields_req = gprs_sndcp_parse_xid(lle->llme, + xid_field_request->data, + xid_field_request->data_len, + NULL); + if (!comp_fields_req) + return -EINVAL; + + DEBUGP(DSNDCP, "Unmodified SNDCP-XID sent from the ggsn:\n"); + gprs_sndcp_dump_comp_fields(comp_fields_req, LOGL_DEBUG); + + /* Parse SNDCP-CID XID-Field */ + comp_fields_conf = gprs_sndcp_parse_xid(lle->llme, + xid_field_confirmation->data, + xid_field_confirmation-> + data_len, comp_fields_req); + if (!comp_fields_conf) + return -EINVAL; + + DEBUGP(DSNDCP, + "Modified version of received SNDCP-XID received from the phone:\n"); + gprs_sndcp_dump_comp_fields(comp_fields_conf, LOGL_DEBUG); + + /* Handle compression entites */ + llist_for_each_entry(comp_field, comp_fields_conf, list) { + compclass = gprs_sndcp_get_compression_class(comp_field); + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + rc = handle_pcomp_entities(comp_field, lle); + else if (compclass == SNDCP_XID_DATA_COMPRESSION) + rc = handle_dcomp_entities(comp_field, lle); + else { + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + rc = 0; + } + + if (rc < 0) { + talloc_free(comp_fields_req); + talloc_free(comp_fields_conf); + return -EINVAL; + } + } + + talloc_free(comp_fields_req); + talloc_free(comp_fields_conf); + + return 0; +} diff --git a/openbsc/src/gprs/gprs_sndcp_comp.c b/openbsc/src/gprs/gprs_sndcp_comp.c new file mode 100644 index 0000000..19cd7b1 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_comp.c @@ -0,0 +1,319 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +/* Create a new compression entity from a XID-Field */ +static struct gprs_sndcp_comp *gprs_sndcp_comp_create(const void *ctx, + const struct + gprs_sndcp_comp_field + *comp_field) +{ + OSMO_ASSERT(comp_field); + + struct gprs_sndcp_comp *comp_entity; + comp_entity = talloc_zero(ctx, struct gprs_sndcp_comp); + + /* Copy relevant information from the SNDCP-XID field */ + comp_entity->entity = comp_field->entity; + comp_entity->comp_len = comp_field->comp_len; + memcpy(comp_entity->comp, comp_field->comp, sizeof(comp_entity->comp)); + + if (comp_field->rfc1144_params) { + comp_entity->nsapi_len = comp_field->rfc1144_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc1144_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->rfc2507_params) { + comp_entity->nsapi_len = comp_field->rfc2507_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc2507_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->rohc_params) { + comp_entity->nsapi_len = comp_field->rohc_params->nsapi_len; + memcpy(comp_entity->nsapi, comp_field->rohc_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->v42bis_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->v44_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + sizeof(comp_entity->nsapi)); + } else { + /* The caller is expected to check carefully if the all + * data fields required for compression entity creation + * are present. Otherwise we blow an assertion here */ + OSMO_ASSERT(false); + } + comp_entity->algo = comp_field->algo; + + /* Check if an NSAPI is selected, if not, it does not make sense + * to create the compression entity, since the caller should + * have checked the presence of the NSAPI, we blow an assertion + * in case of missing NSAPIs */ + OSMO_ASSERT(comp_entity->nsapi_len > 0) + + /* Determine of which class our compression entity will be + * (Protocol or Data compresson ?) */ + comp_entity->compclass = + gprs_sndcp_get_compression_class(comp_field); + OSMO_ASSERT(comp_entity->compclass != -1); + + /* Create an algorithm specific compression context */ + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + if (gprs_sndcp_pcomp_init(ctx, comp_entity, comp_field) != 0) { + talloc_free(comp_entity); + comp_entity = NULL; + } + } else { + LOGP(DSNDCP, LOGL_ERROR, + "We don't support data compression yet!\n"); + talloc_free(comp_entity); + return NULL; + } + + /* Display info message */ + if (comp_entity == NULL) { + LOGP(DSNDCP, LOGL_ERROR, + "Header compression entity (%d) creation failed!\n", + comp_entity->entity); + return NULL; + } + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "New header compression entity (%d) created.\n", + comp_entity->entity); + } else { + LOGP(DSNDCP, LOGL_INFO, + "New data compression entity (%d) created.\n", + comp_entity->entity); + } + + return comp_entity; +} + +/* Allocate a compression enitiy list */ +struct llist_head *gprs_sndcp_comp_alloc(const void *ctx) +{ + struct llist_head *lh; + + lh = talloc_zero(ctx, struct llist_head); + INIT_LLIST_HEAD(lh); + + return lh; +} + +/* Free a compression entitiy list */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities) +{ + struct gprs_sndcp_comp *comp_entity; + + /* We expect the caller to take care of allocating a + * compression entity list properly. Attempting to + * free a non existing list clearly points out + * a malfunction. */ + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + /* Free compression entity */ + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %d ...\n", + comp_entity->entity); + gprs_sndcp_pcomp_term(comp_entity); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %d ...\n", + comp_entity->entity); + } + } + + talloc_free(comp_entities); +} + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, + unsigned int entity) +{ + struct gprs_sndcp_comp *comp_entity; + struct gprs_sndcp_comp *comp_entity_to_delete = NULL; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) + comp_entity_to_delete = comp_entity; + } + + if (!comp_entity_to_delete) + return; + + if (comp_entity_to_delete->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %d ...\n", + comp_entity_to_delete->entity); + gprs_sndcp_pcomp_term(comp_entity_to_delete); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %d ...\n", + comp_entity_to_delete->entity); + } + + /* Delete compression entity */ + llist_del(&comp_entity_to_delete->list); + talloc_free(comp_entity_to_delete); +} + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_entities_add(const void *ctx, + struct llist_head + *comp_entities, + const struct + gprs_sndcp_comp_field + *comp_field) +{ + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(comp_entities); + OSMO_ASSERT(comp_field); + + /* Just to be sure, if the entity is already in + * the list it will be deleted now */ + gprs_sndcp_comp_delete(comp_entities, comp_field->entity); + + /* Create and add a new entity to the list */ + comp_entity = gprs_sndcp_comp_create(ctx, comp_field); + + if (!comp_entity) + return NULL; + + llist_add(&comp_entity->list, comp_entities); + return comp_entity; +} + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head + *comp_entities, uint8_t comp) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return comp_entity; + } + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given pcomp/dcomp value %d.\n", + comp); + return NULL; +} + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head + *comp_entities, uint8_t nsapi) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->nsapi_len; i++) { + if (comp_entity->nsapi[i] == nsapi) + return comp_entity; + } + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given nsapi value %d\n", + nsapi); + return NULL; +} + +/* Find a comp_index for a given pcomp/dcomp value */ +int gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp *comp_entity, int comp) +{ + int i; + + OSMO_ASSERT(comp_entity); + + /* A pcomp/dcomp field set to zero always disables + * all sort of compression and is assigned fix. So we + * just return zero in this case */ + if (comp == 0) + return 0; + + /* Look in the pcomp/dcomp list for the index */ + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return i + 1; + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching comp_index for given pcomp/dcomp value %d\n", + comp); + return 0; +} + +/* Find a pcomp/dcomp value for a given comp_index */ +int gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp *comp_entity, + int comp_index) +{ + OSMO_ASSERT(comp_entity); + + /* A comp_index of zero translates to zero right away. */ + if (comp_index == 0) + return 0; + + if (comp_index > comp_entity->comp_len) { + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching pcomp/dcomp value for given comp_index value %d.\n", + comp_index); + return 0; + } + + /* Look in the pcomp/dcomp list for the comp_index */ + return comp_entity->comp[comp_index - 1]; +} diff --git a/openbsc/src/gprs/gprs_sndcp_pcomp.c b/openbsc/src/gprs/gprs_sndcp_pcomp.c new file mode 100644 index 0000000..0fb72b6 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_pcomp.c @@ -0,0 +1,264 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a new header compression + * entity is created by gprs_sndcp.c */ + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + comp_entity->state = + slhc_init(ctx, comp_field->rfc1144_params->s01 + 1, + comp_field->rfc1144_params->s01 + 1); + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression initalized.\n"); + return 0; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a header compression + * entity is deleted by gprs_sndcp.c */ + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + if (comp_entity->state) { + slhc_free((struct slcompress *)comp_entity->state); + comp_entity->state = NULL; + } + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression terminated.\n"); + return; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Compress a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_compress(uint8_t *pcomp_index, + uint8_t *data_o, uint8_t *data_i, + unsigned int len, + struct slcompress *comp) +{ + uint8_t *comp_ptr; /* Required by slhc_compress() */ + int compr_len; + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Run compressor */ + compr_len = slhc_compress(comp, data_i, len, data_o, &comp_ptr, 0); + + /* Generate pcomp_index */ + if (data_o[0] & SL_TYPE_COMPRESSED_TCP) { + *pcomp_index = 2; + data_o[0] &= ~SL_TYPE_COMPRESSED_TCP; + } else if ((data_o[0] & SL_TYPE_UNCOMPRESSED_TCP) == + SL_TYPE_UNCOMPRESSED_TCP) { + *pcomp_index = 1; + data_o[0] &= 0x4F; + } else + *pcomp_index = 0; + + return compr_len; +} + +/* Expand a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_expand(uint8_t *data_o, uint8_t *data_i, + unsigned int len, + uint8_t pcomp_index, + struct slcompress *comp) +{ + int data_decompressed_len; + int type = -1; + + /* Note: this function should never be called with pcomp_index=0, + * since this condition is already filtered + * out by gprs_sndcp_pcomp_expand() */ + + /* Determine the data type by the PCOMP index */ + switch (pcomp_index) { + case 1: + type = SL_TYPE_UNCOMPRESSED_TCP; + break; + case 2: + type = SL_TYPE_COMPRESSED_TCP; + break; + } + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Restore the original version nibble on + * marked uncompressed packets */ + if (type == SL_TYPE_UNCOMPRESSED_TCP) { + /* Just in case the phone tags uncompressed tcp-datas + * (normally this is handled by pcomp so there is + * no need for tagging the datas) */ + data_o[0] &= 0x4F; + data_decompressed_len = slhc_remember(comp, data_o, len); + return data_decompressed_len; + } + + /* Uncompress compressed packets */ + else if (type == SL_TYPE_COMPRESSED_TCP) { + data_decompressed_len = slhc_uncompress(comp, data_o, len); + return data_decompressed_len; + } + + /* Regular or unknown packets will not be touched */ + return len; +} + +/* Expand packet header */ +int gprs_sndcp_pcomp_expand(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t pcomp, + const struct llist_head *comp_entities) +{ + int rc; + uint8_t pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data_o); + OSMO_ASSERT(data_i); + OSMO_ASSERT(comp_entities); + + /* Skip on pcomp=0 */ + if (pcomp == 0) { + memcpy(data_o, data_i, len); + return len; + } + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_comp(comp_entities, pcomp); + + /* Skip compression if no suitable compression entity can be found */ + if (comp_entity == NULL) { + memcpy(data_o, data_i, len); + return len; + } + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION); + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144); + + /* Find pcomp_index */ + pcomp_index = gprs_sndcp_comp_get_idx(comp_entity, pcomp); + + /* Run decompression algo */ + rc = gprs_sndcp_pcomp_rfc1144_expand(data_o, data_i, len, pcomp_index, + comp_entity->state); + slhc_i_status(comp_entity->state); + slhc_o_status(comp_entity->state); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header expansion done, old length=%d, new length=%d\n", len, rc); + + return rc; +} + +/* Compress packet header */ +int gprs_sndcp_pcomp_compress(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t *pcomp, + const struct llist_head *comp_entities, int nsapi) +{ + int rc; + uint8_t pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data_o); + OSMO_ASSERT(data_i); + OSMO_ASSERT(pcomp); + OSMO_ASSERT(comp_entities); + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_nsapi(comp_entities, nsapi); + + /* Skip compression if no suitable compression entity can be found */ + if (!comp_entity) { + *pcomp = 0; + memcpy(data_o, data_i, len); + return len; + } + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION); + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144); + + /* Run compression algo */ + rc = gprs_sndcp_pcomp_rfc1144_compress(&pcomp_index, data_o, data_i, + len, comp_entity->state); + slhc_i_status(comp_entity->state); + slhc_o_status(comp_entity->state); + + /* Find pcomp value */ + *pcomp = gprs_sndcp_comp_get_comp(comp_entity, pcomp_index); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header compression done, old length=%d, new length=%d\n", + len, rc); + return rc; +} diff --git a/openbsc/src/gprs/sgsn_libgtp.c b/openbsc/src/gprs/sgsn_libgtp.c index be7637a..f548dd6 100644 --- a/openbsc/src/gprs/sgsn_libgtp.c +++ b/openbsc/src/gprs/sgsn_libgtp.c @@ -307,6 +307,9 @@ static int send_act_pdp_cont_acc(struct sgsn_pdp_ctx *pctx) { struct sgsn_signal_data sig_data; + int rc_pdp; + int rc_xid; + struct gprs_llc_lle *lle; /* Inform others about it */ memset(&sig_data, 0, sizeof(sig_data)); @@ -314,7 +317,17 @@ osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_ACT, &sig_data); /* Send PDP CTX ACT to MS */ - return gsm48_tx_gsm_act_pdp_acc(pctx); + rc_pdp = gsm48_tx_gsm_act_pdp_acc(pctx); + if(rc_pdp < 0) + return rc_pdp; + + /* Send SNDCP XID to MS */ + lle = &pctx->mm->gb.llme->lle[pctx->sapi]; + rc_xid = sndcp_sn_xid_req(lle,pctx->nsapi); + if(rc_xid < 0) + return rc_xid; + + return rc_pdp; } /* The GGSN has confirmed the creation of a PDP Context */ diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c index e6dc68d..c7cc268 100644 --- a/openbsc/src/gprs/sgsn_vty.c +++ b/openbsc/src/gprs/sgsn_vty.c @@ -269,6 +269,13 @@ vty_out(vty, " timer t3395 %d%s", g_cfg->timers.T3395, VTY_NEWLINE); vty_out(vty, " timer t3397 %d%s", g_cfg->timers.T3397, VTY_NEWLINE); + if (g_cfg->pcomp_rfc1144.enabled) { + vty_out(vty, " compression rfc1144 slots %d%s", + g_cfg->pcomp_rfc1144.s01+1, VTY_NEWLINE); + } else { + vty_out(vty, " no compression rfc1144%s", VTY_NEWLINE); + } + return CMD_SUCCESS; } @@ -1074,6 +1081,28 @@ return CMD_SUCCESS; } +#define COMPRESSION_STR "Configure compression\n" +DEFUN(cfg_no_comp_rfc1144, cfg_no_comp_rfc1144_cmd, + "no compression rfc1144", + NO_STR COMPRESSION_STR + "disable rfc1144 TCP/IP header compression\n") +{ + g_cfg->pcomp_rfc1144.enabled = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_comp_rfc1144, cfg_comp_rfc1144_cmd, + "compression rfc1144 slots <1-256>", + COMPRESSION_STR + "RFC1144 Header compresion scheme\n" + "Number of compression state slots\n" + "Number of compression state slots\n") +{ + g_cfg->pcomp_rfc1144.enabled = 1; + g_cfg->pcomp_rfc1144.s01 = atoi(argv[0]) - 1; + return CMD_SUCCESS; +} + int sgsn_vty_init(void) { install_element_ve(&show_sgsn_cmd); @@ -1128,6 +1157,9 @@ install_element(SGSN_NODE, &cfg_sgsn_T3395_cmd); install_element(SGSN_NODE, &cfg_sgsn_T3397_cmd); + install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd); + install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd); + return 0; } diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 3e66978..1804280 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -33,6 +33,8 @@ $(top_builddir)/src/gprs/gprs_llc_xid.o \ $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ $(top_builddir)/src/gprs/slhc.o \ + $(top_builddir)/src/gprs/gprs_sndcp_comp.o \ + $(top_builddir)/src/gprs/gprs_sndcp_pcomp.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ -- To view, visit https://gerrit.osmocom.org/642 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 Gerrit-PatchSet: 20 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Fri Aug 19 11:06:49 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Fri, 19 Aug 2016 11:06:49 +0000 Subject: osmo-pcu[master]: jenkins.sh: drop compat with old matrix params In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/701 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I7b50a24cf5879cb473a5cf929768bdd30e863a26 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Fri Aug 19 11:06:54 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Fri, 19 Aug 2016 11:06:54 +0000 Subject: [MERGED] osmo-pcu[master]: jenkins.sh: drop compat with old matrix params In-Reply-To: References: Message-ID: Neels Hofmeyr has submitted this change and it was merged. Change subject: jenkins.sh: drop compat with old matrix params ...................................................................... jenkins.sh: drop compat with old matrix params Change-Id: I7b50a24cf5879cb473a5cf929768bdd30e863a26 --- M contrib/jenkins.sh 1 file changed, 0 insertions(+), 9 deletions(-) Approvals: Neels Hofmeyr: Looks good to me, approved Jenkins Builder: Verified diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index 7826911..7b456c2 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -7,15 +7,6 @@ exit 1 fi -# Compat: to be able to smoothly reconfigure the jenkins job, handle both -# old and new matrix variables -if [ -z "$with_dsp" -a "$sysmodsp" = yes ]; then - with_dsp="sysmo" -else - with_vty="yes" -fi -# end of compat part - base="$PWD" deps="$base/deps" inst="$deps/install" -- To view, visit https://gerrit.osmocom.org/701 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I7b50a24cf5879cb473a5cf929768bdd30e863a26 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Fri Aug 19 11:49:24 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Fri, 19 Aug 2016 11:49:24 +0000 Subject: osmo-pcu[master]: Describe the issue with EGPRS PUAN encoding In-Reply-To: References: Message-ID: Patch Set 1: Code-Review-1 (8 comments) https://gerrit.osmocom.org/#/c/702/1//COMMIT_MSG Commit Message: Line 7: Describe the issue with EGPRS PUAN encoding This commit adds a test case, so the summary should be something like "add test case for ..." Line 17: to be corrected. Sorry, I don't follow at all. * What are you trying to say about the hex values (and why post the same hex values twice)? * What do you mean by "Later"? * What do you mean by "frame work", maybe name a specific test instead? * What exactly is the issue with OTA, maybe add a link to a mailing list posting? Also see inline about adding a wrong assertion, which is my main reason for rejecting. (Though I must admit I don't fully understand the issue this is testing for, the assertion must test for the right behavior.) https://gerrit.osmocom.org/#/c/702/1/tests/tbf/TbfTest.cpp File tests/tbf/TbfTest.cpp: Line 663: Exist_Multislot_capability = 1; (strictly speaking, there is an indent too many before "Exist_") Line 683: OSMO_ASSERT(ul_tbf != NULL); Rather use OSMO_ASSERT(ul_tbf) (drop != NULL). Out of curiosity: check_tbf() below also does the OSMO_ASSERT(ul_tbf), any reason to not use it here as well? Line 696: 0x00 | 0xf << 2, /* GPRS_RLCMAC_DATA_BLOCK << 6, CV = 15 */ Why "0x00 |" ? 0x00 | foo == foo Line 697: uint8_t(0 | (tfi << 1)), 0 | foo == foo? Line 698: uint8_t(1), /* BSN:7, E:1 */ no need to cast to uint8_t, right? Line 753: OSMO_ASSERT(!memcmp(msg2->data, msg1->data, msg1->data_len)); This makes no sense. If this assert is wrong, then this test confirms wrong behavior. Fix the issue and commit the test with the right assertion at the same time. -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Fri Aug 19 11:53:48 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Fri, 19 Aug 2016 11:53:48 +0000 Subject: osmo-pcu[master]: Remove warning while using 'egprs only' command in VTY In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/704 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I62278f998adc691b9a3563ac2a46d756e7bfb66c Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Fri Aug 19 12:13:43 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Fri, 19 Aug 2016 12:13:43 +0000 Subject: osmo-pcu[master]: Describe the issue with EGPRS PUAN encoding In-Reply-To: References: Message-ID: Patch Set 1: Hi Neels, Below patch series is arranged with reference to below mail http://lists.osmocom.org/pipermail/osmocom-net-gprs/2016-July/000680.html Where in https://gerrit.osmocom.org/#/c/702/1 patch explains the issue first with incorrect behaviour. And later https://gerrit.osmocom.org/#/c/703/1 fixes the issue along with modification of assert in test file. Let me know if you are expecting the patch series in different order. The Issue is PUAN is not getting generated properly(or always generated as same hex stream). That is the assert you see with wrong behavior. In next patch in the series same has been updated. please see https://gerrit.osmocom.org/#/c/703/1 to understand it further. Thanks, Aravind Sirsikar -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Fri Aug 19 17:22:27 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Fri, 19 Aug 2016 17:22:27 +0000 Subject: [PATCH] openbsc[master]: Adding compression control and final fixups In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/642 to look at the new patch set (#21). Adding compression control and final fixups - Add module to handle compression entities - Add module to control header compression - Introduce VTY commands for heade compression configuration - Add changes in sndcp and llc to integrate header compression Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 --- M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/gprs_llc.h M openbsc/include/openbsc/gprs_sndcp.h A openbsc/include/openbsc/gprs_sndcp_comp.h A openbsc/include/openbsc/gprs_sndcp_pcomp.h M openbsc/include/openbsc/sgsn.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/gprs_llc.c M openbsc/src/gprs/gprs_sndcp.c A openbsc/src/gprs/gprs_sndcp_comp.c A openbsc/src/gprs/gprs_sndcp_pcomp.c M openbsc/src/gprs/sgsn_libgtp.c M openbsc/src/gprs/sgsn_vty.c M openbsc/tests/sgsn/Makefile.am 14 files changed, 1,342 insertions(+), 34 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/42/642/21 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index f402fea..88a7e2c 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,7 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ - slhc.h + slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h index c3b82b1..4cd6c2e 100644 --- a/openbsc/include/openbsc/gprs_llc.h +++ b/openbsc/include/openbsc/gprs_llc.h @@ -174,6 +174,15 @@ * able to create the compression entity. */ struct llist_head *xid; + /* Compression entities */ + struct { + /* In this two list_heads we will store the + * data and protocol compression entities, + * together with their compression states */ + struct llist_head *proto; + struct llist_head *data; + } comp; + /* Internal management */ uint32_t age_timestamp; }; diff --git a/openbsc/include/openbsc/gprs_sndcp.h b/openbsc/include/openbsc/gprs_sndcp.h index fef871a..cd6ee4e 100644 --- a/openbsc/include/openbsc/gprs_sndcp.h +++ b/openbsc/include/openbsc/gprs_sndcp.h @@ -21,6 +21,16 @@ struct llist_head frag_list; struct osmo_timer_list timer; + + /* Holds state to know which compression mode is used + * when the packet is re-assembled */ + uint8_t pcomp; + uint8_t dcomp; + + /* Holds the pointers to the compression entity list + * that is used when the re-assembled packet is decompressed */ + struct llist_head *proto; + struct llist_head *data; }; /* See 6.7.1.2 Reassembly */ @@ -50,4 +60,20 @@ extern struct llist_head gprs_sndcp_entities; +/* Set of SNDCP-XID negotiation (See also: TS 144 065, + * Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_req(struct gprs_llc_lle *lle, uint8_t nsapi); + +/* Process SNDCP-XID indication (See also: TS 144 065, + * Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_ind(struct gprs_llc_xid_field *xid_field_indication, + struct gprs_llc_xid_field *xid_field_response, + struct gprs_llc_lle *lle); + +/* Process SNDCP-XID indication + * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_conf(struct gprs_llc_xid_field *xid_field_confirmation, + struct gprs_llc_xid_field *xid_field_request, + struct gprs_llc_lle *lle); + #endif /* INT_SNDCP_H */ diff --git a/openbsc/include/openbsc/gprs_sndcp_comp.h b/openbsc/include/openbsc/gprs_sndcp_comp.h new file mode 100644 index 0000000..69441fb --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_comp.h @@ -0,0 +1,84 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +/* Header / Data compression entity */ +struct gprs_sndcp_comp { + struct llist_head list; + + /* Serves as an ID in case we want to delete this entity later */ + unsigned int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + + /* Specifies to which NSAPIs the compression entity is assigned */ + uint8_t nsapi_len; /* Number of applicable NSAPIs (default 0) */ + uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */ + + /* Assigned pcomp values */ + uint8_t comp_len; /* Number of contained PCOMP / DCOMP values */ + uint8_t comp[MAX_COMP]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */ + + /* Algorithm parameters */ + int algo; /* Algorithm type (see gprs_sndcp_xid.h) */ + int compclass; /* See gprs_sndcp_xid.h/c */ + void *state; /* Algorithm status and parameters */ +}; + +#define MAX_COMP 16 /* Maximum number of possible pcomp/dcomp values */ +#define MAX_NSAPI 11 /* Maximum number usable NSAPIs */ + +/* Allocate a compression enitiy list */ +struct llist_head *gprs_sndcp_comp_alloc(const void *ctx); + +/* Free a compression entitiy list */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities); + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, unsigned int entity); + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_entities_add(const void *ctx, struct + llist_head *comp_entities, + const struct + gprs_sndcp_comp_field + *comp_field); + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head + *comp_entities, uint8_t comp); + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head + *comp_entities, uint8_t nsapi); + +/* Find a comp_index for a given pcomp/dcomp value */ +int gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp *comp_entity, + int comp); + +/* Find a pcomp/dcomp value for a given comp_index */ +int gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp *comp_entity, + int comp_index); + diff --git a/openbsc/include/openbsc/gprs_sndcp_pcomp.h b/openbsc/include/openbsc/gprs_sndcp_pcomp.h new file mode 100644 index 0000000..2528a86 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_pcomp.h @@ -0,0 +1,44 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field); + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity); + +/* Expand packet header */ +int gprs_sndcp_pcomp_expand(uint8_t *data_o, uint8_t *data_i, unsigned int len, + uint8_t pcomp, + const struct llist_head *comp_entities); + +/* Compress packet header */ +int gprs_sndcp_pcomp_compress(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t *pcomp, + const struct llist_head *comp_entities, + int nsapi); diff --git a/openbsc/include/openbsc/sgsn.h b/openbsc/include/openbsc/sgsn.h index 59126fe..acd3e4b 100644 --- a/openbsc/include/openbsc/sgsn.h +++ b/openbsc/include/openbsc/sgsn.h @@ -89,6 +89,12 @@ int dynamic_lookup; struct oap_config oap; + + /* RFC1144 TCP/IP Header compression */ + struct { + int enabled; + int s01; + } pcomp_rfc1144; }; struct sgsn_instance { diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 245636b..2910c02 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -27,7 +27,7 @@ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ - slhc.c + slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c index 79795d6..34b7afe 100644 --- a/openbsc/src/gprs/gprs_llc.c +++ b/openbsc/src/gprs/gprs_llc.c @@ -39,6 +39,7 @@ #include #include #include +#include #include static struct gprs_llc_llme *llme_alloc(uint32_t tlli); @@ -88,7 +89,9 @@ llist_add(&l3_xid_field->list, &xid_fields); } - llme->xid = gprs_llc_copy_xid(llme->xid, &xid_fields); + /* Store generated XID for later reference */ + talloc_free(llme->xid); + llme->xid = gprs_llc_copy_xid(llme, &xid_fields); return gprs_llc_compile_xid(bytes, bytes_len, &xid_fields); } @@ -120,7 +123,9 @@ llist_add(&xid_iovui.list, &xid_fields); llist_add(&xid_reset.list, &xid_fields); - llme->xid = gprs_llc_copy_xid(llme->xid, &xid_fields); + /* Store generated XID for later reference */ + talloc_free(llme->xid); + llme->xid = gprs_llc_copy_xid(llme, &xid_fields); return gprs_llc_compile_xid(bytes, bytes_len, &xid_fields); } @@ -135,6 +140,16 @@ struct llist_head *xid_fields; struct gprs_llc_xid_field *xid_field; + struct gprs_llc_xid_field *xid_field_request; + struct gprs_llc_xid_field *xid_field_request_l3 = NULL; + + /* Pick layer3 XID from the XID request we have sent last */ + if (lle->llme->xid) { + llist_for_each_entry(xid_field_request, lle->llme->xid, list) { + if (xid_field_request->type == GPRS_LLC_XID_T_L3_PAR) + xid_field_request_l3 = xid_field_request; + } + } /* Parse and analyze XID-Response */ xid_fields = gprs_llc_parse_xid(NULL, bytes, bytes_len); @@ -145,11 +160,10 @@ llist_for_each_entry(xid_field, xid_fields, list) { /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ - if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { - LOGP(DLLC, LOGL_NOTICE, - "Ignoring SNDCP-XID-Field: XID: type=%i, data_len=%i, data=%s\n", - xid_field->type, xid_field->data_len, - xid_field->data); + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR && + xid_field_request_l3) { + sndcp_sn_xid_conf(xid_field, + xid_field_request_l3, lle); } /* Process LLC-XID fields: */ @@ -163,9 +177,10 @@ * inquiry. There is a remainig risk of * malfunction! */ LOGP(DLLC, LOGL_NOTICE, - "Ignoring XID-Field: XID: type=%i, data_len=%i, data=%s\n", + "Ignoring XID-Field: XID: type=%d, data_len=%d, data=%s\n", xid_field->type, xid_field->data_len, - xid_field->data); + osmo_hexdump_nospc(xid_field->data, + xid_field->data_len)); } } talloc_free(xid_fields); @@ -197,10 +212,6 @@ struct gprs_llc_xid_field *xid_field; struct gprs_llc_xid_field *xid_field_response; - /* Flush eventually pending XID fields */ - talloc_free(lle->llme->xid); - lle->llme->xid = NULL; - /* Parse and analyze XID-Request */ xid_fields = gprs_llc_parse_xid(lle->llme, bytes_request, bytes_request_len); @@ -220,7 +231,7 @@ * when a phone submits values which defer from * the default! */ LOGP(DLLC, LOGL_NOTICE, - "Echoing XID-Field: XID: type=%i, data_len=%i, data=%s\n", + "Echoing XID-Field: XID: type=%d, data_len=%d, data=%s\n", xid_field->type, xid_field->data_len, osmo_hexdump_nospc(xid_field->data, xid_field->data_len)); @@ -229,6 +240,23 @@ (lle->llme, xid_field); llist_add(&xid_field_response->list, xid_fields_response); + } + } + + /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ + llist_for_each_entry(xid_field, xid_fields, list) { + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { + + xid_field_response = + talloc_zero(lle->llme, + struct gprs_llc_xid_field); + rc = sndcp_sn_xid_ind(xid_field, + xid_field_response, lle); + if (rc == 0) + llist_add(&xid_field_response->list, + xid_fields_response); + else + talloc_free(xid_field_response); } } @@ -518,11 +546,16 @@ llist_add(&llme->list, &gprs_llc_llmes); + llme->comp.proto = gprs_sndcp_comp_alloc(llme); + llme->comp.data = gprs_sndcp_comp_alloc(llme); + return llme; } static void llme_free(struct gprs_llc_llme *llme) { + gprs_sndcp_comp_free(llme->comp.proto); + gprs_sndcp_comp_free(llme->comp.data); talloc_free(llme->xid); llist_del(&llme->list); talloc_free(llme); diff --git a/openbsc/src/gprs/gprs_sndcp.c b/openbsc/src/gprs/gprs_sndcp.c index 4f71121..9a6d89a 100644 --- a/openbsc/src/gprs/gprs_sndcp.c +++ b/openbsc/src/gprs/gprs_sndcp.c @@ -35,6 +35,59 @@ #include #include #include +#include +#include +#include +#include + +#define DEBUG_IP_PACKETS 0 /* 0=Disabled, 1=Enabled */ + +#if DEBUG_IP_PACKETS == 1 +/* Show some ip packet details */ +static void debug_ip_packet(uint8_t *data, int len, int dir, char *info) +{ + uint8_t tcp_flags; + char flags_debugmsg[256]; + int len_short; + + if(len > 90) + len_short = 90; + else + len_short = len; + + if (dir) + DEBUGP(DSNDCP,"%s: PHONE => NETWORK: %s\n", info, + osmo_hexdump_nospc(data, len_short)); + else + DEBUGP(DSNDCP,"%s: PHONE <= NETWORK: %s\n", info, + osmo_hexdump_nospc(data, len_short)); + + DEBUGP(DSNDCP,"%s: length: %d\n", info, len); + if (data[9] == 0x06) { + DEBUGP(DSNDCP,"%s: Protocol type: TCP\n", info); + tcp_flags = data[33]; + + memset(flags_debugmsg,0,sizeof(flags_debugmsg)); + if (tcp_flags & 1) + strcat(flags_debugmsg,"FIN "); + if (tcp_flags & 2) + strcat(flags_debugmsg,"SYN "); + if (tcp_flags & 4) + strcat(flags_debugmsg,"RST "); + if (tcp_flags & 8) + strcat(flags_debugmsg,"PSH "); + if (tcp_flags & 16) + strcat(flags_debugmsg,"ACK "); + if (tcp_flags & 32) + strcat(flags_debugmsg,"URG "); + DEBUGP(DSNDCP,"%s: FLAGS: %s\n", info, flags_debugmsg); + } else if (data[9] == 0x11) { + DEBUGP(DSNDCP,"%s: Protocol type: UDP\n", info); + } else { + DEBUGP(DSNDCP,"%s: Protocol type: (%02x)\n", info, data[9]); + } +} +#endif /* Chapter 7.2: SN-PDU Formats */ struct sndcp_common_hdr { @@ -143,6 +196,9 @@ struct msgb *msg; unsigned int seg_nr; uint8_t *npdu; + int npdu_len; + int rc; + uint8_t *expnd; LOGP(DSNDCP, LOGL_DEBUG, "TLLI=0x%08x NSAPI=%u: Defragment output PDU %u " "num_seg=%u tot_len=%u\n", sne->lle->llme->tlli, sne->nsapi, @@ -173,16 +229,46 @@ talloc_free(dqe); } + npdu_len = sne->defrag.tot_len; + /* FIXME: cancel timer */ /* actually send the N-PDU to the SGSN core code, which then * hands it off to the correct GTP tunnel + GGSN via gtp_data_req() */ - return sgsn_rx_sndcp_ud_ind(&sne->ra_id, sne->lle->llme->tlli, - sne->nsapi, msg, sne->defrag.tot_len, npdu); + + /* Decompress packet */ +#if DEBUG_IP_PACKETS == 1 + DEBUGP(DSNDCP," \n"); + DEBUGP(DSNDCP,"::::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP,"====================================================\n"); + debug_ip_packet(npdu, npdu_len,1,"defrag_segments()"); +#endif + expnd = talloc_zero_size(msg,msg->len + 64); + rc = gprs_sndcp_pcomp_expand(expnd, npdu, npdu_len, + sne->defrag.pcomp, sne->defrag.proto); + if (rc < 0) { + talloc_free(expnd); + return -EIO; + } + else + npdu_len = rc; +#if DEBUG_IP_PACKETS == 1 + debug_ip_packet(expnd, npdu_len,1,"defrag_segments()"); + DEBUGP(DSNDCP,"====================================================\n"); + DEBUGP(DSNDCP,"::::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP," \n"); +#endif + + /* Hand off packet to gtp */ + rc = sgsn_rx_sndcp_ud_ind(&sne->ra_id, sne->lle->llme->tlli, + sne->nsapi, msg, npdu_len, expnd); + + talloc_free(expnd); + return rc; } -static int defrag_input(struct gprs_sndcp_entity *sne, struct msgb *msg, uint8_t *hdr, - unsigned int len) +static int defrag_input(struct gprs_sndcp_entity *sne, struct msgb *msg, + uint8_t *hdr, unsigned int len) { struct sndcp_common_hdr *sch; struct sndcp_udata_hdr *suh; @@ -343,7 +429,8 @@ }; /* returns '1' if there are more fragments to send, '0' if none */ -static int sndcp_send_ud_frag(struct sndcp_frag_state *fs) +static int sndcp_send_ud_frag(struct sndcp_frag_state *fs, + uint8_t pcomp, uint8_t dcomp) { struct gprs_sndcp_entity *sne = fs->sne; struct gprs_llc_lle *lle = sne->lle; @@ -380,8 +467,8 @@ if (sch->first) { scomph = (struct sndcp_comp_hdr *) msgb_put(fmsg, sizeof(*scomph)); - scomph->pcomp = 0; - scomph->dcomp = 0; + scomph->pcomp = pcomp; + scomph->dcomp = dcomp; } /* append the user-data header */ @@ -446,8 +533,38 @@ struct sndcp_comp_hdr *scomph; struct sndcp_udata_hdr *suh; struct sndcp_frag_state fs; + uint8_t pcomp = 0; + uint8_t dcomp = 0; + int rc; + uint8_t *compr; /* Identifiers from UP: (TLLI, SAPI) + (BVCI, NSEI) */ + + /* Compress packet */ +#if DEBUG_IP_PACKETS == 1 + DEBUGP(DSNDCP," \n"); + DEBUGP(DSNDCP,"::::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP,"====================================================\n"); + debug_ip_packet(msg->data, msg->len,0,"sndcp_initdata_req()"); +#endif + compr = talloc_zero_size(msg, msg->len); + rc = gprs_sndcp_pcomp_compress(compr,msg->data, msg->len, &pcomp, + lle->llme->comp.proto, nsapi); + if (rc < 0) { + talloc_free(compr); + return -EIO; + } + else { + msg->len = rc; + memcpy(msg->data,compr,rc); + } + talloc_free(compr); +#if DEBUG_IP_PACKETS == 1 + debug_ip_packet(msg->data, msg->len,0,"sndcp_initdata_req()"); + DEBUGP(DSNDCP,"====================================================\n"); + DEBUGP(DSNDCP,"::::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP," \n"); +#endif sne = gprs_sndcp_entity_by_lle(lle, nsapi); if (!sne) { @@ -469,7 +586,7 @@ /* call function to generate and send fragments until all * of the N-PDU has been sent */ while (1) { - int rc = sndcp_send_ud_frag(&fs); + int rc = sndcp_send_ud_frag(&fs,pcomp,dcomp); if (rc == 0) return 0; if (rc < 0) @@ -489,8 +606,8 @@ sne->tx_npdu_nr = (sne->tx_npdu_nr + 1) % 0xfff; scomph = (struct sndcp_comp_hdr *) msgb_push(msg, sizeof(*scomph)); - scomph->pcomp = 0; - scomph->dcomp = 0; + scomph->pcomp = pcomp; + scomph->dcomp = dcomp; /* prepend common SNDCP header */ sch = (struct sndcp_common_hdr *) msgb_push(msg, sizeof(*sch)); @@ -512,6 +629,8 @@ uint8_t *npdu; uint16_t npdu_num __attribute__((unused)); int npdu_len; + int rc; + uint8_t *expnd; sch = (struct sndcp_common_hdr *) hdr; if (sch->first) { @@ -540,26 +659,58 @@ /* FIXME: move this RA_ID up to the LLME or even higher */ bssgp_parse_cell_id(&sne->ra_id, msgb_bcid(msg)); + if(scomph) { + sne->defrag.pcomp = scomph->pcomp; + sne->defrag.dcomp = scomph->dcomp; + sne->defrag.proto = lle->llme->comp.proto; + sne->defrag.data = lle->llme->comp.data; + } + /* any non-first segment is by definition something to defragment * as is any segment that tells us there are more segments */ if (!sch->first || sch->more) return defrag_input(sne, msg, hdr, len); - if (scomph && (scomph->pcomp || scomph->dcomp)) { - LOGP(DSNDCP, LOGL_ERROR, "We don't support compression yet\n"); - return -EIO; - } - npdu_num = (suh->npdu_high << 8) | suh->npdu_low; npdu = (uint8_t *)suh + sizeof(*suh); - npdu_len = (msg->data + msg->len) - npdu; + npdu_len = (msg->data + msg->len) - npdu - 3; /* -3 'removes' the FCS */ + if (npdu_len <= 0) { LOGP(DSNDCP, LOGL_ERROR, "Short SNDCP N-PDU: %d\n", npdu_len); return -EIO; } /* actually send the N-PDU to the SGSN core code, which then * hands it off to the correct GTP tunnel + GGSN via gtp_data_req() */ - return sgsn_rx_sndcp_ud_ind(&sne->ra_id, lle->llme->tlli, sne->nsapi, msg, npdu_len, npdu); + + /* Decompress packet */ +#if DEBUG_IP_PACKETS == 1 + DEBUGP(DSNDCP," \n"); + DEBUGP(DSNDCP,"::::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP,"====================================================\n"); + debug_ip_packet(npdu, npdu_len,1,"sndcp_llunitdata_ind()"); +#endif + expnd = talloc_zero_size(msg,npdu_len + 64); + rc = gprs_sndcp_pcomp_expand(expnd, npdu, npdu_len, + sne->defrag.pcomp, sne->defrag.proto); + if (rc < 0) { + talloc_free(expnd); + return -EIO; + } + else + npdu_len = rc; +#if DEBUG_IP_PACKETS == 1 + debug_ip_packet(expnd, npdu_len,1,"sndcp_llunitdata_ind()"); + DEBUGP(DSNDCP,"====================================================\n"); + DEBUGP(DSNDCP,"::::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP," \n"); +#endif + + /* Hand off packet to gtp */ + rc = sgsn_rx_sndcp_ud_ind(&sne->ra_id, lle->llme->tlli, + sne->nsapi, msg, npdu_len, expnd); + + talloc_free(expnd); + return rc; } #if 0 @@ -619,3 +770,328 @@ case LL_STATUS_IND: } #endif + +/* Generate SNDCP-XID message */ +static int gprs_llc_generate_sndcp_xid(uint8_t *bytes, int bytes_len, + uint8_t nsapi) +{ + LLIST_HEAD(comp_fields); + struct gprs_sndcp_pcomp_rfc1144_params rfc1144_params; + struct gprs_sndcp_comp_field rfc1144_comp_field; + + memset(&rfc1144_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + + /* Setup which NSAPIs shall make use of rfc1144 */ + rfc1144_params.nsapi[0] = nsapi; + rfc1144_params.nsapi_len = 1; + + /* Setup rfc1144 operating parameters */ + rfc1144_params.s01 = sgsn->cfg.pcomp_rfc1144.s01; + + /* Setup rfc1144 compression field */ + rfc1144_comp_field.p = 1; + rfc1144_comp_field.entity = 0; + rfc1144_comp_field.algo = RFC_1144; + rfc1144_comp_field.comp[RFC1144_PCOMP1] = 1; + rfc1144_comp_field.comp[RFC1144_PCOMP2] = 2; + rfc1144_comp_field.comp_len = RFC1144_PCOMP_NUM; + rfc1144_comp_field.rfc1144_params = &rfc1144_params; + + /* Add compression field(s) to list */ + if (sgsn->cfg.pcomp_rfc1144.enabled) + llist_add(&rfc1144_comp_field.list, &comp_fields); + + /* Comile bytestream */ + return gprs_sndcp_compile_xid(bytes, bytes_len, &comp_fields); +} + +/* Set of SNDCP-XID bnegotiation (See also: TS 144 065, + * Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_req(struct gprs_llc_lle *lle, uint8_t nsapi) +{ + /* Note: The specification requires the SNDCP-User to set of an + * SNDCP xid request. See also 3GPP TS 44.065, 6.8 XID parameter + * negotiation, Figure 11: SNDCP XID negotiation procedure. In + * our case the SNDCP-User is sgsn_libgtp.c, which calls + * sndcp_sn_xid_req directly. */ + + uint8_t l3params_bytes[1024]; + int sndcp_xid_bytes_len; + struct gprs_llc_xid_field xid_field_request; + + /* Generate compression parameter bytestream */ + sndcp_xid_bytes_len = gprs_llc_generate_sndcp_xid(l3params_bytes, + sizeof + (l3params_bytes), + nsapi); + + /* Send XID with the SNDCP-XID bytetsream included */ + if (sndcp_xid_bytes_len > 0) { + xid_field_request.type = GPRS_LLC_XID_T_L3_PAR; + xid_field_request.data = l3params_bytes; + xid_field_request.data_len = sndcp_xid_bytes_len; + return gprs_ll_xid_req(lle, &xid_field_request); + } + + /* When bytestream can not be generated, proceed without SNDCP-XID */ + else { + return gprs_ll_xid_req(lle, NULL); + } +} + +/* Hanle header compression entites */ +static int handle_pcomp_entities(struct gprs_sndcp_comp_field *comp_field, + struct gprs_llc_lle *lle) +{ + /* Note: This functions also transforms the comp_field into its + * echo form (strips comp values, resets propose bit etc...) + * the processed comp_fields can then be sent back as XID- + * Response without further modification. */ + + /* Delete propose bit */ + comp_field->p = 0; + + /* Process proposed parameters */ + switch (comp_field->algo) { + case RFC_1144: + if (sgsn->cfg.pcomp_rfc1144.enabled && + comp_field->rfc1144_params->nsapi_len > 0) { + LOGP(DSNDCP, LOGL_DEBUG, + "Accepting RFC1144 header conpression...\n"); + gprs_sndcp_comp_entities_add(lle->llme, + lle->llme->comp.proto, + comp_field); + } else { + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting RFC1144 header conpression...\n"); + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + comp_field->rfc1144_params->nsapi_len = 0; + } + break; + case RFC_2507: + /* RFC 2507 is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting RFC2507 header conpression...\n"); + comp_field->rfc2507_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + break; + case ROHC: + /* ROHC is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting ROHC header conpression...\n"); + comp_field->rohc_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + break; + } + + return 0; +} + +/* Hanle data compression entites */ +static int handle_dcomp_entities(struct gprs_sndcp_comp_field *comp_field, + struct gprs_llc_lle *lle) +{ + /* Note: This functions also transforms the comp_field into its + * echo form (strips comp values, resets propose bit etc...) + * the processed comp_fields can then be sent back as XID- + * Response without further modification. */ + + /* Delete propose bit */ + comp_field->p = 0; + + /* Process proposed parameters */ + switch (comp_field->algo) { + case V42BIS: + /* V42BIS is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting V42BIS data conpression...\n"); + comp_field->rfc2507_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + break; + case V44: + /* V44 is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, "Rejecting V44 data conpression...\n"); + comp_field->rohc_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + break; + } + + return 0; + +} + +/* Process SNDCP-XID indication + * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_ind(struct gprs_llc_xid_field *xid_field_indication, + struct gprs_llc_xid_field *xid_field_response, + struct gprs_llc_lle *lle) +{ + /* Note: This function computes the SNDCP-XID response that is sent + * back to the phone when a phone originated XID is received. The + * Input XID fields are directly processed and the result is directly + * handed back. */ + + int rc; + int compclass; + + struct llist_head *comp_fields; + struct gprs_sndcp_comp_field *comp_field; + + OSMO_ASSERT(xid_field_indication); + OSMO_ASSERT(xid_field_response); + OSMO_ASSERT(lle); + + /* Parse SNDCP-CID XID-Field */ + comp_fields = + gprs_sndcp_parse_xid(lle->llme, xid_field_indication->data, + xid_field_indication->data_len, NULL); + if (!comp_fields) + return -EINVAL; + + /* Don't bother with empty indications */ + if (llist_empty(comp_fields)) { + xid_field_response->data = NULL; + xid_field_response->data_len = 0; + DEBUGP(DSNDCP, + "SNDCP-XID indication did not contain any parameters!\n"); + return 0; + } + + /* Handle compression entites */ + DEBUGP(DSNDCP, "Unmodified SNDCP-XID received from the phone:\n"); + gprs_sndcp_dump_comp_fields(comp_fields, LOGL_DEBUG); + + llist_for_each_entry(comp_field, comp_fields, list) { + compclass = gprs_sndcp_get_compression_class(comp_field); + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + rc = handle_pcomp_entities(comp_field, lle); + else if (compclass == SNDCP_XID_DATA_COMPRESSION) + rc = handle_dcomp_entities(comp_field, lle); + else { + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + rc = 0; + } + + if (rc < 0) { + talloc_free(comp_fields); + return -EINVAL; + } + } + + DEBUGP(DSNDCP, + "Modified version of received SNDCP-XID to be sent back from the ggsn:\n"); + gprs_sndcp_dump_comp_fields(comp_fields, LOGL_DEBUG); + + /* Reserve some memory to store the modified SNDCP-XID bytes */ + xid_field_response->data = + talloc_zero_size(lle->llme, xid_field_indication->data_len); + + /* Set Type flag for response */ + xid_field_response->type = GPRS_LLC_XID_T_L3_PAR; + + /* Compile modified SNDCP-XID bytes */ + rc = gprs_sndcp_compile_xid(xid_field_response->data, + xid_field_indication->data_len, + comp_fields); + + if (rc > 0) + xid_field_response->data_len = rc; + else { + talloc_free(xid_field_response->data); + xid_field_response->data = NULL; + xid_field_response->data_len = 0; + return -EINVAL; + } + + talloc_free(comp_fields); + + return 0; +} + +/* Process SNDCP-XID indication + * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_conf(struct gprs_llc_xid_field *xid_field_confirmation, + struct gprs_llc_xid_field *xid_field_request, + struct gprs_llc_lle *lle) +{ + /* Note: This function handles an incomming SNDCP-XID confirmiation. + * Since the confirmation fields may lack important parameters we + * will reconstruct these missing fields using the original request + * we have sent. After that we will create (or delete) the + * compression entites */ + + struct llist_head *comp_fields_req; + struct llist_head *comp_fields_conf; + struct gprs_sndcp_comp_field *comp_field; + int rc; + int compclass; + + /* We need both, the confirmation that is sent back by the phone, + * and the original request we have sent. If one of this is missing + * we can not process the confirmation, the caller must check if + * request and confirmation fields are available. */ + OSMO_ASSERT(xid_field_confirmation); + OSMO_ASSERT(xid_field_request); + + /* Parse SNDCP-CID XID-Field */ + comp_fields_req = gprs_sndcp_parse_xid(lle->llme, + xid_field_request->data, + xid_field_request->data_len, + NULL); + if (!comp_fields_req) + return -EINVAL; + + DEBUGP(DSNDCP, "Unmodified SNDCP-XID sent from the ggsn:\n"); + gprs_sndcp_dump_comp_fields(comp_fields_req, LOGL_DEBUG); + + /* Parse SNDCP-CID XID-Field */ + comp_fields_conf = gprs_sndcp_parse_xid(lle->llme, + xid_field_confirmation->data, + xid_field_confirmation-> + data_len, comp_fields_req); + if (!comp_fields_conf) + return -EINVAL; + + DEBUGP(DSNDCP, + "Modified version of received SNDCP-XID received from the phone:\n"); + gprs_sndcp_dump_comp_fields(comp_fields_conf, LOGL_DEBUG); + + /* Handle compression entites */ + llist_for_each_entry(comp_field, comp_fields_conf, list) { + compclass = gprs_sndcp_get_compression_class(comp_field); + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + rc = handle_pcomp_entities(comp_field, lle); + else if (compclass == SNDCP_XID_DATA_COMPRESSION) + rc = handle_dcomp_entities(comp_field, lle); + else { + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + rc = 0; + } + + if (rc < 0) { + talloc_free(comp_fields_req); + talloc_free(comp_fields_conf); + return -EINVAL; + } + } + + talloc_free(comp_fields_req); + talloc_free(comp_fields_conf); + + return 0; +} diff --git a/openbsc/src/gprs/gprs_sndcp_comp.c b/openbsc/src/gprs/gprs_sndcp_comp.c new file mode 100644 index 0000000..19cd7b1 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_comp.c @@ -0,0 +1,319 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +/* Create a new compression entity from a XID-Field */ +static struct gprs_sndcp_comp *gprs_sndcp_comp_create(const void *ctx, + const struct + gprs_sndcp_comp_field + *comp_field) +{ + OSMO_ASSERT(comp_field); + + struct gprs_sndcp_comp *comp_entity; + comp_entity = talloc_zero(ctx, struct gprs_sndcp_comp); + + /* Copy relevant information from the SNDCP-XID field */ + comp_entity->entity = comp_field->entity; + comp_entity->comp_len = comp_field->comp_len; + memcpy(comp_entity->comp, comp_field->comp, sizeof(comp_entity->comp)); + + if (comp_field->rfc1144_params) { + comp_entity->nsapi_len = comp_field->rfc1144_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc1144_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->rfc2507_params) { + comp_entity->nsapi_len = comp_field->rfc2507_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc2507_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->rohc_params) { + comp_entity->nsapi_len = comp_field->rohc_params->nsapi_len; + memcpy(comp_entity->nsapi, comp_field->rohc_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->v42bis_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->v44_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + sizeof(comp_entity->nsapi)); + } else { + /* The caller is expected to check carefully if the all + * data fields required for compression entity creation + * are present. Otherwise we blow an assertion here */ + OSMO_ASSERT(false); + } + comp_entity->algo = comp_field->algo; + + /* Check if an NSAPI is selected, if not, it does not make sense + * to create the compression entity, since the caller should + * have checked the presence of the NSAPI, we blow an assertion + * in case of missing NSAPIs */ + OSMO_ASSERT(comp_entity->nsapi_len > 0) + + /* Determine of which class our compression entity will be + * (Protocol or Data compresson ?) */ + comp_entity->compclass = + gprs_sndcp_get_compression_class(comp_field); + OSMO_ASSERT(comp_entity->compclass != -1); + + /* Create an algorithm specific compression context */ + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + if (gprs_sndcp_pcomp_init(ctx, comp_entity, comp_field) != 0) { + talloc_free(comp_entity); + comp_entity = NULL; + } + } else { + LOGP(DSNDCP, LOGL_ERROR, + "We don't support data compression yet!\n"); + talloc_free(comp_entity); + return NULL; + } + + /* Display info message */ + if (comp_entity == NULL) { + LOGP(DSNDCP, LOGL_ERROR, + "Header compression entity (%d) creation failed!\n", + comp_entity->entity); + return NULL; + } + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "New header compression entity (%d) created.\n", + comp_entity->entity); + } else { + LOGP(DSNDCP, LOGL_INFO, + "New data compression entity (%d) created.\n", + comp_entity->entity); + } + + return comp_entity; +} + +/* Allocate a compression enitiy list */ +struct llist_head *gprs_sndcp_comp_alloc(const void *ctx) +{ + struct llist_head *lh; + + lh = talloc_zero(ctx, struct llist_head); + INIT_LLIST_HEAD(lh); + + return lh; +} + +/* Free a compression entitiy list */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities) +{ + struct gprs_sndcp_comp *comp_entity; + + /* We expect the caller to take care of allocating a + * compression entity list properly. Attempting to + * free a non existing list clearly points out + * a malfunction. */ + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + /* Free compression entity */ + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %d ...\n", + comp_entity->entity); + gprs_sndcp_pcomp_term(comp_entity); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %d ...\n", + comp_entity->entity); + } + } + + talloc_free(comp_entities); +} + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, + unsigned int entity) +{ + struct gprs_sndcp_comp *comp_entity; + struct gprs_sndcp_comp *comp_entity_to_delete = NULL; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) + comp_entity_to_delete = comp_entity; + } + + if (!comp_entity_to_delete) + return; + + if (comp_entity_to_delete->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %d ...\n", + comp_entity_to_delete->entity); + gprs_sndcp_pcomp_term(comp_entity_to_delete); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %d ...\n", + comp_entity_to_delete->entity); + } + + /* Delete compression entity */ + llist_del(&comp_entity_to_delete->list); + talloc_free(comp_entity_to_delete); +} + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_entities_add(const void *ctx, + struct llist_head + *comp_entities, + const struct + gprs_sndcp_comp_field + *comp_field) +{ + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(comp_entities); + OSMO_ASSERT(comp_field); + + /* Just to be sure, if the entity is already in + * the list it will be deleted now */ + gprs_sndcp_comp_delete(comp_entities, comp_field->entity); + + /* Create and add a new entity to the list */ + comp_entity = gprs_sndcp_comp_create(ctx, comp_field); + + if (!comp_entity) + return NULL; + + llist_add(&comp_entity->list, comp_entities); + return comp_entity; +} + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head + *comp_entities, uint8_t comp) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return comp_entity; + } + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given pcomp/dcomp value %d.\n", + comp); + return NULL; +} + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head + *comp_entities, uint8_t nsapi) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->nsapi_len; i++) { + if (comp_entity->nsapi[i] == nsapi) + return comp_entity; + } + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given nsapi value %d\n", + nsapi); + return NULL; +} + +/* Find a comp_index for a given pcomp/dcomp value */ +int gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp *comp_entity, int comp) +{ + int i; + + OSMO_ASSERT(comp_entity); + + /* A pcomp/dcomp field set to zero always disables + * all sort of compression and is assigned fix. So we + * just return zero in this case */ + if (comp == 0) + return 0; + + /* Look in the pcomp/dcomp list for the index */ + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return i + 1; + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching comp_index for given pcomp/dcomp value %d\n", + comp); + return 0; +} + +/* Find a pcomp/dcomp value for a given comp_index */ +int gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp *comp_entity, + int comp_index) +{ + OSMO_ASSERT(comp_entity); + + /* A comp_index of zero translates to zero right away. */ + if (comp_index == 0) + return 0; + + if (comp_index > comp_entity->comp_len) { + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching pcomp/dcomp value for given comp_index value %d.\n", + comp_index); + return 0; + } + + /* Look in the pcomp/dcomp list for the comp_index */ + return comp_entity->comp[comp_index - 1]; +} diff --git a/openbsc/src/gprs/gprs_sndcp_pcomp.c b/openbsc/src/gprs/gprs_sndcp_pcomp.c new file mode 100644 index 0000000..0fb72b6 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_pcomp.c @@ -0,0 +1,264 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a new header compression + * entity is created by gprs_sndcp.c */ + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + comp_entity->state = + slhc_init(ctx, comp_field->rfc1144_params->s01 + 1, + comp_field->rfc1144_params->s01 + 1); + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression initalized.\n"); + return 0; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a header compression + * entity is deleted by gprs_sndcp.c */ + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + if (comp_entity->state) { + slhc_free((struct slcompress *)comp_entity->state); + comp_entity->state = NULL; + } + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression terminated.\n"); + return; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Compress a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_compress(uint8_t *pcomp_index, + uint8_t *data_o, uint8_t *data_i, + unsigned int len, + struct slcompress *comp) +{ + uint8_t *comp_ptr; /* Required by slhc_compress() */ + int compr_len; + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Run compressor */ + compr_len = slhc_compress(comp, data_i, len, data_o, &comp_ptr, 0); + + /* Generate pcomp_index */ + if (data_o[0] & SL_TYPE_COMPRESSED_TCP) { + *pcomp_index = 2; + data_o[0] &= ~SL_TYPE_COMPRESSED_TCP; + } else if ((data_o[0] & SL_TYPE_UNCOMPRESSED_TCP) == + SL_TYPE_UNCOMPRESSED_TCP) { + *pcomp_index = 1; + data_o[0] &= 0x4F; + } else + *pcomp_index = 0; + + return compr_len; +} + +/* Expand a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_expand(uint8_t *data_o, uint8_t *data_i, + unsigned int len, + uint8_t pcomp_index, + struct slcompress *comp) +{ + int data_decompressed_len; + int type = -1; + + /* Note: this function should never be called with pcomp_index=0, + * since this condition is already filtered + * out by gprs_sndcp_pcomp_expand() */ + + /* Determine the data type by the PCOMP index */ + switch (pcomp_index) { + case 1: + type = SL_TYPE_UNCOMPRESSED_TCP; + break; + case 2: + type = SL_TYPE_COMPRESSED_TCP; + break; + } + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Restore the original version nibble on + * marked uncompressed packets */ + if (type == SL_TYPE_UNCOMPRESSED_TCP) { + /* Just in case the phone tags uncompressed tcp-datas + * (normally this is handled by pcomp so there is + * no need for tagging the datas) */ + data_o[0] &= 0x4F; + data_decompressed_len = slhc_remember(comp, data_o, len); + return data_decompressed_len; + } + + /* Uncompress compressed packets */ + else if (type == SL_TYPE_COMPRESSED_TCP) { + data_decompressed_len = slhc_uncompress(comp, data_o, len); + return data_decompressed_len; + } + + /* Regular or unknown packets will not be touched */ + return len; +} + +/* Expand packet header */ +int gprs_sndcp_pcomp_expand(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t pcomp, + const struct llist_head *comp_entities) +{ + int rc; + uint8_t pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data_o); + OSMO_ASSERT(data_i); + OSMO_ASSERT(comp_entities); + + /* Skip on pcomp=0 */ + if (pcomp == 0) { + memcpy(data_o, data_i, len); + return len; + } + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_comp(comp_entities, pcomp); + + /* Skip compression if no suitable compression entity can be found */ + if (comp_entity == NULL) { + memcpy(data_o, data_i, len); + return len; + } + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION); + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144); + + /* Find pcomp_index */ + pcomp_index = gprs_sndcp_comp_get_idx(comp_entity, pcomp); + + /* Run decompression algo */ + rc = gprs_sndcp_pcomp_rfc1144_expand(data_o, data_i, len, pcomp_index, + comp_entity->state); + slhc_i_status(comp_entity->state); + slhc_o_status(comp_entity->state); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header expansion done, old length=%d, new length=%d\n", len, rc); + + return rc; +} + +/* Compress packet header */ +int gprs_sndcp_pcomp_compress(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t *pcomp, + const struct llist_head *comp_entities, int nsapi) +{ + int rc; + uint8_t pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data_o); + OSMO_ASSERT(data_i); + OSMO_ASSERT(pcomp); + OSMO_ASSERT(comp_entities); + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_nsapi(comp_entities, nsapi); + + /* Skip compression if no suitable compression entity can be found */ + if (!comp_entity) { + *pcomp = 0; + memcpy(data_o, data_i, len); + return len; + } + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION); + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144); + + /* Run compression algo */ + rc = gprs_sndcp_pcomp_rfc1144_compress(&pcomp_index, data_o, data_i, + len, comp_entity->state); + slhc_i_status(comp_entity->state); + slhc_o_status(comp_entity->state); + + /* Find pcomp value */ + *pcomp = gprs_sndcp_comp_get_comp(comp_entity, pcomp_index); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header compression done, old length=%d, new length=%d\n", + len, rc); + return rc; +} diff --git a/openbsc/src/gprs/sgsn_libgtp.c b/openbsc/src/gprs/sgsn_libgtp.c index be7637a..f548dd6 100644 --- a/openbsc/src/gprs/sgsn_libgtp.c +++ b/openbsc/src/gprs/sgsn_libgtp.c @@ -307,6 +307,9 @@ static int send_act_pdp_cont_acc(struct sgsn_pdp_ctx *pctx) { struct sgsn_signal_data sig_data; + int rc_pdp; + int rc_xid; + struct gprs_llc_lle *lle; /* Inform others about it */ memset(&sig_data, 0, sizeof(sig_data)); @@ -314,7 +317,17 @@ osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_ACT, &sig_data); /* Send PDP CTX ACT to MS */ - return gsm48_tx_gsm_act_pdp_acc(pctx); + rc_pdp = gsm48_tx_gsm_act_pdp_acc(pctx); + if(rc_pdp < 0) + return rc_pdp; + + /* Send SNDCP XID to MS */ + lle = &pctx->mm->gb.llme->lle[pctx->sapi]; + rc_xid = sndcp_sn_xid_req(lle,pctx->nsapi); + if(rc_xid < 0) + return rc_xid; + + return rc_pdp; } /* The GGSN has confirmed the creation of a PDP Context */ diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c index e6dc68d..c7cc268 100644 --- a/openbsc/src/gprs/sgsn_vty.c +++ b/openbsc/src/gprs/sgsn_vty.c @@ -269,6 +269,13 @@ vty_out(vty, " timer t3395 %d%s", g_cfg->timers.T3395, VTY_NEWLINE); vty_out(vty, " timer t3397 %d%s", g_cfg->timers.T3397, VTY_NEWLINE); + if (g_cfg->pcomp_rfc1144.enabled) { + vty_out(vty, " compression rfc1144 slots %d%s", + g_cfg->pcomp_rfc1144.s01+1, VTY_NEWLINE); + } else { + vty_out(vty, " no compression rfc1144%s", VTY_NEWLINE); + } + return CMD_SUCCESS; } @@ -1074,6 +1081,28 @@ return CMD_SUCCESS; } +#define COMPRESSION_STR "Configure compression\n" +DEFUN(cfg_no_comp_rfc1144, cfg_no_comp_rfc1144_cmd, + "no compression rfc1144", + NO_STR COMPRESSION_STR + "disable rfc1144 TCP/IP header compression\n") +{ + g_cfg->pcomp_rfc1144.enabled = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_comp_rfc1144, cfg_comp_rfc1144_cmd, + "compression rfc1144 slots <1-256>", + COMPRESSION_STR + "RFC1144 Header compresion scheme\n" + "Number of compression state slots\n" + "Number of compression state slots\n") +{ + g_cfg->pcomp_rfc1144.enabled = 1; + g_cfg->pcomp_rfc1144.s01 = atoi(argv[0]) - 1; + return CMD_SUCCESS; +} + int sgsn_vty_init(void) { install_element_ve(&show_sgsn_cmd); @@ -1128,6 +1157,9 @@ install_element(SGSN_NODE, &cfg_sgsn_T3395_cmd); install_element(SGSN_NODE, &cfg_sgsn_T3397_cmd); + install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd); + install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd); + return 0; } diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 3e66978..1804280 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -33,6 +33,8 @@ $(top_builddir)/src/gprs/gprs_llc_xid.o \ $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ $(top_builddir)/src/gprs/slhc.o \ + $(top_builddir)/src/gprs/gprs_sndcp_comp.o \ + $(top_builddir)/src/gprs/gprs_sndcp_pcomp.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ -- To view, visit https://gerrit.osmocom.org/642 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 Gerrit-PatchSet: 21 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Sat Aug 20 00:29:04 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sat, 20 Aug 2016 00:29:04 +0000 Subject: osmo-iuh[master]: doc: add example osmo-hnbgw.cfg In-Reply-To: References: Message-ID: Patch Set 2: after the addition of 721 as predecessor of this patch, the example config file will now survive 'make dist' -- To view, visit https://gerrit.osmocom.org/712 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I424ccdea02578edc7816e4d23a9ea7c5729315d8 Gerrit-PatchSet: 2 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 20 00:31:07 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sat, 20 Aug 2016 00:31:07 +0000 Subject: [PATCH] osmo-iuh[master]: doc: add example osmo-hnbgw.cfg In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/712 to look at the new patch set (#3). doc: add example osmo-hnbgw.cfg Note that all *.cfg files are added to 'make dist' by the doc/examples/Makefile.am. Change-Id: I424ccdea02578edc7816e4d23a9ea7c5729315d8 --- A doc/examples/osmo-hnbgw.cfg 1 file changed, 32 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/12/712/3 diff --git a/doc/examples/osmo-hnbgw.cfg b/doc/examples/osmo-hnbgw.cfg new file mode 100644 index 0000000..1cc98c2 --- /dev/null +++ b/doc/examples/osmo-hnbgw.cfg @@ -0,0 +1,32 @@ +! +! OsmoHNBGW (0) configuration saved from vty +!! +! +log stderr + logging filter all 1 + logging color 1 + logging print category 0 + logging timestamp 0 + logging level all everything + logging level main debug + logging level hnbap debug + logging level sua debug + logging level rua debug + logging level ranap debug + logging level lglobal notice + logging level llapd notice + logging level linp notice + logging level lmux notice + logging level lmi notice + logging level lmib notice + logging level lsms notice + logging level lctrl notice + logging level lgtp notice + logging level lstats notice +! +line vty + no login +! +hnbgw + iuh + bind 192.168.0.132 -- To view, visit https://gerrit.osmocom.org/712 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I424ccdea02578edc7816e4d23a9ea7c5729315d8 Gerrit-PatchSet: 3 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Sat Aug 20 01:23:51 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sat, 20 Aug 2016 01:23:51 +0000 Subject: openbsc[master]: lchan: Release channel in case of late activation ack In-Reply-To: References: Message-ID: Patch Set 2: (1 comment) https://gerrit.osmocom.org/#/c/713/2/openbsc/src/libbsc/abis_rsl.c File openbsc/src/libbsc/abis_rsl.c: Line 1134: dyn_ts_switchover_complete(lchan); so this first "accepts" the act ack, but then tells the BTS to release the channel right away. For dyn TS it might be safer to set dyn.pchan_is = dyn.pchan_want = GSM_PCHAN_NONE, because of the logic in rsl_rx_rf_chan_rel_ack(): switching on PDCH will only happen if pchan_is != GSM_PCHAN_PDCH and if pchan_is == pchan_want. If the broken state happened while trying to switch to PDCH, lchan->type might be set to none, the call to dyn_ts_switchover_complete() will thus set pchan_is = PDCH and rsl_rx_rf_chan_rel_ack() will skip the PDCH activation. But after the broken state we might need that to happen? To clarify: "release" normally means "release voice", and for dyn TS that is synonymous to "activate data", so we always want to activate PDCH after this. Complication: dyn TS also introduce a non-std chan act and rf_chan_release message for PDCH, so we could also receive an act ack here that was meant for the PDCH activation request. I'm only trying to figure this out theoretically. Do you have a scenario to test this and make sure? Can a broken channel happen anytime, or only in specific cases? -- To view, visit https://gerrit.osmocom.org/713 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I63dc0deaf15ba7c21e20b1e0c7b85f0437e183ed Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Sat Aug 20 01:41:39 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sat, 20 Aug 2016 01:41:39 +0000 Subject: osmo-pcu[master]: Describe the issue with EGPRS PUAN encoding In-Reply-To: References: Message-ID: Patch Set 1: > Below patch series is arranged with reference to below mail > > http://lists.osmocom.org/pipermail/osmocom-net-gprs/2016-July/000680.html Indeed, I was going to quote the exact same mail, but must find that I remembered it wrongly. I thought it said "commit the correct unit test with the fix", but actually it does say to comment an assert and fix it later. So let me take back the part of my commentary on line 753. (I would prefer a real expected-to-fail infrastructure, but we don't have that.) The other comments are still valid. Most important to me would be an improved commit log message that has a link to an osmocom.org issue and/or a mail thread and is easier to understand. It should also say something in the line of: "add unit test that expects a current bug, to be changed in a subsequent commit containing the bugfix." -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 20 02:10:21 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sat, 20 Aug 2016 02:10:21 +0000 Subject: osmo-pcu[master]: Fix the issue with PUAN encoding for EGPRS In-Reply-To: References: Message-ID: Patch Set 1: (1 comment) I notice that https://gerrit.osmocom.org/412 includes the same fix, but has more changes in it as well. So this here, 703, does a better job at fixing the urbb_len issue separately first. https://gerrit.osmocom.org/#/c/703/1//COMMIT_MSG Commit Message: Line 7: Fix the issue with PUAN encoding for EGPRS Please add "Related: OS#1793" An improved first line could be: "Fix EGPRS PUAN encoding: use correct urbb_len" Mention that the unit test assertion is fixed in the commit log. -- To view, visit https://gerrit.osmocom.org/703 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Iba7b1995028bd81749ffb080616b2ad5f2540d57 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Sat Aug 20 02:13:53 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sat, 20 Aug 2016 02:13:53 +0000 Subject: osmo-pcu[master]: Fix issues in URBB generation in EGPRS PUAN In-Reply-To: References: Message-ID: Patch Set 2: Code-Review-1 https://gerrit.osmocom.org/703 has a fix for the urbb_len issue alone, which is nice. This patch should build on 703, and do not fix things as well as restructure in the same patch. I believe this has been commented on before and assume you are aware of it, just mentioning it for the record. -- To view, visit https://gerrit.osmocom.org/412 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ie5c25b6ee30f2f1b613e923c234b03a6ffe12ae2 Gerrit-PatchSet: 2 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: prasadkg Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: prasadkg Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 20 02:29:23 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sat, 20 Aug 2016 02:29:23 +0000 Subject: osmo-pcu[master]: Update the function immediate assignment for EGPRS In-Reply-To: References: Message-ID: Patch Set 4: (3 comments) https://gerrit.osmocom.org/#/c/431/4/src/encoding.cpp File src/encoding.cpp: Line 22: #include is it really necessary to move this #include? https://gerrit.osmocom.org/#/c/431/4/src/encoding.h File src/encoding.h: Line 43: bitvec * dest, uint8_t downlink, uint16_t ra, It is not obvious why this is changed to uint16_t, maybe describe in the commit log? https://gerrit.osmocom.org/#/c/431/4/tests/edge/EdgeTest.cpp File tests/edge/EdgeTest.cpp: Line 43: #include "encoding.h" is it really necessary to move this #include? If it is, it should be mentioned in the commit log msg. -- To view, visit https://gerrit.osmocom.org/431 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ie5e309156e5dbbb6add74a1b4d257c4ee2332e52 Gerrit-PatchSet: 4 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: bhargava_abhyankar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Sat Aug 20 02:50:20 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sat, 20 Aug 2016 02:50:20 +0000 Subject: osmo-pcu[master]: Change interface in osmo-pcu for 11 bit RACH In-Reply-To: References: Message-ID: Patch Set 4: Code-Review+1 (2 comments) I've reminded Holger of his -2... looks good to me except cosmetics. https://gerrit.osmocom.org/#/c/429/4/src/pcuif_proto.h File src/pcuif_proto.h: Line 76: uint8_t is_11bit; (whitespace: the other lines use tab, but the is_11bit line uses spaces between type and member name) https://gerrit.osmocom.org/#/c/429/4/tests/tbf/TbfTest.cpp File tests/tbf/TbfTest.cpp: Line 1094: /* simulate RACH, sends an Immediate Assignment Uplink on the AGCH */ (unnecessary change in the comment?) -- To view, visit https://gerrit.osmocom.org/429 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I265c2d92d36d6cbcbeee60cdd8407dafe1da06a4 Gerrit-PatchSet: 4 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: bhargava_abhyankar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Sat Aug 20 02:58:11 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sat, 20 Aug 2016 02:58:11 +0000 Subject: osmo-bts[master]: Update parameters in osmo-bts-sysmo for 11bit RACH In-Reply-To: References: Message-ID: Patch Set 6: (1 comment) https://gerrit.osmocom.org/#/c/434/6/src/osmo-bts-sysmo/l1_if.c File src/osmo-bts-sysmo/l1_if.c: Line 986: l1sap->u.rach_ind.is_11bit = is_11bit; /* no of bits in 11 bit RACH */ the name "is_11bit" indicates a boolean value, but the comment says "number of bits"? -- To view, visit https://gerrit.osmocom.org/434 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I93831ddfb3f31b637e6a576f23a9bb4557758582 Gerrit-PatchSet: 6 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: bhargava_abhyankar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Sat Aug 20 03:08:35 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sat, 20 Aug 2016 03:08:35 +0000 Subject: osmo-bts[master]: Change interface in osmo-bts for 11 bit RACH In-Reply-To: References: Message-ID: Patch Set 5: (2 comments) https://gerrit.osmocom.org/#/c/433/5/src/common/l1sap.c File src/common/l1sap.c: Line 969: (trx == bts->c0 && rach_ind->is_11bit)) { strictly speaking, this change is more than just changing the interface between bts and pcu. You should mention this in the commit log (e.g. "Add 11bit rach to the ts_is_pdch() check in l1sap.c") or move this to the other 11bit commit. https://gerrit.osmocom.org/#/c/433/5/src/osmo-bts-sysmo/l1_if.c File src/osmo-bts-sysmo/l1_if.c: Line 978: this is the only change in this patch that is for a specific BTS model. Does that mean the other BTS models are missing this initialization? Can this BTS-specific part be moved to the osmo-bts-sysmo specific commit? -- To view, visit https://gerrit.osmocom.org/433 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I4f4c501b2d86d77c78de32a84b1804172ffb6f4d Gerrit-PatchSet: 5 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: bhargava_abhyankar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Sat Aug 20 06:36:27 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 20 Aug 2016 06:36:27 +0000 Subject: osmo-bts[master]: Change interface in osmo-bts for 11 bit RACH In-Reply-To: References: Message-ID: Patch Set 5: Code-Review+2 (1 comment) https://gerrit.osmocom.org/#/c/433/5/src/osmo-bts-sysmo/l1_if.c File src/osmo-bts-sysmo/l1_if.c: Line 978: > this is the only change in this patch that is for a ths is has already been discussed in earlier review comments. of this gerrit patch, I think it is fine. -- To view, visit https://gerrit.osmocom.org/433 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I4f4c501b2d86d77c78de32a84b1804172ffb6f4d Gerrit-PatchSet: 5 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: bhargava_abhyankar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Sat Aug 20 06:38:37 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 20 Aug 2016 06:38:37 +0000 Subject: osmo-bts[master]: Update parameters in osmo-bts-sysmo for 11bit RACH In-Reply-To: References: Message-ID: Patch Set 6: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/434 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I93831ddfb3f31b637e6a576f23a9bb4557758582 Gerrit-PatchSet: 6 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: bhargava_abhyankar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 20 06:44:19 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 20 Aug 2016 06:44:19 +0000 Subject: [PATCH] osmo-pcu[master]: Change interface in osmo-pcu for 11 bit RACH In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/429 to look at the new patch set (#5). Change interface in osmo-pcu for 11 bit RACH Interface structure between osmo-bts and osmo-pcu is updated with the parameters to differentiate the type of RACH and further support 11 bit RACH. The function prototype and definitions are changed accordingly. Interface version number is increased. Change-Id: I265c2d92d36d6cbcbeee60cdd8407dafe1da06a4 --- M src/bts.cpp M src/bts.h M src/pcu_l1_if.cpp M src/pcuif_proto.h M tests/tbf/TbfTest.cpp 5 files changed, 18 insertions(+), 9 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/29/429/5 diff --git a/src/bts.cpp b/src/bts.cpp index c53c92c..e65d608 100644 --- a/src/bts.cpp +++ b/src/bts.cpp @@ -467,7 +467,8 @@ return 0; } -int BTS::rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta) +int BTS::rcv_rach(uint16_t ra, uint32_t Fn, int16_t qta, uint8_t is_11bit, + enum ph_burst_type burst_type) { struct gprs_rlcmac_ul_tbf *tbf = NULL; uint8_t trx_no, ts_no = 0; diff --git a/src/bts.h b/src/bts.h index 807ce08..d68e5d8 100644 --- a/src/bts.h +++ b/src/bts.h @@ -28,6 +28,7 @@ #include #include #include +#include } #include "poll_controller.h" @@ -285,7 +286,8 @@ int tfi_find_free(enum gprs_rlcmac_tbf_direction dir, uint8_t *_trx, int8_t use_trx); int rcv_imm_ass_cnf(const uint8_t *data, uint32_t fn); - int rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta); + int rcv_rach(uint16_t ra, uint32_t Fn, int16_t qta, uint8_t is_11bit, + enum ph_burst_type burst_type); void trigger_dl_ass(gprs_rlcmac_dl_tbf *tbf, gprs_rlcmac_tbf *old_tbf); void snd_dl_ass(gprs_rlcmac_tbf *tbf, uint8_t poll, const char *imsi); diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp index 1434213..f1c73c9 100644 --- a/src/pcu_l1_if.cpp +++ b/src/pcu_l1_if.cpp @@ -322,7 +322,8 @@ case PCU_IF_SAPI_RACH: rc = BTS::main_bts()->rcv_rach( rach_ind->ra, rach_ind->fn, - rach_ind->qta); + rach_ind->qta, rach_ind->is_11bit, + (ph_burst_type)rach_ind->burst_type); break; default: LOGP(DL1IF, LOGL_ERROR, "Received PCU rach request with " diff --git a/src/pcuif_proto.h b/src/pcuif_proto.h index d320380..944f364 100644 --- a/src/pcuif_proto.h +++ b/src/pcuif_proto.h @@ -1,7 +1,9 @@ #ifndef _PCUIF_PROTO_H #define _PCUIF_PROTO_H -#define PCU_IF_VERSION 0x06 +#include + +#define PCU_IF_VERSION 0x07 /* msg_type */ #define PCU_IF_MSG_DATA_REQ 0x00 /* send data to given channel */ @@ -67,10 +69,12 @@ struct gsm_pcu_if_rach_ind { uint8_t sapi; - uint8_t ra; + uint16_t ra; int16_t qta; uint32_t fn; uint16_t arfcn; + uint8_t is_11bit; + uint8_t burst_type; } __attribute__ ((packed)); struct gsm_pcu_if_info_trx { diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..2569f8c 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -36,6 +36,7 @@ #include #include #include +#include } #include @@ -553,7 +554,7 @@ tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1); - the_bts->rcv_rach(0x03, *fn, qta); + the_bts->rcv_rach(0x03, *fn, qta, 0, GSM_L1_BURST_TYPE_ACCESS_0); ul_tbf = the_bts->ul_tbf_by_tfi(tfi, trx_no, ts_no); OSMO_ASSERT(ul_tbf != NULL); @@ -645,7 +646,7 @@ * simulate RACH, this sends an Immediate * Assignment Uplink on the AGCH */ - the_bts->rcv_rach(0x73, rach_fn, qta); + the_bts->rcv_rach(0x73, rach_fn, qta, 0, GSM_L1_BURST_TYPE_ACCESS_0); /* get next free TFI */ tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1); @@ -1090,8 +1091,8 @@ /* needed to set last_rts_fn in the PDCH object */ request_dl_rlc_block(bts, trx_no, ts_no, fn); - /* simulate RACH, this sends an Immediate Assignment Uplink on the AGCH */ - the_bts->rcv_rach(0x73, rach_fn, qta); + /* simulate RACH, sends an Immediate Assignment Uplink on the AGCH */ + the_bts->rcv_rach(0x73, rach_fn, qta, 0, GSM_L1_BURST_TYPE_ACCESS_0); /* get next free TFI */ tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1); -- To view, visit https://gerrit.osmocom.org/429 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I265c2d92d36d6cbcbeee60cdd8407dafe1da06a4 Gerrit-PatchSet: 5 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: bhargava_abhyankar From gerrit-no-reply at lists.osmocom.org Sat Aug 20 06:44:28 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 20 Aug 2016 06:44:28 +0000 Subject: osmo-pcu[master]: Change interface in osmo-pcu for 11 bit RACH In-Reply-To: References: Message-ID: Patch Set 5: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/429 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I265c2d92d36d6cbcbeee60cdd8407dafe1da06a4 Gerrit-PatchSet: 5 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: bhargava_abhyankar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 20 06:46:39 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 20 Aug 2016 06:46:39 +0000 Subject: osmo-pcu[master]: Update the function immediate assignment for EGPRS In-Reply-To: References: Message-ID: Patch Set 4: Code-Review+1 (1 comment) would be great to remove the (probably?) unneccessary moving of #include file order. https://gerrit.osmocom.org/#/c/431/4/src/encoding.h File src/encoding.h: Line 43: bitvec * dest, uint8_t downlink, uint16_t ra, > It is not obvious why this is changed to uint16_t, maybe describe in the co the patch is about 11bit rach. I think it is rather obvious that this won't fit into uint8_t. -- To view, visit https://gerrit.osmocom.org/431 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ie5e309156e5dbbb6add74a1b4d257c4ee2332e52 Gerrit-PatchSet: 4 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: bhargava_abhyankar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Sat Aug 20 06:48:10 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 20 Aug 2016 06:48:10 +0000 Subject: osmo-iuh[master]: doc: add example osmo-hnbgw.cfg In-Reply-To: References: Message-ID: Patch Set 3: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/712 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I424ccdea02578edc7816e4d23a9ea7c5729315d8 Gerrit-PatchSet: 3 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 20 06:55:12 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 20 Aug 2016 06:55:12 +0000 Subject: openbsc[master]: V42BIS integration and unit test In-Reply-To: References: Message-ID: Patch Set 27: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/644 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d Gerrit-PatchSet: 27 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 20 06:55:36 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 20 Aug 2016 06:55:36 +0000 Subject: openbsc[master]: Adding compression control and final fixups In-Reply-To: References: Message-ID: Patch Set 21: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/642 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 Gerrit-PatchSet: 21 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 20 06:59:05 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 20 Aug 2016 06:59:05 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 15: (1 comment) https://gerrit.osmocom.org/#/c/655/15/src/pcu_vty.c File src/pcu_vty.c: Line 490: EGPRS_STR "DL ARQ options\n" > Hi Neels, I think the problem is that you use EGPRS_STR (intended for all commands starting with "egprs" for a command starting with "dl". The question thus is: * what is the help the vty shows for a command startign with 'dl' (type ? on empty prompt)? * is the entire command EGPRS specific? If yes, it should be "egprs dl ...". If not, EGPRS_STR is probably the wrong help for the first word in the command. -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 15 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Sat Aug 20 07:02:06 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 20 Aug 2016 07:02:06 +0000 Subject: osmo-iuh[master]: add doc/examples, Makefile.am adds all *.cfg files generically In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/721 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I1fadad4deb7f73d2b3aa753a84a76ba5b9bf9574 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 20 07:02:19 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 20 Aug 2016 07:02:19 +0000 Subject: osmo-iuh[master]: add to dist: doc subdir with all current doc files In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/720 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Idfef4f050e21a5d0eae3a530fe319a5adf81534d Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 20 07:02:52 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 20 Aug 2016 07:02:52 +0000 Subject: [MERGED] osmo-iuh[master]: doc: add example osmo-hnbgw.cfg In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: doc: add example osmo-hnbgw.cfg ...................................................................... doc: add example osmo-hnbgw.cfg Note that all *.cfg files are added to 'make dist' by the doc/examples/Makefile.am. Change-Id: I424ccdea02578edc7816e4d23a9ea7c5729315d8 --- A doc/examples/osmo-hnbgw.cfg 1 file changed, 32 insertions(+), 0 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/doc/examples/osmo-hnbgw.cfg b/doc/examples/osmo-hnbgw.cfg new file mode 100644 index 0000000..1cc98c2 --- /dev/null +++ b/doc/examples/osmo-hnbgw.cfg @@ -0,0 +1,32 @@ +! +! OsmoHNBGW (0) configuration saved from vty +!! +! +log stderr + logging filter all 1 + logging color 1 + logging print category 0 + logging timestamp 0 + logging level all everything + logging level main debug + logging level hnbap debug + logging level sua debug + logging level rua debug + logging level ranap debug + logging level lglobal notice + logging level llapd notice + logging level linp notice + logging level lmux notice + logging level lmi notice + logging level lmib notice + logging level lsms notice + logging level lctrl notice + logging level lgtp notice + logging level lstats notice +! +line vty + no login +! +hnbgw + iuh + bind 192.168.0.132 -- To view, visit https://gerrit.osmocom.org/712 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I424ccdea02578edc7816e4d23a9ea7c5729315d8 Gerrit-PatchSet: 3 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Sat Aug 20 14:26:05 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sat, 20 Aug 2016 14:26:05 +0000 Subject: [ABANDON] osmo-iuh[master]: add doc/examples, Makefile.am adds all *.cfg files generically In-Reply-To: References: Message-ID: Neels Hofmeyr has abandoned this change. Change subject: add doc/examples, Makefile.am adds all *.cfg files generically ...................................................................... Abandoned This change has been merged but gerrit fails to notice. -- To view, visit https://gerrit.osmocom.org/721 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: abandon Gerrit-Change-Id: I1fadad4deb7f73d2b3aa753a84a76ba5b9bf9574 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Sat Aug 20 14:26:15 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sat, 20 Aug 2016 14:26:15 +0000 Subject: [ABANDON] osmo-iuh[master]: add to dist: doc subdir with all current doc files In-Reply-To: References: Message-ID: Neels Hofmeyr has abandoned this change. Change subject: add to dist: doc subdir with all current doc files ...................................................................... Abandoned This change has been merged but gerrit fails to notice. -- To view, visit https://gerrit.osmocom.org/720 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: abandon Gerrit-Change-Id: Idfef4f050e21a5d0eae3a530fe319a5adf81534d Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Sat Aug 20 14:26:21 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sat, 20 Aug 2016 14:26:21 +0000 Subject: [ABANDON] osmo-iuh[master]: hnbgw: make Iuh bind address configurable via VTY In-Reply-To: References: Message-ID: Neels Hofmeyr has abandoned this change. Change subject: hnbgw: make Iuh bind address configurable via VTY ...................................................................... Abandoned This change has been merged but gerrit fails to notice. -- To view, visit https://gerrit.osmocom.org/711 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: abandon Gerrit-Change-Id: Ie2749c152b878e17aa65dfb806826357d5c494f1 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Sat Aug 20 14:26:26 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sat, 20 Aug 2016 14:26:26 +0000 Subject: [ABANDON] osmo-iuh[master]: hnbgw vty: add empty hnbgw and hnbgw/iuh vty nodes In-Reply-To: References: Message-ID: Neels Hofmeyr has abandoned this change. Change subject: hnbgw vty: add empty hnbgw and hnbgw/iuh vty nodes ...................................................................... Abandoned This change has been merged but gerrit fails to notice. -- To view, visit https://gerrit.osmocom.org/710 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: abandon Gerrit-Change-Id: I71545823d3bd81cb888c85df8e298a56c98bf131 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Sat Aug 20 14:26:32 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sat, 20 Aug 2016 14:26:32 +0000 Subject: [ABANDON] osmo-iuh[master]: hnbgw: move vty commands out to new hnbgw_vty.c In-Reply-To: References: Message-ID: Neels Hofmeyr has abandoned this change. Change subject: hnbgw: move vty commands out to new hnbgw_vty.c ...................................................................... Abandoned This change has been merged but gerrit fails to notice. -- To view, visit https://gerrit.osmocom.org/709 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: abandon Gerrit-Change-Id: If85c1b97a240bd1dcf9f367ea6fca857d542ab22 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Sat Aug 20 14:26:36 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sat, 20 Aug 2016 14:26:36 +0000 Subject: [ABANDON] osmo-iuh[master]: hnbgw: make cmdline options stronger than config file In-Reply-To: References: Message-ID: Neels Hofmeyr has abandoned this change. Change subject: hnbgw: make cmdline options stronger than config file ...................................................................... Abandoned This change has been merged but gerrit fails to notice. -- To view, visit https://gerrit.osmocom.org/708 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: abandon Gerrit-Change-Id: I16ad55b173a443c36b71dc6b70f58695f6665312 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Sat Aug 20 14:26:41 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sat, 20 Aug 2016 14:26:41 +0000 Subject: [ABANDON] osmo-iuh[master]: hnbgw: add config file and -c cmdline option In-Reply-To: References: Message-ID: Neels Hofmeyr has abandoned this change. Change subject: hnbgw: add config file and -c cmdline option ...................................................................... Abandoned This change has been merged but gerrit fails to notice. -- To view, visit https://gerrit.osmocom.org/707 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: abandon Gerrit-Change-Id: I6ac9fa17b35260031c55aab664124d466f60c937 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Sat Aug 20 14:26:46 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sat, 20 Aug 2016 14:26:46 +0000 Subject: [ABANDON] osmo-iuh[master]: hnbgw: add cmdline arg parsing with default options In-Reply-To: References: Message-ID: Neels Hofmeyr has abandoned this change. Change subject: hnbgw: add cmdline arg parsing with default options ...................................................................... Abandoned This change has been merged but gerrit fails to notice. -- To view, visit https://gerrit.osmocom.org/706 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: abandon Gerrit-Change-Id: I931cee01c605c1b507c16041ada226cf963ea433 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Sat Aug 20 14:26:51 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sat, 20 Aug 2016 14:26:51 +0000 Subject: [ABANDON] osmo-iuh[master]: hnbgw: add copyright to vty_info In-Reply-To: References: Message-ID: Neels Hofmeyr has abandoned this change. Change subject: hnbgw: add copyright to vty_info ...................................................................... Abandoned This change has been merged but gerrit fails to notice. -- To view, visit https://gerrit.osmocom.org/705 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: abandon Gerrit-Change-Id: I702b606837199ab64c3590546900d4d30357b919 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Sat Aug 20 14:30:43 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sat, 20 Aug 2016 14:30:43 +0000 Subject: [PATCH] openbsc[master]: comment: gsm48_gmm_sendmsg(): add spec reference on encryptable In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/689 to look at the new patch set (#2). comment: gsm48_gmm_sendmsg(): add spec reference on encryptable Change-Id: I54a3bc518bc38e38b78f6e9ea3705e4fbd5ffb98 --- M openbsc/src/gprs/gprs_gmm.c 1 file changed, 3 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/89/689/2 diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index aa49919..036164f 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -130,7 +130,9 @@ return sgsn->cfg.timers.T3314 + (sgsn->cfg.timers.T3312 + 4 * 60); } -/* Send a message through the underlying layer */ +/* Send a message through the underlying layer. + * For param encryptable, see 3GPP TS 24.008 ? 4.7.1.2 and + * gsm48_hdr_gmm_cipherable(). Pass false for not cipherable messages. */ static int gsm48_gmm_sendmsg(struct msgb *msg, int command, struct sgsn_mm_ctx *mm, bool encryptable) { -- To view, visit https://gerrit.osmocom.org/689 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I54a3bc518bc38e38b78f6e9ea3705e4fbd5ffb98 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Sat Aug 20 14:34:10 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sat, 20 Aug 2016 14:34:10 +0000 Subject: [PATCH] libosmocore[master]: vty: use VTY_BIND_ADDR_DEFAULT instead of "127.0.0.1" Message-ID: Review at https://gerrit.osmocom.org/722 vty: use VTY_BIND_ADDR_DEFAULT instead of "127.0.0.1" Change-Id: Ice0688ac9847524cb546f6d41547090b6a3cb3d8 --- M src/vty/vty.c 1 file changed, 1 insertion(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/22/722/1 diff --git a/src/vty/vty.c b/src/vty/vty.c index 8c0c73a..88ed937 100644 --- a/src/vty/vty.c +++ b/src/vty/vty.c @@ -1678,7 +1678,7 @@ vty_out(vty, " no login%s", VTY_NEWLINE); /* bind */ - if (vty_bind_addr && (strcmp(vty_bind_addr, "127.0.0.1") != 0)) + if (vty_bind_addr && (strcmp(vty_bind_addr, VTY_BIND_ADDR_DEFAULT) != 0)) vty_out(vty, " bind %s%s", vty_bind_addr, VTY_NEWLINE); vty_out(vty, "!%s", VTY_NEWLINE); -- To view, visit https://gerrit.osmocom.org/722 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ice0688ac9847524cb546f6d41547090b6a3cb3d8 Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Sat Aug 20 15:09:40 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sat, 20 Aug 2016 15:09:40 +0000 Subject: [PATCH] osmo-iuh[master]: UE Register with TMSI: reply with a Register Reject Message-ID: Review at https://gerrit.osmocom.org/723 UE Register with TMSI: reply with a Register Reject When receiving a UE Register Request with TMSI and no IMSI, compose a Register Reject with the same UE Identity and send. The accepting function expects a ue_context argument and composes the message from the IMSI found there. This new rejection message cannot rely on a ue_context struct and hence uses the asn1 uE_Identity directly. Change-Id: Ia47e398e50e316842cd260dc0d9a4e2d8a1c627c --- M src/hnbgw_hnbap.c 1 file changed, 65 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/23/723/1 diff --git a/src/hnbgw_hnbap.c b/src/hnbgw_hnbap.c index 8a0bc9b..5246b81 100644 --- a/src/hnbgw_hnbap.c +++ b/src/hnbgw_hnbap.c @@ -114,6 +114,69 @@ return hnbgw_hnbap_tx(ue->hnb, msg); } +static int hnbgw_tx_ue_register_rej_tmsi(struct hnb_context *hnb, UE_Identity_t *ue_id) +{ + UERegisterReject_t reject_out; + UERegisterRejectIEs_t reject; + struct msgb *msg; + int rc; + + memset(&reject, 0, sizeof(reject)); + reject.uE_Identity.present = ue_id->present; + + if (ue_id->present != UE_Identity_PR_tMSILAI) { + LOGP(DHNBAP, LOGL_ERROR, "Trying to reject UE Register without IMSI: only rejects of UE_Identity_PR_tMSILAI supported so far.\n"); + return -1; + } + + LOGP(DHNBAP, LOGL_DEBUG, "REJ UE_Id tMSI %d %s\n", + ue_id->choice.tMSILAI.tMSI.size, + osmo_hexdump(ue_id->choice.tMSILAI.tMSI.buf, + ue_id->choice.tMSILAI.tMSI.size)); + + LOGP(DHNBAP, LOGL_DEBUG, "REJ UE_Id pLMNID %d %s\n", + ue_id->choice.tMSILAI.lAI.pLMNID.size, + osmo_hexdump(ue_id->choice.tMSILAI.lAI.pLMNID.buf, + ue_id->choice.tMSILAI.lAI.pLMNID.size)); + + LOGP(DHNBAP, LOGL_DEBUG, "REJ UE_Id lAC %d %s\n", + ue_id->choice.tMSILAI.lAI.lAC.size, + osmo_hexdump(ue_id->choice.tMSILAI.lAI.lAC.buf, + ue_id->choice.tMSILAI.lAI.lAC.size)); + + BIT_STRING_fromBuf(&reject.uE_Identity.choice.tMSILAI.tMSI, + ue_id->choice.tMSILAI.tMSI.buf, + ue_id->choice.tMSILAI.tMSI.size * 8 + - ue_id->choice.tMSILAI.tMSI.bits_unused); + OCTET_STRING_fromBuf(&reject.uE_Identity.choice.tMSILAI.lAI.pLMNID, + ue_id->choice.tMSILAI.lAI.pLMNID.buf, + ue_id->choice.tMSILAI.lAI.pLMNID.size); + OCTET_STRING_fromBuf(&reject.uE_Identity.choice.tMSILAI.lAI.lAC, + ue_id->choice.tMSILAI.lAI.lAC.buf, + ue_id->choice.tMSILAI.lAI.lAC.size); + + reject.cause.present = Cause_PR_radioNetwork; + reject.cause.choice.radioNetwork = CauseRadioNetwork_invalid_UE_identity; + + memset(&reject_out, 0, sizeof(reject_out)); + rc = hnbap_encode_ueregisterrejecties(&reject_out, &reject); + if (rc < 0) { + return rc; + } + + msg = hnbap_generate_unsuccessful_outcome(ProcedureCode_id_UERegister, + Criticality_reject, + &asn_DEF_UERegisterReject, + &reject_out); + + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_BIT_STRING, &reject.uE_Identity.choice.tMSILAI.tMSI); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_OCTET_STRING, &reject.uE_Identity.choice.tMSILAI.lAI.pLMNID); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_OCTET_STRING, &reject.uE_Identity.choice.tMSILAI.lAI.lAC); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_UERegisterReject, &reject_out); + + return hnbgw_hnbap_tx(hnb, msg); +} + static int hnbgw_rx_hnb_deregister(struct hnb_context *ctx, ANY_t *in) { HNBDe_RegisterIEs_t ies; @@ -187,8 +250,9 @@ LOGP(DHNBAP, LOGL_NOTICE, "UE-REGISTER-REQ without IMSI\n"); /* TODO: this is probably a TMSI registration. Store TMSIs * and look them up to accept UE Registration. */ + rc = hnbgw_tx_ue_register_rej_tmsi(ctx, &ies.uE_Identity); hnbap_free_ueregisterrequesties(&ies); - return -1; + return rc; } DEBUGP(DHNBAP, "UE-REGISTER-REQ ID_type=%d imsi=%s cause=%ld\n", -- To view, visit https://gerrit.osmocom.org/723 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ia47e398e50e316842cd260dc0d9a4e2d8a1c627c Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Sun Aug 21 07:07:27 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Sun, 21 Aug 2016 07:07:27 +0000 Subject: osmo-pcu[master]: Revert "tbf: Add state WAIT_ASSIGN" In-Reply-To: References: Message-ID: Patch Set 3: I will not have time for another three to four weeks, so maybe we apply it and move forward? -- To view, visit https://gerrit.osmocom.org/218 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I1532f8e93194368cdc1e3846f82afa6d68cd5fbd Gerrit-PatchSet: 3 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sun Aug 21 07:08:47 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Sun, 21 Aug 2016 07:08:47 +0000 Subject: openbsc[master]: ussd: Add band-aid for interrogationSS In-Reply-To: References: Message-ID: Patch Set 3: -Code-Review -- To view, visit https://gerrit.osmocom.org/503 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ib0dc4485388f030eb172fe21f5327b7ab94751f5 Gerrit-PatchSet: 3 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sun Aug 21 07:13:16 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Sun, 21 Aug 2016 07:13:16 +0000 Subject: openbsc[master]: move ts_sublots() to gsm_data_shared.c, it will be used by o... In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 Looks okay -- To view, visit https://gerrit.osmocom.org/669 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I8ba06d7dd6e0ceab3d8d18bb565354d6ed461f7e Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sun Aug 21 07:14:13 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Sun, 21 Aug 2016 07:14:13 +0000 Subject: openbsc[master]: chan_alloc.c: use ts_subslots() instead of subslots_per_pchan[] In-Reply-To: References: Message-ID: Patch Set 1: How frequently do we call this? -- To view, visit https://gerrit.osmocom.org/668 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Icbea7dbd78abf6144e5291f531a97f96507d8cbf Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sun Aug 21 07:16:00 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Sun, 21 Aug 2016 07:16:00 +0000 Subject: osmo-pcu[master]: Add data structure to handle SPB for EGPRS DL In-Reply-To: References: Message-ID: Patch Set 6: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/654 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I57673e53a9da2affa7e8aaa6551ac4b271c3d525 Gerrit-PatchSet: 6 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sun Aug 21 07:20:49 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Sun, 21 Aug 2016 07:20:49 +0000 Subject: osmo-pcu[master]: Remove warning while using 'egprs only' command in VTY In-Reply-To: References: Message-ID: Patch Set 1: Code-Review-2 The warning is about the fact that if EGPRS is enabled then only EGPRS capable phones will be able to attach (e.g. there are no checks for the MS class, capabilities, etc). From what I remember there is also no code to support GPRS/EDGE on the same timeslots, etc. Can you please clarify? -- To view, visit https://gerrit.osmocom.org/704 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I62278f998adc691b9a3563ac2a46d756e7bfb66c Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sun Aug 21 07:21:53 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Sun, 21 Aug 2016 07:21:53 +0000 Subject: osmo-pcu[master]: Fix the issue with PUAN encoding for EGPRS In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/703 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Iba7b1995028bd81749ffb080616b2ad5f2540d57 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sun Aug 21 07:22:07 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Sun, 21 Aug 2016 07:22:07 +0000 Subject: osmo-pcu[master]: Fix the issue with PUAN encoding for EGPRS In-Reply-To: References: Message-ID: Patch Set 1: Waiting for addressing neels feedback on the previous patch. -- To view, visit https://gerrit.osmocom.org/703 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Iba7b1995028bd81749ffb080616b2ad5f2540d57 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sun Aug 21 07:31:56 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Sun, 21 Aug 2016 07:31:56 +0000 Subject: osmo-pcu[master]: Change interface in osmo-pcu for 11 bit RACH In-Reply-To: References: Message-ID: Patch Set 5: -Code-Review -- To view, visit https://gerrit.osmocom.org/429 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I265c2d92d36d6cbcbeee60cdd8407dafe1da06a4 Gerrit-PatchSet: 5 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: bhargava_abhyankar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sun Aug 21 07:47:54 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sun, 21 Aug 2016 07:47:54 +0000 Subject: osmo-pcu[master]: Revert "tbf: Add state WAIT_ASSIGN" In-Reply-To: References: Message-ID: Patch Set 3: Code-Review+1 > I will not have time for another three to four weeks, so maybe we > apply it and move forward? fine with me. -- To view, visit https://gerrit.osmocom.org/218 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I1532f8e93194368cdc1e3846f82afa6d68cd5fbd Gerrit-PatchSet: 3 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sun Aug 21 07:56:01 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Sun, 21 Aug 2016 07:56:01 +0000 Subject: osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Patch Set 18: (10 comments) https://gerrit.osmocom.org/#/c/416/18/src/egprs_rlc_compression.cpp File src/egprs_rlc_compression.cpp: Line 17: Node *egprs_compress::create_tree_node() ::create_tree_node(void *parent) PS18, Line 21: talloc_zero talloc_zert(parent, Node) Line 51: iter->left = create_tree_node(); create_tree_node(root) Line 55: iter->right = create_tree_node(); create_tree_node(root) Line 329: tall_tree_ctx = talloc_named_const(tall_pcu_ctx, 0, you can remove.. we will see two trees anyway Line 333: ones_list = talloc(tall_tree_ctx, Node); ones_list = create_tree_node(tall_pcu_ctx); Line 334: zeros_list = talloc(tall_tree_ctx, Node); zeroes_list = create_tree_node(tall_pcu_ctx) https://gerrit.osmocom.org/#/c/416/18/src/egprs_rlc_compression.h File src/egprs_rlc_compression.h: Line 3: */ missing pragma once. Line 27: extern void *tall_pcu_ctx; not needed. https://gerrit.osmocom.org/#/c/416/18/tests/Makefile.am File tests/Makefile.am: Line 38: -Wl,-u,bssgp_prim_cb Still.. the tree code doesn't depend on GB, GSM, etc.. drop that.. drop the linking hack with allowing bssgp_prim_cb to be undefined. -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 18 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: pravin Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Sun Aug 21 07:57:11 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Sun, 21 Aug 2016 07:57:11 +0000 Subject: osmo-pcu[master]: Describe the issue with EGPRS PUAN encoding In-Reply-To: References: Message-ID: Patch Set 1: General approach is indeed fine (and requested) by me. As this part of the code has not been tested yet it makes sense to add a test case and then have the fix to see how the messages change. Please address the other feedback by Neels -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sun Aug 21 08:05:48 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Sun, 21 Aug 2016 08:05:48 +0000 Subject: [PATCH] osmo-pcu[master]: llc: fix NULL-pointer check gprs_llc_queue::size() gprs_llc_... In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/213 to look at the new patch set (#2). llc: fix NULL-pointer check gprs_llc_queue::size() gprs_llc_queue::octets() gcc6 is optimizing if (!this) {CODE} as this is assumed to never be a std::nullptr here. Move the null check to the caller. Change-Id: I918a094e0dc59098a9eb00d152c9ae42d36b3a99 --- M src/llc.h 1 file changed, 2 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/13/213/2 diff --git a/src/llc.h b/src/llc.h index 94de16e..4883624 100644 --- a/src/llc.h +++ b/src/llc.h @@ -127,10 +127,10 @@ inline size_t gprs_llc_queue::size() const { - return this ? m_queue_size : 0; + return m_queue_size; } inline size_t gprs_llc_queue::octets() const { - return this ? m_queue_octets : 0; + return m_queue_octets; } -- To view, visit https://gerrit.osmocom.org/213 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I918a094e0dc59098a9eb00d152c9ae42d36b3a99 Gerrit-PatchSet: 2 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: lynxis lazus From gerrit-no-reply at lists.osmocom.org Sun Aug 21 08:06:19 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Sun, 21 Aug 2016 08:06:19 +0000 Subject: osmo-pcu[master]: llc: fix NULL-pointer check gprs_llc_queue::size() gprs_llc_... In-Reply-To: References: Message-ID: Patch Set 2: The only thing that is missing is to actually move the null check to the caller. Did you see where that might be? -- To view, visit https://gerrit.osmocom.org/213 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I918a094e0dc59098a9eb00d152c9ae42d36b3a99 Gerrit-PatchSet: 2 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: lynxis lazus Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sun Aug 21 08:07:59 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Sun, 21 Aug 2016 08:07:59 +0000 Subject: osmo-pcu[master]: Handle Timing Advance IE properly In-Reply-To: References: Message-ID: Patch Set 6: Code-Review-1 (1 comment) https://gerrit.osmocom.org/#/c/552/6/src/encoding.cpp File src/encoding.cpp: Line 39: static inline bool write_tai(bitvec *dest, unsigned& wp, int8_t tai) Let me repeat the question. Why should wp be a mutable reference here? -- To view, visit https://gerrit.osmocom.org/552 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I786bf7fc999d401cc3d9e7f1e7a1fba953b5d458 Gerrit-PatchSet: 6 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Sun Aug 21 13:25:08 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sun, 21 Aug 2016 13:25:08 +0000 Subject: openbsc[master]: chan_alloc.c: use ts_subslots() instead of subslots_per_pchan[] In-Reply-To: References: Message-ID: Patch Set 1: In terms of this patch, i.e. in chan_alloc.c, this will be called only once per lchan being allocated. So if a voice call is established, there is one call to ts_sublsots() (per MS). -- To view, visit https://gerrit.osmocom.org/668 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Icbea7dbd78abf6144e5291f531a97f96507d8cbf Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sun Aug 21 13:31:07 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sun, 21 Aug 2016 13:31:07 +0000 Subject: openbsc[master]: dyn TS: bts_chan_load: use correct nr of subslots for dyn ts In-Reply-To: References: Message-ID: Patch Set 1: Call frequency: bts_chan_load() and hence ts_subslots() will be called: * once per paging and lchan * for VTY show commands * for CTRL commands to fetch the channel load -- To view, visit https://gerrit.osmocom.org/667 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I659acebca82dfb3e305433471be64e9d27439af8 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sun Aug 21 13:34:17 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sun, 21 Aug 2016 13:34:17 +0000 Subject: openbsc[master]: move ts_sublots() to gsm_data_shared.c, it will be used by o... In-Reply-To: References: Message-ID: Patch Set 1: damn, why did I submit this as a branch tip? :) Rather waiting for the other two patches for fear of causing more gerrit confusion... -- To view, visit https://gerrit.osmocom.org/669 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I8ba06d7dd6e0ceab3d8d18bb565354d6ed461f7e Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sun Aug 21 13:38:36 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sun, 21 Aug 2016 13:38:36 +0000 Subject: openbsc[master]: add libiu In-Reply-To: References: Message-ID: Patch Set 5: This had a +2 before ... the only change to the previous patch set is that I don't add the DIU logging category in the preceding commit and use DRANAP here. -- To view, visit https://gerrit.osmocom.org/192 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Iffc26f9c73cb15463948f7435b72ac1747aabdb3 Gerrit-PatchSet: 5 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sun Aug 21 13:50:47 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sun, 21 Aug 2016 13:50:47 +0000 Subject: openbsc[master]: Adding SLHC (RFC1144 header compression) code from linux kernel In-Reply-To: References: Message-ID: Patch Set 9: > Build Failed The SLHC logging constant is added in the patch *after* this and hence missing in this patch. -- To view, visit https://gerrit.osmocom.org/634 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ied69c143678dc4a64cecc671f5c4dfebe19d8519 Gerrit-PatchSet: 9 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sun Aug 21 14:02:15 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sun, 21 Aug 2016 14:02:15 +0000 Subject: [PATCH] osmo-bts[master]: sysmo: ts_connect: log channel combination name instead of n... In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/685 to look at the new patch set (#2). sysmo: ts_connect: log channel combination name instead of number Change-Id: Ife11cfdb0f83d56ed61e66286a79b7c3a000cce5 --- M src/osmo-bts-sysmo/femtobts.h M src/osmo-bts-sysmo/oml.c 2 files changed, 4 insertions(+), 3 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/85/685/2 diff --git a/src/osmo-bts-sysmo/femtobts.h b/src/osmo-bts-sysmo/femtobts.h index 8be198f..9163ebb 100644 --- a/src/osmo-bts-sysmo/femtobts.h +++ b/src/osmo-bts-sysmo/femtobts.h @@ -83,7 +83,7 @@ const struct value_string femtobts_tracef_docs[29]; const struct value_string femtobts_tch_pl_names[15]; - +const struct value_string femtobts_chcomb_names[8]; const struct value_string femtobts_clksrc_names[10]; const struct value_string femtobts_dir_names[6]; diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c index e9a4794..86e2bee 100644 --- a/src/osmo-bts-sysmo/oml.c +++ b/src/osmo-bts-sysmo/oml.c @@ -504,9 +504,10 @@ cr->u8Tn = ts->nr; cr->logChComb = pchan_to_logChComb[pchan]; - DEBUGP(DL1C, "%s pchan=%s ts_connect_as(%s) logChComb=%d\n", + DEBUGP(DL1C, "%s pchan=%s ts_connect_as(%s) logChComb=%s\n", gsm_lchan_name(ts->lchan), gsm_pchan_name(ts->pchan), - gsm_pchan_name(pchan), cr->logChComb); + gsm_pchan_name(pchan), get_value_string(femtobts_chcomb_names, + cr->logChComb)); return l1if_gsm_req_compl(fl1h, msg, cb, NULL); } -- To view, visit https://gerrit.osmocom.org/685 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ife11cfdb0f83d56ed61e66286a79b7c3a000cce5 Gerrit-PatchSet: 2 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Sun Aug 21 14:02:21 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sun, 21 Aug 2016 14:02:21 +0000 Subject: osmo-bts[master]: sysmo: ts_connect: log channel combination name instead of n... In-Reply-To: References: Message-ID: Patch Set 2: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/685 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ife11cfdb0f83d56ed61e66286a79b7c3a000cce5 Gerrit-PatchSet: 2 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sun Aug 21 14:02:30 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sun, 21 Aug 2016 14:02:30 +0000 Subject: [MERGED] osmo-bts[master]: sysmo: ts_connect: log channel combination name instead of n... In-Reply-To: References: Message-ID: Neels Hofmeyr has submitted this change and it was merged. Change subject: sysmo: ts_connect: log channel combination name instead of number ...................................................................... sysmo: ts_connect: log channel combination name instead of number Change-Id: Ife11cfdb0f83d56ed61e66286a79b7c3a000cce5 --- M src/osmo-bts-sysmo/femtobts.h M src/osmo-bts-sysmo/oml.c 2 files changed, 4 insertions(+), 3 deletions(-) Approvals: Neels Hofmeyr: Looks good to me, approved Jenkins Builder: Verified diff --git a/src/osmo-bts-sysmo/femtobts.h b/src/osmo-bts-sysmo/femtobts.h index 8be198f..9163ebb 100644 --- a/src/osmo-bts-sysmo/femtobts.h +++ b/src/osmo-bts-sysmo/femtobts.h @@ -83,7 +83,7 @@ const struct value_string femtobts_tracef_docs[29]; const struct value_string femtobts_tch_pl_names[15]; - +const struct value_string femtobts_chcomb_names[8]; const struct value_string femtobts_clksrc_names[10]; const struct value_string femtobts_dir_names[6]; diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c index e5d3e40..6f0629d 100644 --- a/src/osmo-bts-sysmo/oml.c +++ b/src/osmo-bts-sysmo/oml.c @@ -505,9 +505,10 @@ cr->u8Tn = ts->nr; cr->logChComb = pchan_to_logChComb[pchan]; - DEBUGP(DL1C, "%s pchan=%s ts_connect_as(%s) logChComb=%d\n", + DEBUGP(DL1C, "%s pchan=%s ts_connect_as(%s) logChComb=%s\n", gsm_lchan_name(ts->lchan), gsm_pchan_name(ts->pchan), - gsm_pchan_name(pchan), cr->logChComb); + gsm_pchan_name(pchan), get_value_string(femtobts_chcomb_names, + cr->logChComb)); return l1if_gsm_req_compl(fl1h, msg, cb, NULL); } -- To view, visit https://gerrit.osmocom.org/685 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ife11cfdb0f83d56ed61e66286a79b7c3a000cce5 Gerrit-PatchSet: 3 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Sun Aug 21 14:06:03 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sun, 21 Aug 2016 14:06:03 +0000 Subject: libosmo-abis[master]: Change API to convey marker bit In-Reply-To: References: Message-ID: Patch Set 1: (1 comment) https://gerrit.osmocom.org/#/c/688/1/include/osmocom/trau/osmo_ortp.h File include/osmocom/trau/osmo_ortp.h: Line 58: unsigned int payload_len, bool marker); maybe a less general name would be better, like "rtp_marker"?? -- To view, visit https://gerrit.osmocom.org/688 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I3c2b6365d8a51bf98805614e07344d2639875fde Gerrit-PatchSet: 1 Gerrit-Project: libosmo-abis Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Sun Aug 21 14:12:00 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sun, 21 Aug 2016 14:12:00 +0000 Subject: osmo-pcu[master]: Remove warning while using 'egprs only' command in VTY In-Reply-To: References: Message-ID: Patch Set 1: -Code-Review removing my vote cause I'm clearly out of my depth here -- To view, visit https://gerrit.osmocom.org/704 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I62278f998adc691b9a3563ac2a46d756e7bfb66c Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sun Aug 21 14:14:53 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sun, 21 Aug 2016 14:14:53 +0000 Subject: osmo-pcu[master]: Revert "tbf: Add state WAIT_ASSIGN" In-Reply-To: References: Message-ID: Patch Set 3: Code-Review-1 I'm not clear on whether reverting WAIT_ASSIGN would break two phase configuration... otherwise I would agree. -- To view, visit https://gerrit.osmocom.org/218 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I1532f8e93194368cdc1e3846f82afa6d68cd5fbd Gerrit-PatchSet: 3 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sun Aug 21 17:43:49 2016 From: gerrit-no-reply at lists.osmocom.org (lynxis lazus) Date: Sun, 21 Aug 2016 17:43:49 +0000 Subject: [PATCH] osmo-pcu[master]: tbf: add llc_queue_size() to check llc_queue is valid before... Message-ID: Review at https://gerrit.osmocom.org/724 tbf: add llc_queue_size() to check llc_queue is valid before calling size() gcc6 is optimizing if (!this) {CODE} as this is assumed to never be a std::nullptr here. Move the null check to the caller. In preparation of removing the check within llc_queue->size() all callers must check the object before calling it. Change-Id: I88cc3180f8f86785e3f07981895dabddf50b60a2 --- M src/tbf.cpp M src/tbf.h M src/tbf_dl.cpp 3 files changed, 11 insertions(+), 4 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/24/724/1 diff --git a/src/tbf.cpp b/src/tbf.cpp index 1fc1aef..75b110d 100644 --- a/src/tbf.cpp +++ b/src/tbf.cpp @@ -188,6 +188,12 @@ return m_ms ? m_ms->llc_queue() : NULL; } +int gprs_rlcmac_tbf::llc_queue_size() const +{ + /* m_ms llc_queue can never be NULL because it's instantiated by m_ms contructor */ + return m_ms ? m_ms->llc_queue()->size() : 0; +} + void gprs_rlcmac_tbf::set_ms(GprsMs *ms) { if (m_ms == ms) diff --git a/src/tbf.h b/src/tbf.h index 1bd7878..788a960 100644 --- a/src/tbf.h +++ b/src/tbf.h @@ -144,6 +144,7 @@ GprsCodingScheme current_cs() const; gprs_llc_queue *llc_queue(); const gprs_llc_queue *llc_queue() const; + int llc_queue_size() const; time_t created_ts() const; uint8_t dl_slots() const; diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp index 07a747a..a877a0d 100644 --- a/src/tbf_dl.cpp +++ b/src/tbf_dl.cpp @@ -310,7 +310,7 @@ LOGP(DRLCMACDL, LOGL_NOTICE, "%s Discarding LLC PDU " "because lifetime limit reached, " "count=%u new_queue_size=%zu\n", - tbf_name(this), frames, llc_queue()->size()); + tbf_name(this), frames, llc_queue_size()); if (frames > 0xff) frames = 0xff; if (octets > 0xffffff) @@ -560,7 +560,7 @@ m_llc.frame_length(), frames_since_last_drain(fn)); } - is_final = llc_queue()->size() == 0 && !keep_open(fn); + is_final = llc_queue_size() == 0 && !keep_open(fn); ar = Encoding::rlc_data_to_dl_append(rdbi, cs, &m_llc, &write_offset, &num_chunks, data, is_final, &payload_written); @@ -1012,7 +1012,7 @@ release(); /* check for LLC PDU in the LLC Queue */ - if (llc_queue()->size() > 0) + if (llc_queue() && llc_queue_size() > 0) /* we have more data so we will re-use this tbf */ establish_dl_tbf_on_pacch(); @@ -1130,7 +1130,7 @@ bool gprs_rlcmac_dl_tbf::have_data() const { return m_llc.chunk_size() > 0 || - (llc_queue() && llc_queue()->size() > 0); + (llc_queue_size() > 0); } int gprs_rlcmac_dl_tbf::frames_since_last_poll(unsigned fn) const -- To view, visit https://gerrit.osmocom.org/724 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I88cc3180f8f86785e3f07981895dabddf50b60a2 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: lynxis lazus From gerrit-no-reply at lists.osmocom.org Sun Aug 21 17:48:27 2016 From: gerrit-no-reply at lists.osmocom.org (lynxis lazus) Date: Sun, 21 Aug 2016 17:48:27 +0000 Subject: osmo-pcu[master]: llc: fix NULL-pointer check gprs_llc_queue::size() gprs_llc_... In-Reply-To: References: Message-ID: Patch Set 3: @Holger: it's now ready. -- To view, visit https://gerrit.osmocom.org/213 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I918a094e0dc59098a9eb00d152c9ae42d36b3a99 Gerrit-PatchSet: 3 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: lynxis lazus Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sun Aug 21 17:50:53 2016 From: gerrit-no-reply at lists.osmocom.org (lynxis lazus) Date: Sun, 21 Aug 2016 17:50:53 +0000 Subject: openbsc[master]: sms: change rp err cause of smpp_try_deliver errors In-Reply-To: References: Message-ID: Patch Set 1: (1 comment) https://gerrit.osmocom.org/#/c/551/1/openbsc/src/libmsc/gsm_04_11.c File openbsc/src/libmsc/gsm_04_11.c: Line 298: LOGP(DLSMS, LOGL_ERROR, "While trying to deliver a SMS the error code %d received. Sending rp err cause 41 to ms\n", rc); > u we should create a dump of all fields. do we want to log the everything including the body? -- To view, visit https://gerrit.osmocom.org/551 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia03e50ce2bd9a7d1054cc5a6000fd73bd3497c03 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: lynxis lazus Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Sun Aug 21 18:06:13 2016 From: gerrit-no-reply at lists.osmocom.org (lynxis lazus) Date: Sun, 21 Aug 2016 18:06:13 +0000 Subject: [PATCH] openbsc[master]: libbsc/libmsc: convert old osmo counter into rate_ctrgs In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/500 to look at the new patch set (#8). libbsc/libmsc: convert old osmo counter into rate_ctrgs rate counters support the export to statsd and can have a delta value. Change-Id: Ie749cebd53a0bb618d0e23d375885712078bf8dd --- M openbsc/include/openbsc/gsm_data.h M openbsc/src/libbsc/abis_rsl.c M openbsc/src/libbsc/bsc_init.c M openbsc/src/libbsc/bsc_vty.c M openbsc/src/libbsc/gsm_04_08_utils.c M openbsc/src/libbsc/handover_logic.c M openbsc/src/libbsc/net_init.c M openbsc/src/libbsc/paging.c M openbsc/src/libmsc/gsm_04_08.c M openbsc/src/libmsc/gsm_04_11.c M openbsc/src/libmsc/vty_interface_layer3.c 11 files changed, 152 insertions(+), 140 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/00/500/8 diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index b9cb48d..6168a6b 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -7,7 +7,10 @@ #include #include +#include #include +#include + #include #include @@ -148,55 +151,79 @@ /* Some statistics of our network */ -struct gsmnet_stats { - struct { - struct osmo_counter *total; - struct osmo_counter *no_channel; - } chreq; - struct { - struct osmo_counter *attempted; - struct osmo_counter *no_channel; /* no channel available */ - struct osmo_counter *timeout; /* T3103 timeout */ - struct osmo_counter *completed; /* HO COMPL received */ - struct osmo_counter *failed; /* HO FAIL received */ - } handover; - struct { - struct osmo_counter *attach; - struct osmo_counter *normal; - struct osmo_counter *periodic; - struct osmo_counter *detach; - } loc_upd_type; - struct { - struct osmo_counter *reject; - struct osmo_counter *accept; - } loc_upd_resp; - struct { - struct osmo_counter *attempted; - struct osmo_counter *detached; - struct osmo_counter *completed; - struct osmo_counter *expired; - } paging; - struct { - struct osmo_counter *submitted; /* MO SMS submissions */ - struct osmo_counter *no_receiver; - struct osmo_counter *delivered; /* MT SMS deliveries */ - struct osmo_counter *rp_err_mem; - struct osmo_counter *rp_err_other; - } sms; - struct { - struct osmo_counter *mo_setup; - struct osmo_counter *mo_connect_ack; - struct osmo_counter *mt_setup; - struct osmo_counter *mt_connect; - } call; - struct { - struct osmo_counter *rf_fail; - struct osmo_counter *rll_err; - } chan; - struct { - struct osmo_counter *oml_fail; - struct osmo_counter *rsl_fail; - } bts; +enum { + MSC_CTR_CHREQ_TOTAL, + MSC_CTR_CHREQ_NO_CHANNEL, + MSC_CTR_HANDOVER_ATTEMPTED, + MSC_CTR_HANDOVER_NO_CHANNEL, + MSC_CTR_HANDOVER_TIMEOUT, + MSC_CTR_HANDOVER_COMPLETED, + MSC_CTR_HANDOVER_FAILED, + MSC_CTR_LOC_UPDATE_TYPE_ATTACH, + MSC_CTR_LOC_UPDATE_TYPE_NORMAL, + MSC_CTR_LOC_UPDATE_TYPE_PERIODIC, + MSC_CTR_LOC_UPDATE_TYPE_DETACH, + MSC_CTR_LOC_UPDATE_RESP_REJECT, + MSC_CTR_LOC_UPDATE_RESP_ACCEPT, + MSC_CTR_PAGING_ATTEMPTED, + MSC_CTR_PAGING_DETACHED, + MSC_CTR_PAGING_COMPLETED, + MSC_CTR_PAGING_EXPIRED, + MSC_CTR_SMS_SUBMITTED, + MSC_CTR_SMS_NO_RECEIVER, + MSC_CTR_SMS_DELIVERED, + MSC_CTR_SMS_RP_ERR_MEM, + MSC_CTR_SMS_RP_ERR_OTHER, + MSC_CTR_CALL_MO_SETUP, + MSC_CTR_CALL_MO_CONNECT_ACK, + MSC_CTR_CALL_MT_SETUP, + MSC_CTR_CALL_MT_CONNECT, + MSC_CTR_CHAN_RF_FAIL, + MSC_CTR_CHAN_RLL_ERR, + MSC_CTR_BTS_OML_FAIL, + MSC_CTR_BTS_RSL_FAIL, +}; + +static const struct rate_ctr_desc msc_ctr_description[] = { + [MSC_CTR_CHREQ_TOTAL] = {"chreq.total", "Received channel requests."}, + [MSC_CTR_CHREQ_NO_CHANNEL] = {"chreq.no_channel", "Sent to MS no channel available."}, + [MSC_CTR_HANDOVER_ATTEMPTED] = {"handover.attempted", "Received handover attempts."}, + [MSC_CTR_HANDOVER_NO_CHANNEL] = {"handover.no_channel", "Sent no channel available responses."}, + [MSC_CTR_HANDOVER_TIMEOUT] = {"handover.timeout", "Count the amount of timeouts of timer T3103."}, + [MSC_CTR_HANDOVER_COMPLETED] = {"handover.completed", "Received handover completed."}, + [MSC_CTR_HANDOVER_FAILED] = {"handover.failed", "Receive HO FAIL messages."}, + [MSC_CTR_LOC_UPDATE_TYPE_ATTACH] = {"loc_update_type.attach", "Received location update imsi attach requests."}, + [MSC_CTR_LOC_UPDATE_TYPE_NORMAL] = {"loc_update_type.normal", "Received location update normal requests."}, + [MSC_CTR_LOC_UPDATE_TYPE_PERIODIC] = {"loc_update_type.periodic", "Received location update periodic requests."}, + [MSC_CTR_LOC_UPDATE_TYPE_DETACH] = {"loc_update_type.detach", "Received location update detach indication."}, + [MSC_CTR_LOC_UPDATE_RESP_REJECT] = {"loc_update_resp.reject", "Sent location update reject responses."}, + [MSC_CTR_LOC_UPDATE_RESP_ACCEPT] = {"loc_update_resp.accept", "Sent location update accept responses."}, + [MSC_CTR_PAGING_ATTEMPTED] = {"paging.attempted", "Paging attempts for a MS."}, + [MSC_CTR_PAGING_DETACHED] = {"paging.detached", "Counts the amount of paging attempts which couldn't sent out any paging request because no responsible bts found."}, + [MSC_CTR_PAGING_COMPLETED] = {"paging.completed", "Paging successful completed."}, + [MSC_CTR_PAGING_EXPIRED] = {"paging.expired", "Paging Request expired because of timeout T3113."}, + [MSC_CTR_SMS_SUBMITTED] = {"sms.submitted", "Received a RPDU from a MS (MO)."}, + [MSC_CTR_SMS_NO_RECEIVER] = {"sms.no_receiver", "Counts SMS which couldn't routed because no receiver found."}, + [MSC_CTR_SMS_DELIVERED] = {"sms.delivered", "Global SMS Deliver attempts."}, + [MSC_CTR_SMS_RP_ERR_MEM] = {"sms.rp_err_mem", "CAUSE_MT_MEM_EXCEEDED errors of MS responses on a sms deliver attempt."}, + [MSC_CTR_SMS_RP_ERR_OTHER] = {"sms.rp_err_other", "Other error of MS responses on a sms delive attempt."}, + /* FIXME: count also sms delivered */ + [MSC_CTR_CALL_MO_SETUP] = {"call.mo_setup", "Received setup requests from a MS to init a MO call."}, + [MSC_CTR_CALL_MO_CONNECT_ACK] = {"call.mo_connect_ack", "Received a connect ack from MS of a MO call. Call is now succesful connected up."}, + [MSC_CTR_CALL_MT_SETUP] = {"call.mt_setup", "Sent setup requests to the MS (MT)."}, + [MSC_CTR_CALL_MT_CONNECT] = {"call.mt_connect", "Sent a connect to the MS (MT)."}, + [MSC_CTR_CHAN_RF_FAIL] = {"chan.rf_fail", "Received a RF failure indication from BTS."}, + [MSC_CTR_CHAN_RLL_ERR] = {"chan.rll_err", "Received a RLL failure with T200 cause from BTS."}, + [MSC_CTR_BTS_OML_FAIL] = {"bts.oml_fail", "Received a TEI down on a OML link."}, + [MSC_CTR_BTS_RSL_FAIL] = {"bts.rsl_fail", "Received a TEI down on a OML link."}, +}; + +static const struct rate_ctr_group_desc msc_ctrg_desc = { + "msc", + "mobile switching center", + OSMO_STATS_CLASS_GLOBAL, + ARRAY_SIZE(msc_ctr_description), + msc_ctr_description, }; enum gsm_auth_policy { @@ -241,7 +268,8 @@ unsigned int max_distance; /* TA values */ } handover; - struct gsmnet_stats stats; + struct rate_ctr_group *ratectrs; + /* layer 4 */ struct mncc_sock_state *mncc_state; diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index b84a0b5..092ec4e 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -1207,7 +1207,7 @@ TLVP_LEN(&tp, RSL_IE_CAUSE)); LOGPC(DRSL, LOGL_NOTICE, "\n"); - osmo_counter_inc(msg->lchan->ts->trx->bts->network->stats.chan.rf_fail); + rate_ctr_inc(&msg->lchan->ts->trx->bts->network->ratectrs->ctr[MSC_CTR_CHAN_RF_FAIL]); return rsl_rf_chan_release_err(msg->lchan); } @@ -1641,7 +1641,7 @@ lctype = get_ctype_by_chreq(bts->network, rqd_ref->ra); chreq_reason = get_reason_by_chreq(rqd_ref->ra, bts->network->neci); - osmo_counter_inc(bts->network->stats.chreq.total); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_CHREQ_TOTAL]); /* * We want LOCATION UPDATES to succeed and will assign a TCH @@ -1654,7 +1654,7 @@ if (!lchan) { LOGP(DRSL, LOGL_NOTICE, "BTS %d CHAN RQD: no resources for %s 0x%x\n", msg->lchan->ts->trx->bts->nr, gsm_lchant_name(lctype), rqd_ref->ra); - osmo_counter_inc(bts->network->stats.chreq.no_channel); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_CHREQ_NO_CHANNEL]); /* FIXME gather multiple CHAN RQD and reject up to 4 at the same time */ if (bts->network->T3122) rsl_send_imm_ass_rej(bts, 1, rqd_ref, bts->network->T3122 & 0xff); @@ -1837,7 +1837,7 @@ rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_ERR_IND); if (rlm_cause == RLL_CAUSE_T200_EXPIRED) { - osmo_counter_inc(msg->lchan->ts->trx->bts->network->stats.chan.rll_err); + rate_ctr_inc(&msg->lchan->ts->trx->bts->network->ratectrs->ctr[MSC_CTR_CHAN_RLL_ERR]); return rsl_rf_chan_release_err(msg->lchan); } diff --git a/openbsc/src/libbsc/bsc_init.c b/openbsc/src/libbsc/bsc_init.c index 5c27862..5ea85d0 100644 --- a/openbsc/src/libbsc/bsc_init.c +++ b/openbsc/src/libbsc/bsc_init.c @@ -340,9 +340,9 @@ LOGP(DLMI, LOGL_ERROR, "Lost some E1 TEI link: %d %p\n", isd->link_type, trx); if (isd->link_type == E1INP_SIGN_OML) - osmo_counter_inc(trx->bts->network->stats.bts.oml_fail); + rate_ctr_inc(&trx->bts->network->ratectrs->ctr[MSC_CTR_BTS_OML_FAIL]); else if (isd->link_type == E1INP_SIGN_RSL) - osmo_counter_inc(trx->bts->network->stats.bts.rsl_fail); + rate_ctr_inc(&trx->bts->network->ratectrs->ctr[MSC_CTR_BTS_RSL_FAIL]); /* * free all allocated channels. change the nm_state so the diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c index 6584cf0..fbaf06b 100644 --- a/openbsc/src/libbsc/bsc_vty.c +++ b/openbsc/src/libbsc/bsc_vty.c @@ -3784,18 +3784,22 @@ void openbsc_vty_print_statistics(struct vty *vty, struct gsm_network *net) { vty_out(vty, "Channel Requests : %lu total, %lu no channel%s", - osmo_counter_get(net->stats.chreq.total), - osmo_counter_get(net->stats.chreq.no_channel), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_CHREQ_TOTAL].current, + net->ratectrs->ctr[MSC_CTR_CHREQ_NO_CHANNEL].current, + VTY_NEWLINE); vty_out(vty, "Channel Failures : %lu rf_failures, %lu rll failures%s", - osmo_counter_get(net->stats.chan.rf_fail), - osmo_counter_get(net->stats.chan.rll_err), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_CHAN_RF_FAIL].current, + net->ratectrs->ctr[MSC_CTR_CHAN_RLL_ERR].current, + VTY_NEWLINE); vty_out(vty, "Paging : %lu attempted, %lu complete, %lu expired%s", - osmo_counter_get(net->stats.paging.attempted), - osmo_counter_get(net->stats.paging.completed), - osmo_counter_get(net->stats.paging.expired), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_PAGING_ATTEMPTED].current, + net->ratectrs->ctr[MSC_CTR_PAGING_COMPLETED].current, + net->ratectrs->ctr[MSC_CTR_PAGING_EXPIRED].current, + VTY_NEWLINE); vty_out(vty, "BTS failures : %lu OML, %lu RSL%s", - osmo_counter_get(net->stats.bts.oml_fail), - osmo_counter_get(net->stats.bts.rsl_fail), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_BTS_OML_FAIL].current, + net->ratectrs->ctr[MSC_CTR_BTS_RSL_FAIL].current, + VTY_NEWLINE); } DEFUN(drop_bts, diff --git a/openbsc/src/libbsc/gsm_04_08_utils.c b/openbsc/src/libbsc/gsm_04_08_utils.c index 635665a..d4eca4a 100644 --- a/openbsc/src/libbsc/gsm_04_08_utils.c +++ b/openbsc/src/libbsc/gsm_04_08_utils.c @@ -304,7 +304,7 @@ subscr = conn->subscr; } - osmo_counter_inc(bts->network->stats.paging.completed); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_PAGING_COMPLETED]); /* Stop paging on the bts we received the paging response */ paging_request_stop(conn->bts, subscr, conn, msg); diff --git a/openbsc/src/libbsc/handover_logic.c b/openbsc/src/libbsc/handover_logic.c index 52fa4af..5424e27 100644 --- a/openbsc/src/libbsc/handover_logic.c +++ b/openbsc/src/libbsc/handover_logic.c @@ -103,7 +103,7 @@ DEBUGP(DHO, "(old_lchan on BTS %u, new BTS %u)\n", old_lchan->ts->trx->bts->nr, bts->nr); - osmo_counter_inc(bts->network->stats.handover.attempted); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_HANDOVER_ATTEMPTED]); if (!old_lchan->conn) { LOGP(DHO, LOGL_ERROR, "Old lchan lacks connection data.\n"); @@ -113,7 +113,7 @@ new_lchan = lchan_alloc(bts, old_lchan->type, 0); if (!new_lchan) { LOGP(DHO, LOGL_NOTICE, "No free channel\n"); - osmo_counter_inc(bts->network->stats.handover.no_channel); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_HANDOVER_NO_CHANNEL]); return -ENOSPC; } @@ -188,7 +188,7 @@ struct gsm_network *net = ho->new_lchan->ts->trx->bts->network; DEBUGP(DHO, "HO T3103 expired\n"); - osmo_counter_inc(net->stats.handover.timeout); + rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_HANDOVER_TIMEOUT]); ho->new_lchan->conn->ho_lchan = NULL; ho->new_lchan->conn = NULL; @@ -265,7 +265,7 @@ ho->old_lchan->ts->trx->bts->nr, new_lchan->ts->trx->bts->nr, ho->old_lchan->ts->trx->arfcn, new_lchan->ts->trx->arfcn); - osmo_counter_inc(net->stats.handover.completed); + rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_HANDOVER_COMPLETED]); osmo_timer_del(&ho->T3103); @@ -303,7 +303,7 @@ return -ENODEV; } - osmo_counter_inc(net->stats.handover.failed); + rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_HANDOVER_FAILED]); new_lchan = ho->new_lchan; diff --git a/openbsc/src/libbsc/net_init.c b/openbsc/src/libbsc/net_init.c index 6d03ee4..b99f3d2 100644 --- a/openbsc/src/libbsc/net_init.c +++ b/openbsc/src/libbsc/net_init.c @@ -80,36 +80,8 @@ INIT_LLIST_HEAD(&net->upqueue); INIT_LLIST_HEAD(&net->bts_list); - net->stats.chreq.total = osmo_counter_alloc("net.chreq.total"); - net->stats.chreq.no_channel = osmo_counter_alloc("net.chreq.no_channel"); - net->stats.handover.attempted = osmo_counter_alloc("net.handover.attempted"); - net->stats.handover.no_channel = osmo_counter_alloc("net.handover.no_channel"); - net->stats.handover.timeout = osmo_counter_alloc("net.handover.timeout"); - net->stats.handover.completed = osmo_counter_alloc("net.handover.completed"); - net->stats.handover.failed = osmo_counter_alloc("net.handover.failed"); - net->stats.loc_upd_type.attach = osmo_counter_alloc("net.loc_upd_type.attach"); - net->stats.loc_upd_type.normal = osmo_counter_alloc("net.loc_upd_type.normal"); - net->stats.loc_upd_type.periodic = osmo_counter_alloc("net.loc_upd_type.periodic"); - net->stats.loc_upd_type.detach = osmo_counter_alloc("net.imsi_detach.count"); - net->stats.loc_upd_resp.reject = osmo_counter_alloc("net.loc_upd_resp.reject"); - net->stats.loc_upd_resp.accept = osmo_counter_alloc("net.loc_upd_resp.accept"); - net->stats.paging.attempted = osmo_counter_alloc("net.paging.attempted"); - net->stats.paging.detached = osmo_counter_alloc("net.paging.detached"); - net->stats.paging.completed = osmo_counter_alloc("net.paging.completed"); - net->stats.paging.expired = osmo_counter_alloc("net.paging.expired"); - net->stats.sms.submitted = osmo_counter_alloc("net.sms.submitted"); - net->stats.sms.no_receiver = osmo_counter_alloc("net.sms.no_receiver"); - net->stats.sms.delivered = osmo_counter_alloc("net.sms.delivered"); - net->stats.sms.rp_err_mem = osmo_counter_alloc("net.sms.rp_err_mem"); - net->stats.sms.rp_err_other = osmo_counter_alloc("net.sms.rp_err_other"); - net->stats.call.mo_setup = osmo_counter_alloc("net.call.mo_setup"); - net->stats.call.mo_connect_ack = osmo_counter_alloc("net.call.mo_connect_ack"); - net->stats.call.mt_setup = osmo_counter_alloc("net.call.mt_setup"); - net->stats.call.mt_connect = osmo_counter_alloc("net.call.mt_connect"); - net->stats.chan.rf_fail = osmo_counter_alloc("net.chan.rf_fail"); - net->stats.chan.rll_err = osmo_counter_alloc("net.chan.rll_err"); - net->stats.bts.oml_fail = osmo_counter_alloc("net.bts.oml_fail"); - net->stats.bts.rsl_fail = osmo_counter_alloc("net.bts.rsl_fail"); + /* init statistics */ + net->ratectrs = rate_ctr_group_alloc(net, &msc_ctrg_desc, 0); net->mncc_recv = mncc_recv; net->ext_min = GSM_MIN_EXTEN; diff --git a/openbsc/src/libbsc/paging.c b/openbsc/src/libbsc/paging.c index 9ae28e0..03c91fd 100644 --- a/openbsc/src/libbsc/paging.c +++ b/openbsc/src/libbsc/paging.c @@ -260,7 +260,7 @@ req, req->subscr->imsi); /* must be destroyed before calling cbfn, to prevent double free */ - osmo_counter_inc(req->bts->network->stats.paging.expired); + rate_ctr_inc(&req->bts->network->ratectrs->ctr[MSC_CTR_PAGING_EXPIRED]); cbfn_param = req->cbfn_param; cbfn = req->cbfn; @@ -330,7 +330,7 @@ struct gsm_bts *bts = NULL; int num_pages = 0; - osmo_counter_inc(network->stats.paging.attempted); + rate_ctr_inc(&network->ratectrs->ctr[MSC_CTR_PAGING_ATTEMPTED]); /* start paging subscriber on all BTS within Location Area */ do { @@ -349,7 +349,7 @@ } while (1); if (num_pages == 0) - osmo_counter_inc(network->stats.paging.detached); + rate_ctr_inc(&network->ratectrs->ctr[MSC_CTR_PAGING_DETACHED]); return num_pages; } diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c index 1b02efe..c4ecf1c 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/src/libmsc/gsm_04_08.c @@ -457,7 +457,7 @@ struct gsm_bts *bts = conn->bts; struct msgb *msg; - osmo_counter_inc(bts->network->stats.loc_upd_resp.reject); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_REJECT]); msg = gsm48_create_loc_upd_rej(cause); if (!msg) { @@ -506,7 +506,7 @@ DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n"); - osmo_counter_inc(bts->network->stats.loc_upd_resp.accept); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_ACCEPT]); return gsm48_conn_sendmsg(msg, conn, NULL); } @@ -637,13 +637,13 @@ switch (lu->type) { case GSM48_LUPD_NORMAL: - osmo_counter_inc(bts->network->stats.loc_upd_type.normal); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_NORMAL]); break; case GSM48_LUPD_IMSI_ATT: - osmo_counter_inc(bts->network->stats.loc_upd_type.attach); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_ATTACH]); break; case GSM48_LUPD_PERIODIC: - osmo_counter_inc(bts->network->stats.loc_upd_type.periodic); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_PERIODIC]); break; } @@ -1063,7 +1063,7 @@ DEBUGP(DMM, "IMSI DETACH INDICATION: MI(%s)=%s", gsm48_mi_type_name(mi_type), mi_string); - osmo_counter_inc(bts->network->stats.loc_upd_type.detach); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_DETACH]); switch (mi_type) { case GSM_MI_TYPE_TMSI: @@ -2002,7 +2002,7 @@ subscr_name(trans->subscr), trans->subscr->extension, setup.called.number); - osmo_counter_inc(trans->net->stats.call.mo_setup); + rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MO_SETUP]); /* indicate setup to MNCC */ mncc_recvmsg(trans->net, trans, MNCC_SETUP_IND, &setup); @@ -2080,7 +2080,7 @@ new_cc_state(trans, GSM_CSTATE_CALL_PRESENT); - osmo_counter_inc(trans->net->stats.call.mt_setup); + rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MT_SETUP]); return gsm48_conn_sendmsg(msg, trans->conn, trans); } @@ -2306,7 +2306,7 @@ } new_cc_state(trans, GSM_CSTATE_CONNECT_REQUEST); - osmo_counter_inc(trans->net->stats.call.mt_connect); + rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MT_CONNECT]); return mncc_recvmsg(trans->net, trans, MNCC_SETUP_CNF, &connect); } @@ -2319,7 +2319,7 @@ gsm48_stop_cc_timer(trans); new_cc_state(trans, GSM_CSTATE_ACTIVE); - osmo_counter_inc(trans->net->stats.call.mo_connect_ack); + rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MO_CONNECT_ACK]); memset(&connect_ack, 0, sizeof(struct gsm_mncc)); connect_ack.callref = trans->callref; diff --git a/openbsc/src/libmsc/gsm_04_11.c b/openbsc/src/libmsc/gsm_04_11.c index 20d18a9..fba5208 100644 --- a/openbsc/src/libmsc/gsm_04_11.c +++ b/openbsc/src/libmsc/gsm_04_11.c @@ -315,14 +315,14 @@ rc = smpp_try_deliver(gsms, conn); if (rc == 1) { rc = 1; /* cause 1: unknown subscriber */ - osmo_counter_inc(conn->bts->network->stats.sms.no_receiver); + rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); } else if (rc < 0) { rc = 21; /* cause 21: short message transfer rejected */ /* FIXME: handle the error somehow? */ } #else rc = 1; /* cause 1: unknown subscriber */ - osmo_counter_inc(conn->bts->network->stats.sms.no_receiver); + rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); #endif return rc; } @@ -363,7 +363,7 @@ uint8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */ int rc = 0; - osmo_counter_inc(conn->bts->network->stats.sms.submitted); + rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_SUBMITTED]); gsms = sms_alloc(); if (!gsms) @@ -633,10 +633,10 @@ * to store this in our database and wait for a SMMA message */ /* FIXME */ send_signal(S_SMS_MEM_EXCEEDED, trans, sms, 0); - osmo_counter_inc(net->stats.sms.rp_err_mem); + rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_MEM]); } else { send_signal(S_SMS_UNKNOWN_ERROR, trans, sms, 0); - osmo_counter_inc(net->stats.sms.rp_err_other); + rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_OTHER]); } sms_free(sms); @@ -932,7 +932,7 @@ DEBUGP(DLSMS, "TX: SMS DELIVER\n"); - osmo_counter_inc(conn->bts->network->stats.sms.delivered); + rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_DELIVERED]); db_sms_inc_deliver_attempts(trans->sms.sms); return gsm411_rp_sendmsg(&trans->sms.smr_inst, msg, diff --git a/openbsc/src/libmsc/vty_interface_layer3.c b/openbsc/src/libmsc/vty_interface_layer3.c index 74da1d7..d1041b3 100644 --- a/openbsc/src/libmsc/vty_interface_layer3.c +++ b/openbsc/src/libmsc/vty_interface_layer3.c @@ -795,34 +795,42 @@ openbsc_vty_print_statistics(vty, net); vty_out(vty, "Location Update : %lu attach, %lu normal, %lu periodic%s", - osmo_counter_get(net->stats.loc_upd_type.attach), - osmo_counter_get(net->stats.loc_upd_type.normal), - osmo_counter_get(net->stats.loc_upd_type.periodic), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_ATTACH].current, + net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_NORMAL].current, + net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_PERIODIC].current, + VTY_NEWLINE); vty_out(vty, "IMSI Detach Indications : %lu%s", - osmo_counter_get(net->stats.loc_upd_type.detach), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_DETACH].current, + VTY_NEWLINE); vty_out(vty, "Location Update Response: %lu accept, %lu reject%s", - osmo_counter_get(net->stats.loc_upd_resp.accept), - osmo_counter_get(net->stats.loc_upd_resp.reject), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_ACCEPT].current, + net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_REJECT].current, + VTY_NEWLINE); vty_out(vty, "Handover : %lu attempted, %lu no_channel, %lu timeout, " "%lu completed, %lu failed%s", - osmo_counter_get(net->stats.handover.attempted), - osmo_counter_get(net->stats.handover.no_channel), - osmo_counter_get(net->stats.handover.timeout), - osmo_counter_get(net->stats.handover.completed), - osmo_counter_get(net->stats.handover.failed), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_HANDOVER_ATTEMPTED].current, + net->ratectrs->ctr[MSC_CTR_HANDOVER_NO_CHANNEL].current, + net->ratectrs->ctr[MSC_CTR_HANDOVER_TIMEOUT].current, + net->ratectrs->ctr[MSC_CTR_HANDOVER_COMPLETED].current, + net->ratectrs->ctr[MSC_CTR_HANDOVER_FAILED].current, + VTY_NEWLINE); vty_out(vty, "SMS MO : %lu submitted, %lu no receiver%s", - osmo_counter_get(net->stats.sms.submitted), - osmo_counter_get(net->stats.sms.no_receiver), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_SMS_SUBMITTED].current, + net->ratectrs->ctr[MSC_CTR_SMS_NO_RECEIVER].current, + VTY_NEWLINE); vty_out(vty, "SMS MT : %lu delivered, %lu no memory, %lu other error%s", - osmo_counter_get(net->stats.sms.delivered), - osmo_counter_get(net->stats.sms.rp_err_mem), - osmo_counter_get(net->stats.sms.rp_err_other), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_SMS_DELIVERED].current, + net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_MEM].current, + net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_OTHER].current, + VTY_NEWLINE); vty_out(vty, "MO Calls : %lu setup, %lu connect ack%s", - osmo_counter_get(net->stats.call.mo_setup), - osmo_counter_get(net->stats.call.mo_connect_ack), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_CALL_MO_SETUP].current, + net->ratectrs->ctr[MSC_CTR_CALL_MO_CONNECT_ACK].current, + VTY_NEWLINE); vty_out(vty, "MT Calls : %lu setup, %lu connect%s", - osmo_counter_get(net->stats.call.mt_setup), - osmo_counter_get(net->stats.call.mt_connect), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_CALL_MT_SETUP].current, + net->ratectrs->ctr[MSC_CTR_CALL_MT_CONNECT].current, + VTY_NEWLINE); return CMD_SUCCESS; } -- To view, visit https://gerrit.osmocom.org/500 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ie749cebd53a0bb618d0e23d375885712078bf8dd Gerrit-PatchSet: 8 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: lynxis lazus From gerrit-no-reply at lists.osmocom.org Sun Aug 21 18:19:50 2016 From: gerrit-no-reply at lists.osmocom.org (lynxis lazus) Date: Sun, 21 Aug 2016 18:19:50 +0000 Subject: [PATCH] openbsc[master]: sms: change rp err cause of smpp_try_deliver errors In-Reply-To: References: Message-ID: Hello Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/551 to look at the new patch set (#2). sms: change rp err cause of smpp_try_deliver errors smpp_try_deliver could fail with rc < 0. In such cases don't sent the MS the rp error sms rejected (cause 21). A rejected message should not sent again. The spec 04 11 recommends sending cause 41 Temporary failure in unknown cases. Add also a log message and rate counter for such cases. Change-Id: Ia03e50ce2bd9a7d1054cc5a6000fd73bd3497c03 --- M openbsc/include/openbsc/gsm_data.h M openbsc/src/libmsc/gsm_04_11.c 2 files changed, 9 insertions(+), 4 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/51/551/2 diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 6168a6b..9221913 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -174,6 +174,7 @@ MSC_CTR_SMS_DELIVERED, MSC_CTR_SMS_RP_ERR_MEM, MSC_CTR_SMS_RP_ERR_OTHER, + MSC_CTR_SMS_DELIVER_UNKNOWN_ERROR, MSC_CTR_CALL_MO_SETUP, MSC_CTR_CALL_MO_CONNECT_ACK, MSC_CTR_CALL_MT_SETUP, @@ -207,6 +208,7 @@ [MSC_CTR_SMS_DELIVERED] = {"sms.delivered", "Global SMS Deliver attempts."}, [MSC_CTR_SMS_RP_ERR_MEM] = {"sms.rp_err_mem", "CAUSE_MT_MEM_EXCEEDED errors of MS responses on a sms deliver attempt."}, [MSC_CTR_SMS_RP_ERR_OTHER] = {"sms.rp_err_other", "Other error of MS responses on a sms delive attempt."}, + [MSC_CTR_SMS_DELIVER_UNKNOWN_ERROR] = {"sms.deliver_unknown_error", "While trying to deliver an unknown error attempted."}, /* FIXME: count also sms delivered */ [MSC_CTR_CALL_MO_SETUP] = {"call.mo_setup", "Received setup requests from a MS to init a MO call."}, [MSC_CTR_CALL_MO_CONNECT_ACK] = {"call.mo_connect_ack", "Received a connect ack from MS of a MO call. Call is now succesful connected up."}, diff --git a/openbsc/src/libmsc/gsm_04_11.c b/openbsc/src/libmsc/gsm_04_11.c index 840d4d4..619ff42 100644 --- a/openbsc/src/libmsc/gsm_04_11.c +++ b/openbsc/src/libmsc/gsm_04_11.c @@ -40,6 +40,7 @@ #include #include +#include #include #include @@ -294,8 +295,9 @@ if (rc == 1) goto try_local; if (rc < 0) { - rc = 21; /* cause 21: short message transfer rejected */ - /* FIXME: handle the error somehow? */ + LOGP(DLSMS, LOGL_ERROR, "While trying to deliver a SMS the error code %d received. Sending rp err cause 41 to ms\n", rc); + rc = GSM411_RP_CAUSE_MO_TEMP_FAIL; /* cause 41: Temporary failure */ + rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_DELIVER_UNKNOWN_ERROR]); } return rc; } @@ -319,8 +321,9 @@ rc = 1; /* cause 1: unknown subscriber */ rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); } else if (rc < 0) { - rc = 21; /* cause 21: short message transfer rejected */ - /* FIXME: handle the error somehow? */ + LOGP(DLSMS, LOGL_ERROR, "While trying to deliver a SMS the error code %d received. Sending rp err cause 41 to ms\n", rc); + rc = GSM411_RP_CAUSE_MO_TEMP_FAIL; /* cause 41: Temporary failure */ + rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_DELIVER_UNKNOWN_ERROR]); } #else rc = 1; /* cause 1: unknown subscriber */ -- To view, visit https://gerrit.osmocom.org/551 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia03e50ce2bd9a7d1054cc5a6000fd73bd3497c03 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: lynxis lazus From gerrit-no-reply at lists.osmocom.org Sun Aug 21 19:18:00 2016 From: gerrit-no-reply at lists.osmocom.org (lynxis lazus) Date: Sun, 21 Aug 2016 19:18:00 +0000 Subject: [PATCH] openbsc[master]: libmsc/bsc: split rate counters into bsc and msc group In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/646 to look at the new patch set (#3). libmsc/bsc: split rate counters into bsc and msc group Change-Id: I7361033cd1eb919ec3c2ea2652f40ab8c75b2f99 --- M openbsc/include/openbsc/gsm_data.h M openbsc/include/openbsc/transaction.h M openbsc/src/libbsc/abis_rsl.c M openbsc/src/libbsc/bsc_init.c M openbsc/src/libbsc/bsc_vty.c M openbsc/src/libbsc/gsm_04_08_utils.c M openbsc/src/libbsc/handover_logic.c M openbsc/src/libbsc/net_init.c M openbsc/src/libbsc/paging.c M openbsc/src/libmsc/gsm_04_08.c M openbsc/src/libmsc/gsm_04_11.c M openbsc/src/libmsc/vty_interface_layer3.c 12 files changed, 113 insertions(+), 97 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/46/646/3 diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 9221913..bfb7a60 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -150,25 +150,49 @@ #include "gsm_data_shared.h" -/* Some statistics of our network */ enum { - MSC_CTR_CHREQ_TOTAL, - MSC_CTR_CHREQ_NO_CHANNEL, - MSC_CTR_HANDOVER_ATTEMPTED, - MSC_CTR_HANDOVER_NO_CHANNEL, - MSC_CTR_HANDOVER_TIMEOUT, - MSC_CTR_HANDOVER_COMPLETED, - MSC_CTR_HANDOVER_FAILED, + BSC_CTR_CHREQ_TOTAL, + BSC_CTR_CHREQ_NO_CHANNEL, + BSC_CTR_HANDOVER_ATTEMPTED, + BSC_CTR_HANDOVER_NO_CHANNEL, + BSC_CTR_HANDOVER_TIMEOUT, + BSC_CTR_HANDOVER_COMPLETED, + BSC_CTR_HANDOVER_FAILED, + BSC_CTR_PAGING_ATTEMPTED, + BSC_CTR_PAGING_DETACHED, + BSC_CTR_PAGING_COMPLETED, + BSC_CTR_PAGING_EXPIRED, + BSC_CTR_CHAN_RF_FAIL, + BSC_CTR_CHAN_RLL_ERR, + BSC_CTR_BTS_OML_FAIL, + BSC_CTR_BTS_RSL_FAIL, +}; + +static const struct rate_ctr_desc bsc_ctr_description[] = { + [BSC_CTR_CHREQ_TOTAL] = {"chreq.total", "Received channel requests."}, + [BSC_CTR_CHREQ_NO_CHANNEL] = {"chreq.no_channel", "Sent to MS no channel available."}, + [BSC_CTR_HANDOVER_ATTEMPTED] = {"handover.attempted", "Received handover attempts."}, + [BSC_CTR_HANDOVER_NO_CHANNEL] = {"handover.no_channel", "Sent no channel available responses."}, + [BSC_CTR_HANDOVER_TIMEOUT] = {"handover.timeout", "Count the amount of timeouts of timer T3103."}, + [BSC_CTR_HANDOVER_COMPLETED] = {"handover.completed", "Received handover completed."}, + [BSC_CTR_HANDOVER_FAILED] = {"handover.failed", "Receive HO FAIL messages."}, + [BSC_CTR_PAGING_ATTEMPTED] = {"paging.attempted", "Paging attempts for a MS."}, + [BSC_CTR_PAGING_DETACHED] = {"paging.detached", "Counts the amount of paging attempts which couldn't sent out any paging request because no responsible bts found."}, + [BSC_CTR_PAGING_COMPLETED] = {"paging.completed", "Paging successful completed."}, + [BSC_CTR_PAGING_EXPIRED] = {"paging.expired", "Paging Request expired because of timeout T3113."}, + [BSC_CTR_CHAN_RF_FAIL] = {"chan.rf_fail", "Received a RF failure indication from BTS."}, + [BSC_CTR_CHAN_RLL_ERR] = {"chan.rll_err", "Received a RLL failure with T200 cause from BTS."}, + [BSC_CTR_BTS_OML_FAIL] = {"bts.oml_fail", "Received a TEI down on a OML link."}, + [BSC_CTR_BTS_RSL_FAIL] = {"bts.rsl_fail", "Received a TEI down on a OML link."}, +}; + +enum { MSC_CTR_LOC_UPDATE_TYPE_ATTACH, MSC_CTR_LOC_UPDATE_TYPE_NORMAL, MSC_CTR_LOC_UPDATE_TYPE_PERIODIC, MSC_CTR_LOC_UPDATE_TYPE_DETACH, MSC_CTR_LOC_UPDATE_RESP_REJECT, MSC_CTR_LOC_UPDATE_RESP_ACCEPT, - MSC_CTR_PAGING_ATTEMPTED, - MSC_CTR_PAGING_DETACHED, - MSC_CTR_PAGING_COMPLETED, - MSC_CTR_PAGING_EXPIRED, MSC_CTR_SMS_SUBMITTED, MSC_CTR_SMS_NO_RECEIVER, MSC_CTR_SMS_DELIVERED, @@ -179,30 +203,15 @@ MSC_CTR_CALL_MO_CONNECT_ACK, MSC_CTR_CALL_MT_SETUP, MSC_CTR_CALL_MT_CONNECT, - MSC_CTR_CHAN_RF_FAIL, - MSC_CTR_CHAN_RLL_ERR, - MSC_CTR_BTS_OML_FAIL, - MSC_CTR_BTS_RSL_FAIL, }; static const struct rate_ctr_desc msc_ctr_description[] = { - [MSC_CTR_CHREQ_TOTAL] = {"chreq.total", "Received channel requests."}, - [MSC_CTR_CHREQ_NO_CHANNEL] = {"chreq.no_channel", "Sent to MS no channel available."}, - [MSC_CTR_HANDOVER_ATTEMPTED] = {"handover.attempted", "Received handover attempts."}, - [MSC_CTR_HANDOVER_NO_CHANNEL] = {"handover.no_channel", "Sent no channel available responses."}, - [MSC_CTR_HANDOVER_TIMEOUT] = {"handover.timeout", "Count the amount of timeouts of timer T3103."}, - [MSC_CTR_HANDOVER_COMPLETED] = {"handover.completed", "Received handover completed."}, - [MSC_CTR_HANDOVER_FAILED] = {"handover.failed", "Receive HO FAIL messages."}, [MSC_CTR_LOC_UPDATE_TYPE_ATTACH] = {"loc_update_type.attach", "Received location update imsi attach requests."}, [MSC_CTR_LOC_UPDATE_TYPE_NORMAL] = {"loc_update_type.normal", "Received location update normal requests."}, [MSC_CTR_LOC_UPDATE_TYPE_PERIODIC] = {"loc_update_type.periodic", "Received location update periodic requests."}, [MSC_CTR_LOC_UPDATE_TYPE_DETACH] = {"loc_update_type.detach", "Received location update detach indication."}, [MSC_CTR_LOC_UPDATE_RESP_REJECT] = {"loc_update_resp.reject", "Sent location update reject responses."}, [MSC_CTR_LOC_UPDATE_RESP_ACCEPT] = {"loc_update_resp.accept", "Sent location update accept responses."}, - [MSC_CTR_PAGING_ATTEMPTED] = {"paging.attempted", "Paging attempts for a MS."}, - [MSC_CTR_PAGING_DETACHED] = {"paging.detached", "Counts the amount of paging attempts which couldn't sent out any paging request because no responsible bts found."}, - [MSC_CTR_PAGING_COMPLETED] = {"paging.completed", "Paging successful completed."}, - [MSC_CTR_PAGING_EXPIRED] = {"paging.expired", "Paging Request expired because of timeout T3113."}, [MSC_CTR_SMS_SUBMITTED] = {"sms.submitted", "Received a RPDU from a MS (MO)."}, [MSC_CTR_SMS_NO_RECEIVER] = {"sms.no_receiver", "Counts SMS which couldn't routed because no receiver found."}, [MSC_CTR_SMS_DELIVERED] = {"sms.delivered", "Global SMS Deliver attempts."}, @@ -214,10 +223,15 @@ [MSC_CTR_CALL_MO_CONNECT_ACK] = {"call.mo_connect_ack", "Received a connect ack from MS of a MO call. Call is now succesful connected up."}, [MSC_CTR_CALL_MT_SETUP] = {"call.mt_setup", "Sent setup requests to the MS (MT)."}, [MSC_CTR_CALL_MT_CONNECT] = {"call.mt_connect", "Sent a connect to the MS (MT)."}, - [MSC_CTR_CHAN_RF_FAIL] = {"chan.rf_fail", "Received a RF failure indication from BTS."}, - [MSC_CTR_CHAN_RLL_ERR] = {"chan.rll_err", "Received a RLL failure with T200 cause from BTS."}, - [MSC_CTR_BTS_OML_FAIL] = {"bts.oml_fail", "Received a TEI down on a OML link."}, - [MSC_CTR_BTS_RSL_FAIL] = {"bts.rsl_fail", "Received a TEI down on a OML link."}, +}; + + +static const struct rate_ctr_group_desc bsc_ctrg_desc = { + "bsc", + "base station controller", + OSMO_STATS_CLASS_GLOBAL, + ARRAY_SIZE(bsc_ctr_description), + bsc_ctr_description, }; static const struct rate_ctr_group_desc msc_ctrg_desc = { @@ -270,7 +284,8 @@ unsigned int max_distance; /* TA values */ } handover; - struct rate_ctr_group *ratectrs; + struct rate_ctr_group *bsc_ctrs; + struct rate_ctr_group *msc_ctrs; /* layer 4 */ diff --git a/openbsc/include/openbsc/transaction.h b/openbsc/include/openbsc/transaction.h index 6ef1612..bf7b22d 100644 --- a/openbsc/include/openbsc/transaction.h +++ b/openbsc/include/openbsc/transaction.h @@ -14,7 +14,7 @@ /* Entry in list of all transactions */ struct llist_head entry; - /* Back pointer to the netweork struct */ + /* Back pointer to the network struct */ struct gsm_network *net; /* The protocol within which we live */ diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index 092ec4e..69d69e8 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -1207,7 +1207,7 @@ TLVP_LEN(&tp, RSL_IE_CAUSE)); LOGPC(DRSL, LOGL_NOTICE, "\n"); - rate_ctr_inc(&msg->lchan->ts->trx->bts->network->ratectrs->ctr[MSC_CTR_CHAN_RF_FAIL]); + rate_ctr_inc(&msg->lchan->ts->trx->bts->network->bsc_ctrs->ctr[BSC_CTR_CHAN_RF_FAIL]); return rsl_rf_chan_release_err(msg->lchan); } @@ -1641,7 +1641,7 @@ lctype = get_ctype_by_chreq(bts->network, rqd_ref->ra); chreq_reason = get_reason_by_chreq(rqd_ref->ra, bts->network->neci); - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_CHREQ_TOTAL]); + rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_CHREQ_TOTAL]); /* * We want LOCATION UPDATES to succeed and will assign a TCH @@ -1654,7 +1654,7 @@ if (!lchan) { LOGP(DRSL, LOGL_NOTICE, "BTS %d CHAN RQD: no resources for %s 0x%x\n", msg->lchan->ts->trx->bts->nr, gsm_lchant_name(lctype), rqd_ref->ra); - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_CHREQ_NO_CHANNEL]); + rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_CHREQ_NO_CHANNEL]); /* FIXME gather multiple CHAN RQD and reject up to 4 at the same time */ if (bts->network->T3122) rsl_send_imm_ass_rej(bts, 1, rqd_ref, bts->network->T3122 & 0xff); @@ -1837,7 +1837,7 @@ rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_ERR_IND); if (rlm_cause == RLL_CAUSE_T200_EXPIRED) { - rate_ctr_inc(&msg->lchan->ts->trx->bts->network->ratectrs->ctr[MSC_CTR_CHAN_RLL_ERR]); + rate_ctr_inc(&msg->lchan->ts->trx->bts->network->bsc_ctrs->ctr[BSC_CTR_CHAN_RLL_ERR]); return rsl_rf_chan_release_err(msg->lchan); } diff --git a/openbsc/src/libbsc/bsc_init.c b/openbsc/src/libbsc/bsc_init.c index 5ea85d0..989fca8 100644 --- a/openbsc/src/libbsc/bsc_init.c +++ b/openbsc/src/libbsc/bsc_init.c @@ -340,9 +340,9 @@ LOGP(DLMI, LOGL_ERROR, "Lost some E1 TEI link: %d %p\n", isd->link_type, trx); if (isd->link_type == E1INP_SIGN_OML) - rate_ctr_inc(&trx->bts->network->ratectrs->ctr[MSC_CTR_BTS_OML_FAIL]); + rate_ctr_inc(&trx->bts->network->bsc_ctrs->ctr[BSC_CTR_BTS_OML_FAIL]); else if (isd->link_type == E1INP_SIGN_RSL) - rate_ctr_inc(&trx->bts->network->ratectrs->ctr[MSC_CTR_BTS_RSL_FAIL]); + rate_ctr_inc(&trx->bts->network->bsc_ctrs->ctr[BSC_CTR_BTS_RSL_FAIL]); /* * free all allocated channels. change the nm_state so the diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c index fbaf06b..8116af1 100644 --- a/openbsc/src/libbsc/bsc_vty.c +++ b/openbsc/src/libbsc/bsc_vty.c @@ -3784,21 +3784,21 @@ void openbsc_vty_print_statistics(struct vty *vty, struct gsm_network *net) { vty_out(vty, "Channel Requests : %lu total, %lu no channel%s", - net->ratectrs->ctr[MSC_CTR_CHREQ_TOTAL].current, - net->ratectrs->ctr[MSC_CTR_CHREQ_NO_CHANNEL].current, + net->bsc_ctrs->ctr[BSC_CTR_CHREQ_TOTAL].current, + net->bsc_ctrs->ctr[BSC_CTR_CHREQ_NO_CHANNEL].current, VTY_NEWLINE); vty_out(vty, "Channel Failures : %lu rf_failures, %lu rll failures%s", - net->ratectrs->ctr[MSC_CTR_CHAN_RF_FAIL].current, - net->ratectrs->ctr[MSC_CTR_CHAN_RLL_ERR].current, + net->bsc_ctrs->ctr[BSC_CTR_CHAN_RF_FAIL].current, + net->bsc_ctrs->ctr[BSC_CTR_CHAN_RLL_ERR].current, VTY_NEWLINE); vty_out(vty, "Paging : %lu attempted, %lu complete, %lu expired%s", - net->ratectrs->ctr[MSC_CTR_PAGING_ATTEMPTED].current, - net->ratectrs->ctr[MSC_CTR_PAGING_COMPLETED].current, - net->ratectrs->ctr[MSC_CTR_PAGING_EXPIRED].current, + net->bsc_ctrs->ctr[BSC_CTR_PAGING_ATTEMPTED].current, + net->bsc_ctrs->ctr[BSC_CTR_PAGING_COMPLETED].current, + net->bsc_ctrs->ctr[BSC_CTR_PAGING_EXPIRED].current, VTY_NEWLINE); vty_out(vty, "BTS failures : %lu OML, %lu RSL%s", - net->ratectrs->ctr[MSC_CTR_BTS_OML_FAIL].current, - net->ratectrs->ctr[MSC_CTR_BTS_RSL_FAIL].current, + net->bsc_ctrs->ctr[BSC_CTR_BTS_OML_FAIL].current, + net->bsc_ctrs->ctr[BSC_CTR_BTS_RSL_FAIL].current, VTY_NEWLINE); } diff --git a/openbsc/src/libbsc/gsm_04_08_utils.c b/openbsc/src/libbsc/gsm_04_08_utils.c index d4eca4a..46df108 100644 --- a/openbsc/src/libbsc/gsm_04_08_utils.c +++ b/openbsc/src/libbsc/gsm_04_08_utils.c @@ -304,7 +304,7 @@ subscr = conn->subscr; } - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_PAGING_COMPLETED]); + rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_PAGING_COMPLETED]); /* Stop paging on the bts we received the paging response */ paging_request_stop(conn->bts, subscr, conn, msg); diff --git a/openbsc/src/libbsc/handover_logic.c b/openbsc/src/libbsc/handover_logic.c index 5424e27..ffcca66 100644 --- a/openbsc/src/libbsc/handover_logic.c +++ b/openbsc/src/libbsc/handover_logic.c @@ -103,7 +103,7 @@ DEBUGP(DHO, "(old_lchan on BTS %u, new BTS %u)\n", old_lchan->ts->trx->bts->nr, bts->nr); - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_HANDOVER_ATTEMPTED]); + rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_HANDOVER_ATTEMPTED]); if (!old_lchan->conn) { LOGP(DHO, LOGL_ERROR, "Old lchan lacks connection data.\n"); @@ -113,7 +113,7 @@ new_lchan = lchan_alloc(bts, old_lchan->type, 0); if (!new_lchan) { LOGP(DHO, LOGL_NOTICE, "No free channel\n"); - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_HANDOVER_NO_CHANNEL]); + rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_HANDOVER_NO_CHANNEL]); return -ENOSPC; } @@ -188,7 +188,7 @@ struct gsm_network *net = ho->new_lchan->ts->trx->bts->network; DEBUGP(DHO, "HO T3103 expired\n"); - rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_HANDOVER_TIMEOUT]); + rate_ctr_inc(&net->bsc_ctrs->ctr[BSC_CTR_HANDOVER_TIMEOUT]); ho->new_lchan->conn->ho_lchan = NULL; ho->new_lchan->conn = NULL; @@ -265,7 +265,7 @@ ho->old_lchan->ts->trx->bts->nr, new_lchan->ts->trx->bts->nr, ho->old_lchan->ts->trx->arfcn, new_lchan->ts->trx->arfcn); - rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_HANDOVER_COMPLETED]); + rate_ctr_inc(&net->bsc_ctrs->ctr[BSC_CTR_HANDOVER_COMPLETED]); osmo_timer_del(&ho->T3103); @@ -303,7 +303,7 @@ return -ENODEV; } - rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_HANDOVER_FAILED]); + rate_ctr_inc(&net->bsc_ctrs->ctr[BSC_CTR_HANDOVER_FAILED]); new_lchan = ho->new_lchan; diff --git a/openbsc/src/libbsc/net_init.c b/openbsc/src/libbsc/net_init.c index b99f3d2..37ba3c0 100644 --- a/openbsc/src/libbsc/net_init.c +++ b/openbsc/src/libbsc/net_init.c @@ -81,7 +81,8 @@ INIT_LLIST_HEAD(&net->bts_list); /* init statistics */ - net->ratectrs = rate_ctr_group_alloc(net, &msc_ctrg_desc, 0); + net->bsc_ctrs = rate_ctr_group_alloc(net, &bsc_ctrg_desc, 0); + net->bsc_ctrs = rate_ctr_group_alloc(net, &msc_ctrg_desc, 0); net->mncc_recv = mncc_recv; net->ext_min = GSM_MIN_EXTEN; diff --git a/openbsc/src/libbsc/paging.c b/openbsc/src/libbsc/paging.c index 03c91fd..fcb4deb 100644 --- a/openbsc/src/libbsc/paging.c +++ b/openbsc/src/libbsc/paging.c @@ -260,7 +260,7 @@ req, req->subscr->imsi); /* must be destroyed before calling cbfn, to prevent double free */ - rate_ctr_inc(&req->bts->network->ratectrs->ctr[MSC_CTR_PAGING_EXPIRED]); + rate_ctr_inc(&req->bts->network->bsc_ctrs->ctr[BSC_CTR_PAGING_EXPIRED]); cbfn_param = req->cbfn_param; cbfn = req->cbfn; @@ -330,7 +330,7 @@ struct gsm_bts *bts = NULL; int num_pages = 0; - rate_ctr_inc(&network->ratectrs->ctr[MSC_CTR_PAGING_ATTEMPTED]); + rate_ctr_inc(&network->bsc_ctrs->ctr[BSC_CTR_PAGING_ATTEMPTED]); /* start paging subscriber on all BTS within Location Area */ do { @@ -349,7 +349,7 @@ } while (1); if (num_pages == 0) - rate_ctr_inc(&network->ratectrs->ctr[MSC_CTR_PAGING_DETACHED]); + rate_ctr_inc(&network->bsc_ctrs->ctr[BSC_CTR_PAGING_DETACHED]); return num_pages; } diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c index c4ecf1c..c30fbb0 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/src/libmsc/gsm_04_08.c @@ -457,7 +457,7 @@ struct gsm_bts *bts = conn->bts; struct msgb *msg; - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_REJECT]); + rate_ctr_inc(&bts->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_RESP_REJECT]); msg = gsm48_create_loc_upd_rej(cause); if (!msg) { @@ -506,7 +506,7 @@ DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n"); - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_ACCEPT]); + rate_ctr_inc(&bts->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_RESP_ACCEPT]); return gsm48_conn_sendmsg(msg, conn, NULL); } @@ -637,13 +637,13 @@ switch (lu->type) { case GSM48_LUPD_NORMAL: - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_NORMAL]); + rate_ctr_inc(&bts->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_NORMAL]); break; case GSM48_LUPD_IMSI_ATT: - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_ATTACH]); + rate_ctr_inc(&bts->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_ATTACH]); break; case GSM48_LUPD_PERIODIC: - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_PERIODIC]); + rate_ctr_inc(&bts->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_PERIODIC]); break; } @@ -1063,7 +1063,7 @@ DEBUGP(DMM, "IMSI DETACH INDICATION: MI(%s)=%s", gsm48_mi_type_name(mi_type), mi_string); - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_DETACH]); + rate_ctr_inc(&bts->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_DETACH]); switch (mi_type) { case GSM_MI_TYPE_TMSI: @@ -2002,7 +2002,7 @@ subscr_name(trans->subscr), trans->subscr->extension, setup.called.number); - rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MO_SETUP]); + rate_ctr_inc(&trans->net->msc_ctrs->ctr[MSC_CTR_CALL_MO_SETUP]); /* indicate setup to MNCC */ mncc_recvmsg(trans->net, trans, MNCC_SETUP_IND, &setup); @@ -2080,7 +2080,7 @@ new_cc_state(trans, GSM_CSTATE_CALL_PRESENT); - rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MT_SETUP]); + rate_ctr_inc(&trans->net->msc_ctrs->ctr[MSC_CTR_CALL_MT_SETUP]); return gsm48_conn_sendmsg(msg, trans->conn, trans); } @@ -2306,7 +2306,7 @@ } new_cc_state(trans, GSM_CSTATE_CONNECT_REQUEST); - rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MT_CONNECT]); + rate_ctr_inc(&trans->net->msc_ctrs->ctr[MSC_CTR_CALL_MT_CONNECT]); return mncc_recvmsg(trans->net, trans, MNCC_SETUP_CNF, &connect); } @@ -2319,7 +2319,7 @@ gsm48_stop_cc_timer(trans); new_cc_state(trans, GSM_CSTATE_ACTIVE); - rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MO_CONNECT_ACK]); + rate_ctr_inc(&trans->net->msc_ctrs->ctr[MSC_CTR_CALL_MO_CONNECT_ACK]); memset(&connect_ack, 0, sizeof(struct gsm_mncc)); connect_ack.callref = trans->callref; diff --git a/openbsc/src/libmsc/gsm_04_11.c b/openbsc/src/libmsc/gsm_04_11.c index 619ff42..bf70971 100644 --- a/openbsc/src/libmsc/gsm_04_11.c +++ b/openbsc/src/libmsc/gsm_04_11.c @@ -297,7 +297,7 @@ if (rc < 0) { LOGP(DLSMS, LOGL_ERROR, "While trying to deliver a SMS the error code %d received. Sending rp err cause 41 to ms\n", rc); rc = GSM411_RP_CAUSE_MO_TEMP_FAIL; /* cause 41: Temporary failure */ - rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_DELIVER_UNKNOWN_ERROR]); + rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_DELIVER_UNKNOWN_ERROR]); } return rc; } @@ -312,22 +312,22 @@ #ifdef BUILD_SMPP /* Avoid a second look-up */ if (smpp_first) { - rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); + rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); return 1; /* cause 1: unknown subscriber */ } rc = smpp_try_deliver(gsms, conn); if (rc == 1) { rc = 1; /* cause 1: unknown subscriber */ - rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); + rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); } else if (rc < 0) { LOGP(DLSMS, LOGL_ERROR, "While trying to deliver a SMS the error code %d received. Sending rp err cause 41 to ms\n", rc); rc = GSM411_RP_CAUSE_MO_TEMP_FAIL; /* cause 41: Temporary failure */ - rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_DELIVER_UNKNOWN_ERROR]); + rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_DELIVER_UNKNOWN_ERROR]); } #else rc = 1; /* cause 1: unknown subscriber */ - rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); + rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); #endif return rc; } @@ -368,7 +368,7 @@ uint8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */ int rc = 0; - rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_SUBMITTED]); + rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_SUBMITTED]); gsms = sms_alloc(); if (!gsms) @@ -638,10 +638,10 @@ * to store this in our database and wait for a SMMA message */ /* FIXME */ send_signal(S_SMS_MEM_EXCEEDED, trans, sms, 0); - rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_MEM]); + rate_ctr_inc(&net->msc_ctrs->ctr[MSC_CTR_SMS_RP_ERR_MEM]); } else { send_signal(S_SMS_UNKNOWN_ERROR, trans, sms, 0); - rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_OTHER]); + rate_ctr_inc(&net->msc_ctrs->ctr[MSC_CTR_SMS_RP_ERR_OTHER]); } sms_free(sms); @@ -937,7 +937,7 @@ DEBUGP(DLSMS, "TX: SMS DELIVER\n"); - rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_DELIVERED]); + rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_DELIVERED]); db_sms_inc_deliver_attempts(trans->sms.sms); return gsm411_rp_sendmsg(&trans->sms.smr_inst, msg, diff --git a/openbsc/src/libmsc/vty_interface_layer3.c b/openbsc/src/libmsc/vty_interface_layer3.c index d1041b3..e7ff0a9 100644 --- a/openbsc/src/libmsc/vty_interface_layer3.c +++ b/openbsc/src/libmsc/vty_interface_layer3.c @@ -795,41 +795,41 @@ openbsc_vty_print_statistics(vty, net); vty_out(vty, "Location Update : %lu attach, %lu normal, %lu periodic%s", - net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_ATTACH].current, - net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_NORMAL].current, - net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_PERIODIC].current, + net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_ATTACH].current, + net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_NORMAL].current, + net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_PERIODIC].current, VTY_NEWLINE); vty_out(vty, "IMSI Detach Indications : %lu%s", - net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_DETACH].current, + net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_DETACH].current, VTY_NEWLINE); vty_out(vty, "Location Update Response: %lu accept, %lu reject%s", - net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_ACCEPT].current, - net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_REJECT].current, + net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_RESP_ACCEPT].current, + net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_RESP_REJECT].current, VTY_NEWLINE); vty_out(vty, "Handover : %lu attempted, %lu no_channel, %lu timeout, " "%lu completed, %lu failed%s", - net->ratectrs->ctr[MSC_CTR_HANDOVER_ATTEMPTED].current, - net->ratectrs->ctr[MSC_CTR_HANDOVER_NO_CHANNEL].current, - net->ratectrs->ctr[MSC_CTR_HANDOVER_TIMEOUT].current, - net->ratectrs->ctr[MSC_CTR_HANDOVER_COMPLETED].current, - net->ratectrs->ctr[MSC_CTR_HANDOVER_FAILED].current, + net->msc_ctrs->ctr[BSC_CTR_HANDOVER_ATTEMPTED].current, + net->msc_ctrs->ctr[BSC_CTR_HANDOVER_NO_CHANNEL].current, + net->msc_ctrs->ctr[BSC_CTR_HANDOVER_TIMEOUT].current, + net->msc_ctrs->ctr[BSC_CTR_HANDOVER_COMPLETED].current, + net->msc_ctrs->ctr[BSC_CTR_HANDOVER_FAILED].current, VTY_NEWLINE); vty_out(vty, "SMS MO : %lu submitted, %lu no receiver%s", - net->ratectrs->ctr[MSC_CTR_SMS_SUBMITTED].current, - net->ratectrs->ctr[MSC_CTR_SMS_NO_RECEIVER].current, + net->msc_ctrs->ctr[MSC_CTR_SMS_SUBMITTED].current, + net->msc_ctrs->ctr[MSC_CTR_SMS_NO_RECEIVER].current, VTY_NEWLINE); vty_out(vty, "SMS MT : %lu delivered, %lu no memory, %lu other error%s", - net->ratectrs->ctr[MSC_CTR_SMS_DELIVERED].current, - net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_MEM].current, - net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_OTHER].current, + net->msc_ctrs->ctr[MSC_CTR_SMS_DELIVERED].current, + net->msc_ctrs->ctr[MSC_CTR_SMS_RP_ERR_MEM].current, + net->msc_ctrs->ctr[MSC_CTR_SMS_RP_ERR_OTHER].current, VTY_NEWLINE); vty_out(vty, "MO Calls : %lu setup, %lu connect ack%s", - net->ratectrs->ctr[MSC_CTR_CALL_MO_SETUP].current, - net->ratectrs->ctr[MSC_CTR_CALL_MO_CONNECT_ACK].current, + net->msc_ctrs->ctr[MSC_CTR_CALL_MO_SETUP].current, + net->msc_ctrs->ctr[MSC_CTR_CALL_MO_CONNECT_ACK].current, VTY_NEWLINE); vty_out(vty, "MT Calls : %lu setup, %lu connect%s", - net->ratectrs->ctr[MSC_CTR_CALL_MT_SETUP].current, - net->ratectrs->ctr[MSC_CTR_CALL_MT_CONNECT].current, + net->msc_ctrs->ctr[MSC_CTR_CALL_MT_SETUP].current, + net->msc_ctrs->ctr[MSC_CTR_CALL_MT_CONNECT].current, VTY_NEWLINE); return CMD_SUCCESS; } -- To view, visit https://gerrit.osmocom.org/646 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I7361033cd1eb919ec3c2ea2652f40ab8c75b2f99 Gerrit-PatchSet: 3 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 22 07:28:11 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Mon, 22 Aug 2016 07:28:11 +0000 Subject: [PATCH] osmo-pcu[master]: Describe the issue with EGPRS PUAN encoding In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/702 to look at the new patch set (#2). Describe the issue with EGPRS PUAN encoding Currently pcu doesn?t encode EGPRS PUAN message for VQ not equal to VR case. This patch describe the issue with initially sending the BSN 1 which generated the PUAN message as below 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b. Later Unit test frame work sends BSN 4 and PUAN generated is below 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b which is same as previous PUAN message. Please see the Generated test file. This is considerable issue with OTA. The assert in the test file needs to be corrected. Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 --- M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 3 files changed, 298 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/02/702/2 diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..cea9d75 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -618,6 +618,143 @@ &ulreq, tbf->poll_fn); } +static gprs_rlcmac_ul_tbf *puan_issue(BTS *the_bts, + uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, + uint8_t ms_class, uint8_t egprs_ms_class) +{ + GprsMs *ms; + uint32_t rach_fn = *fn - 51; + uint32_t sba_fn = *fn + 52; + uint8_t trx_no = 0; + int tfi = 0, i = 0; + gprs_rlcmac_ul_tbf *ul_tbf; + struct gprs_rlcmac_pdch *pdch; + gprs_rlcmac_bts *bts; + RlcMacUplink_t ulreq = {0}; + struct pcu_l1_meas meas; + struct gprs_rlc_ul_header_egprs_3 *egprs3 = NULL; + GprsCodingScheme cs; + + meas.set_rssi(31); + bts = the_bts->bts_data(); + + /* needed to set last_rts_fn in the PDCH object */ + request_dl_rlc_block(bts, trx_no, ts_no, fn); + + /* + * simulate RACH, this sends an Immediate + * Assignment Uplink on the AGCH + */ + the_bts->rcv_rach(0x73, rach_fn, qta); + + /* get next free TFI */ + tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1); + + /* fake a resource request */ + ulreq.u.MESSAGE_TYPE = MT_PACKET_RESOURCE_REQUEST; + ulreq.u.Packet_Resource_Request.PayloadType = GPRS_RLCMAC_CONTROL_BLOCK; + ulreq.u.Packet_Resource_Request.ID.UnionType = 1; /* != 0 */ + ulreq.u.Packet_Resource_Request.ID.u.TLLI = tlli; + ulreq.u.Packet_Resource_Request.Exist_MS_Radio_Access_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + Count_MS_RA_capability_value = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Exist_Multislot_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + Exist_GPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + GPRS_multislot_class = ms_class; + if (egprs_ms_class) { + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Multislot_capability.Exist_EGPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Multislot_capability.EGPRS_multislot_class = ms_class; + } + + send_ul_mac_block(the_bts, trx_no, ts_no, &ulreq, sba_fn); + + /* check the TBF */ + ul_tbf = the_bts->ul_tbf_by_tfi(tfi, trx_no, ts_no); + OSMO_ASSERT(ul_tbf != NULL); + OSMO_ASSERT(ul_tbf->ta() == qta / 4); + + /* send packet uplink assignment */ + *fn = sba_fn; + request_dl_rlc_block(ul_tbf, fn); + + /* send real acknowledgement */ + send_control_ack(ul_tbf); + + check_tbf(ul_tbf); + /* send fake data */ + uint8_t data_msg[42] = { + 0x00 | 0xf << 2, /* GPRS_RLCMAC_DATA_BLOCK << 6, CV = 15 */ + uint8_t(0 | (tfi << 1)), + 1, /* BSN:7, E:1 */ + }; + + pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no]; + pdch->rcv_block(&data_msg[0], 23, *fn, &meas); + + ms = the_bts->ms_by_tlli(tlli); + OSMO_ASSERT(ms != NULL); + OSMO_ASSERT(ms->ta() == qta/4); + OSMO_ASSERT(ms->ul_tbf() == ul_tbf); + + /* + * TS 44.060, B.8.1 + * first seg received first, later second seg + */ + cs = GprsCodingScheme::MCS3; + egprs3 = (struct gprs_rlc_ul_header_egprs_3 *) data_msg; + egprs3->si = 0; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 1; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 0; + egprs3->pi = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + struct msgb *msg1 = ul_tbf->create_ul_ack(*fn, ts_no); + + egprs3->si = 0; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 4; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + struct msgb *msg2 = ul_tbf->create_ul_ack(*fn, ts_no); + + /* TODO: Need to modify the assert */ + OSMO_ASSERT(!memcmp(msg2->data, msg1->data, msg1->data_len)); + + return ul_tbf; +} + static gprs_rlcmac_ul_tbf *establish_ul_tbf_two_phase_spb(BTS *the_bts, uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, uint8_t ms_class, uint8_t egprs_ms_class) @@ -1631,6 +1768,41 @@ gprs_bssgp_destroy(); } +static void test_tbf_puan_issue(void) +{ + BTS the_bts; + int ts_no = 7; + uint32_t fn = 2654218; + uint16_t qta = 31; + uint32_t tlli = 0xf1223344; + const char *imsi = "0011223344"; + uint8_t ms_class = 1; + uint8_t egprs_ms_class = 1; + gprs_rlcmac_ul_tbf *ul_tbf; + GprsMs *ms; + uint8_t test_data[256]; + + printf("=== start %s ===\n", __func__); + + memset(test_data, 1, sizeof(test_data)); + + setup_bts(&the_bts, ts_no, 4); + the_bts.bts_data()->initial_mcs_dl = 9; + the_bts.bts_data()->egprs_enabled = 1; + + ul_tbf = puan_issue(&the_bts, ts_no, tlli, &fn, qta, + ms_class, egprs_ms_class); + + ms = ul_tbf->ms(); + fprintf(stderr, "Got '%s', TA=%d\n", ul_tbf->name(), ul_tbf->ta()); + fprintf(stderr, + "Got MS: TLLI = 0x%08x, TA = %d\n", ms->tlli(), ms->ta()); + + send_dl_data(&the_bts, tlli, imsi, test_data, sizeof(test_data)); + + printf("=== end %s ===\n", __func__); +} + static void test_tbf_egprs_two_phase_spb(void) { BTS the_bts; @@ -2071,6 +2243,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_puan_issue(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..aa8a087 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -5780,3 +5780,126 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654218 block=8 data=47 94 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +MS requests UL TBF on RACH, so we provide one: +MS requests single block allocation +RX: [PCU <- BTS] RACH qbit-ta=31 ra=0x73, Fn=2654167 (17,25,9), SBFn=2654270 +TX: Immediate Assignment Uplink (AGCH) + - TRX=0 (0) TS=7 TA=7 TSC=0 TFI=-1 USF=7 +Sending data request: trx=0 ts=0 sapi=2 arfcn=0 fn=0 block=0 data=2d 06 3f 10 0f 00 00 73 8b 29 07 00 c0 0c 5a 43 2b 2b 2b 2b 2b 2b 2b +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +MS requests UL TBF in packet resource request of single block, so we provide one: +MS supports EGPRS multislot class 1. +********** TBF starts here ********** +Allocating UL TBF: MS_CLASS=1/1 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 1 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 1 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign uplink TS=7 TFI=0 USF=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 00 +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=ASSIGN EGPRS) starting timer 3169. +Modifying MS object, UL TLLI: 0x00000000 -> 0xf1223344, not yet confirmed +Modifying MS object, TLLI = 0xf1223344, TA 0 -> 7 +Change control TS to 7 until assinment is complete. +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS)s start Packet Uplink Assignment (PACCH) ++++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++ +------------------------- TX : Packet Uplink Assignment ------------------------- +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS): Scheduling polling at FN 2654283 TS 7 +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS) changes state from ASSIGN to WAIT ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Scheduled UL Assignment polling on FN=2654283, TS=7 +Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) (TRX=0, TS=7) +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654270 block=8 data=4f 28 5e 24 46 68 90 f8 0a 39 00 00 88 00 08 2b 2b 2b 2b 2b 2b 2b 2b +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Packet Control Ack +TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) changes state from WAIT ASSIGN to FLOW +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=0 .. V(R)=0) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got CS-1 RLC data block: CV=15, BSN=0, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 0 storing in window (0..63) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 1 +- Taking block 0 out, raising V(Q) to 1 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=0 CV=15 +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1d 08 40 c1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=0, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=1) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=1, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 1 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 2 +- Taking block 1 out, raising V(Q) to 2 +- Assembling frames: (len=37) +-- Frame 1 starts at offset 0, length=37, is_complete=0 +- No gaps in received block, last block: BSN=1 CV=7 +Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) + - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 2, BOW, EOW +Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1d 20 40 c1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=0, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=2 .. V(R)=2) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=4, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 4 storing in window (2..65) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 5 +Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) + - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 5, BOW, EOW +Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got 'TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS)', TA=7 +Got MS: TLLI = 0xf1223344, TA = 7 +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=1/1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign downlink TS=7 TFI=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0xf1223344, TBF = TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 80 +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +Modifying MS object, TLLI: 0xf1223344 confirmed +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) [DOWNLINK] START +Modifying MS object, TLLI = 0xf1223344, IMSI '' -> '0011223344' +Send dowlink assignment on PACCH, because TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) exists +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) starting timer 0. +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) append diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..6b99857 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,5 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_puan_issue === +=== end test_tbf_puan_issue === -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 2 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Mon Aug 22 07:30:09 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Mon, 22 Aug 2016 07:30:09 +0000 Subject: [PATCH] osmo-pcu[master]: Describe the issue with EGPRS PUAN encoding In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/702 to look at the new patch set (#3). Describe the issue with EGPRS PUAN encoding Currently pcu doesn?t encode EGPRS PUAN message for VQ not equal to VR case. This patch describe the issue with initially sending the BSN 1 which generated the PUAN message as below 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b. Later Unit test frame work sends BSN 4 and PUAN generated is below 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b which is same as previous PUAN message. Please see the Generated test file. This is considerable issue with OTA. The assert in the test file needs to be corrected. Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 --- M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 3 files changed, 298 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/02/702/3 diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..26ba0d6 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -618,6 +618,143 @@ &ulreq, tbf->poll_fn); } +static gprs_rlcmac_ul_tbf *puan_issue(BTS *the_bts, + uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, + uint8_t ms_class, uint8_t egprs_ms_class) +{ + GprsMs *ms; + uint32_t rach_fn = *fn - 51; + uint32_t sba_fn = *fn + 52; + uint8_t trx_no = 0; + int tfi = 0, i = 0; + gprs_rlcmac_ul_tbf *ul_tbf; + struct gprs_rlcmac_pdch *pdch; + gprs_rlcmac_bts *bts; + RlcMacUplink_t ulreq = {0}; + struct pcu_l1_meas meas; + struct gprs_rlc_ul_header_egprs_3 *egprs3 = NULL; + GprsCodingScheme cs; + + meas.set_rssi(31); + bts = the_bts->bts_data(); + + /* needed to set last_rts_fn in the PDCH object */ + request_dl_rlc_block(bts, trx_no, ts_no, fn); + + /* + * simulate RACH, this sends an Immediate + * Assignment Uplink on the AGCH + */ + the_bts->rcv_rach(0x73, rach_fn, qta); + + /* get next free TFI */ + tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1); + + /* fake a resource request */ + ulreq.u.MESSAGE_TYPE = MT_PACKET_RESOURCE_REQUEST; + ulreq.u.Packet_Resource_Request.PayloadType = GPRS_RLCMAC_CONTROL_BLOCK; + ulreq.u.Packet_Resource_Request.ID.UnionType = 1; /* != 0 */ + ulreq.u.Packet_Resource_Request.ID.u.TLLI = tlli; + ulreq.u.Packet_Resource_Request.Exist_MS_Radio_Access_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + Count_MS_RA_capability_value = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Exist_Multislot_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + Exist_GPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + GPRS_multislot_class = ms_class; + if (egprs_ms_class) { + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Multislot_capability.Exist_EGPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Multislot_capability.EGPRS_multislot_class = ms_class; + } + + send_ul_mac_block(the_bts, trx_no, ts_no, &ulreq, sba_fn); + + /* check the TBF */ + ul_tbf = the_bts->ul_tbf_by_tfi(tfi, trx_no, ts_no); + OSMO_ASSERT(ul_tbf != NULL); + OSMO_ASSERT(ul_tbf->ta() == qta / 4); + + /* send packet uplink assignment */ + *fn = sba_fn; + request_dl_rlc_block(ul_tbf, fn); + + /* send real acknowledgement */ + send_control_ack(ul_tbf); + + check_tbf(ul_tbf); + /* send fake data */ + uint8_t data_msg[42] = { + 0xf << 2, /* GPRS_RLCMAC_DATA_BLOCK << 6, CV = 15 */ + uint8_t(0 | (tfi << 1)), + uint8_t(1), /* BSN:7, E:1 */ + }; + + pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no]; + pdch->rcv_block(&data_msg[0], 23, *fn, &meas); + + ms = the_bts->ms_by_tlli(tlli); + OSMO_ASSERT(ms != NULL); + OSMO_ASSERT(ms->ta() == qta/4); + OSMO_ASSERT(ms->ul_tbf() == ul_tbf); + + /* + * TS 44.060, B.8.1 + * first seg received first, later second seg + */ + cs = GprsCodingScheme::MCS3; + egprs3 = (struct gprs_rlc_ul_header_egprs_3 *) data_msg; + egprs3->si = 0; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 1; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 0; + egprs3->pi = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + struct msgb *msg1 = ul_tbf->create_ul_ack(*fn, ts_no); + + egprs3->si = 0; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 4; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + struct msgb *msg2 = ul_tbf->create_ul_ack(*fn, ts_no); + + /* TODO: Need to modify the assert */ + OSMO_ASSERT(!memcmp(msg2->data, msg1->data, msg1->data_len)); + + return ul_tbf; +} + static gprs_rlcmac_ul_tbf *establish_ul_tbf_two_phase_spb(BTS *the_bts, uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, uint8_t ms_class, uint8_t egprs_ms_class) @@ -1631,6 +1768,41 @@ gprs_bssgp_destroy(); } +static void test_tbf_puan_issue(void) +{ + BTS the_bts; + int ts_no = 7; + uint32_t fn = 2654218; + uint16_t qta = 31; + uint32_t tlli = 0xf1223344; + const char *imsi = "0011223344"; + uint8_t ms_class = 1; + uint8_t egprs_ms_class = 1; + gprs_rlcmac_ul_tbf *ul_tbf; + GprsMs *ms; + uint8_t test_data[256]; + + printf("=== start %s ===\n", __func__); + + memset(test_data, 1, sizeof(test_data)); + + setup_bts(&the_bts, ts_no, 4); + the_bts.bts_data()->initial_mcs_dl = 9; + the_bts.bts_data()->egprs_enabled = 1; + + ul_tbf = puan_issue(&the_bts, ts_no, tlli, &fn, qta, + ms_class, egprs_ms_class); + + ms = ul_tbf->ms(); + fprintf(stderr, "Got '%s', TA=%d\n", ul_tbf->name(), ul_tbf->ta()); + fprintf(stderr, + "Got MS: TLLI = 0x%08x, TA = %d\n", ms->tlli(), ms->ta()); + + send_dl_data(&the_bts, tlli, imsi, test_data, sizeof(test_data)); + + printf("=== end %s ===\n", __func__); +} + static void test_tbf_egprs_two_phase_spb(void) { BTS the_bts; @@ -2071,6 +2243,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_puan_issue(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..aa8a087 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -5780,3 +5780,126 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654218 block=8 data=47 94 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +MS requests UL TBF on RACH, so we provide one: +MS requests single block allocation +RX: [PCU <- BTS] RACH qbit-ta=31 ra=0x73, Fn=2654167 (17,25,9), SBFn=2654270 +TX: Immediate Assignment Uplink (AGCH) + - TRX=0 (0) TS=7 TA=7 TSC=0 TFI=-1 USF=7 +Sending data request: trx=0 ts=0 sapi=2 arfcn=0 fn=0 block=0 data=2d 06 3f 10 0f 00 00 73 8b 29 07 00 c0 0c 5a 43 2b 2b 2b 2b 2b 2b 2b +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +MS requests UL TBF in packet resource request of single block, so we provide one: +MS supports EGPRS multislot class 1. +********** TBF starts here ********** +Allocating UL TBF: MS_CLASS=1/1 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 1 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 1 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign uplink TS=7 TFI=0 USF=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 00 +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=ASSIGN EGPRS) starting timer 3169. +Modifying MS object, UL TLLI: 0x00000000 -> 0xf1223344, not yet confirmed +Modifying MS object, TLLI = 0xf1223344, TA 0 -> 7 +Change control TS to 7 until assinment is complete. +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS)s start Packet Uplink Assignment (PACCH) ++++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++ +------------------------- TX : Packet Uplink Assignment ------------------------- +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS): Scheduling polling at FN 2654283 TS 7 +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS) changes state from ASSIGN to WAIT ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Scheduled UL Assignment polling on FN=2654283, TS=7 +Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) (TRX=0, TS=7) +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654270 block=8 data=4f 28 5e 24 46 68 90 f8 0a 39 00 00 88 00 08 2b 2b 2b 2b 2b 2b 2b 2b +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Packet Control Ack +TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) changes state from WAIT ASSIGN to FLOW +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=0 .. V(R)=0) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got CS-1 RLC data block: CV=15, BSN=0, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 0 storing in window (0..63) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 1 +- Taking block 0 out, raising V(Q) to 1 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=0 CV=15 +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1d 08 40 c1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=0, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=1) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=1, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 1 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 2 +- Taking block 1 out, raising V(Q) to 2 +- Assembling frames: (len=37) +-- Frame 1 starts at offset 0, length=37, is_complete=0 +- No gaps in received block, last block: BSN=1 CV=7 +Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) + - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 2, BOW, EOW +Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1d 20 40 c1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=0, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=2 .. V(R)=2) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=4, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 4 storing in window (2..65) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 5 +Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) + - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 5, BOW, EOW +Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got 'TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS)', TA=7 +Got MS: TLLI = 0xf1223344, TA = 7 +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=1/1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign downlink TS=7 TFI=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0xf1223344, TBF = TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 80 +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +Modifying MS object, TLLI: 0xf1223344 confirmed +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) [DOWNLINK] START +Modifying MS object, TLLI = 0xf1223344, IMSI '' -> '0011223344' +Send dowlink assignment on PACCH, because TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) exists +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) starting timer 0. +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) append diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..6b99857 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,5 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_puan_issue === +=== end test_tbf_puan_issue === -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 3 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Mon Aug 22 07:37:52 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Mon, 22 Aug 2016 07:37:52 +0000 Subject: [PATCH] osmo-pcu[master]: Describe the issue with EGPRS PUAN encoding In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/702 to look at the new patch set (#4). Describe the issue with EGPRS PUAN encoding Currently pcu doesn?t encode EGPRS PUAN message for VQ not equal to VR case. This patch describe the issue with initially sending the BSN 1 which generated the PUAN message as below 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b. Later Unit test frame work sends BSN 4 and PUAN generated is below 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b which is same as previous PUAN message. Please see the Generated test file. This is considerable issue with OTA. The assert in the test file needs to be corrected. Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 --- M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 3 files changed, 298 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/02/702/4 diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..d867331 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -618,6 +618,143 @@ &ulreq, tbf->poll_fn); } +static gprs_rlcmac_ul_tbf *puan_issue(BTS *the_bts, + uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, + uint8_t ms_class, uint8_t egprs_ms_class) +{ + GprsMs *ms; + uint32_t rach_fn = *fn - 51; + uint32_t sba_fn = *fn + 52; + uint8_t trx_no = 0; + int tfi = 0, i = 0; + gprs_rlcmac_ul_tbf *ul_tbf; + struct gprs_rlcmac_pdch *pdch; + gprs_rlcmac_bts *bts; + RlcMacUplink_t ulreq = {0}; + struct pcu_l1_meas meas; + struct gprs_rlc_ul_header_egprs_3 *egprs3 = NULL; + GprsCodingScheme cs; + + meas.set_rssi(31); + bts = the_bts->bts_data(); + + /* needed to set last_rts_fn in the PDCH object */ + request_dl_rlc_block(bts, trx_no, ts_no, fn); + + /* + * simulate RACH, this sends an Immediate + * Assignment Uplink on the AGCH + */ + the_bts->rcv_rach(0x73, rach_fn, qta); + + /* get next free TFI */ + tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1); + + /* fake a resource request */ + ulreq.u.MESSAGE_TYPE = MT_PACKET_RESOURCE_REQUEST; + ulreq.u.Packet_Resource_Request.PayloadType = GPRS_RLCMAC_CONTROL_BLOCK; + ulreq.u.Packet_Resource_Request.ID.UnionType = 1; /* != 0 */ + ulreq.u.Packet_Resource_Request.ID.u.TLLI = tlli; + ulreq.u.Packet_Resource_Request.Exist_MS_Radio_Access_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + Count_MS_RA_capability_value = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Exist_Multislot_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + Exist_GPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + GPRS_multislot_class = ms_class; + if (egprs_ms_class) { + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Multislot_capability.Exist_EGPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Multislot_capability.EGPRS_multislot_class = ms_class; + } + + send_ul_mac_block(the_bts, trx_no, ts_no, &ulreq, sba_fn); + + /* check the TBF */ + ul_tbf = the_bts->ul_tbf_by_tfi(tfi, trx_no, ts_no); + OSMO_ASSERT(ul_tbf != NULL); + OSMO_ASSERT(ul_tbf->ta() == qta / 4); + + /* send packet uplink assignment */ + *fn = sba_fn; + request_dl_rlc_block(ul_tbf, fn); + + /* send real acknowledgement */ + send_control_ack(ul_tbf); + + check_tbf(ul_tbf); + /* send fake data */ + uint8_t data_msg[42] = { + 0xf << 2, /* GPRS_RLCMAC_DATA_BLOCK << 6, CV = 15 */ + tfi << 1, + 1, /* BSN:7, E:1 */ + }; + + pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no]; + pdch->rcv_block(&data_msg[0], 23, *fn, &meas); + + ms = the_bts->ms_by_tlli(tlli); + OSMO_ASSERT(ms != NULL); + OSMO_ASSERT(ms->ta() == qta/4); + OSMO_ASSERT(ms->ul_tbf() == ul_tbf); + + /* + * TS 44.060, B.8.1 + * first seg received first, later second seg + */ + cs = GprsCodingScheme::MCS3; + egprs3 = (struct gprs_rlc_ul_header_egprs_3 *) data_msg; + egprs3->si = 0; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 1; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 0; + egprs3->pi = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + struct msgb *msg1 = ul_tbf->create_ul_ack(*fn, ts_no); + + egprs3->si = 0; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 4; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + struct msgb *msg2 = ul_tbf->create_ul_ack(*fn, ts_no); + + /* TODO: Need to modify the assert */ + OSMO_ASSERT(!memcmp(msg2->data, msg1->data, msg1->data_len)); + + return ul_tbf; +} + static gprs_rlcmac_ul_tbf *establish_ul_tbf_two_phase_spb(BTS *the_bts, uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, uint8_t ms_class, uint8_t egprs_ms_class) @@ -1631,6 +1768,41 @@ gprs_bssgp_destroy(); } +static void test_tbf_puan_issue(void) +{ + BTS the_bts; + int ts_no = 7; + uint32_t fn = 2654218; + uint16_t qta = 31; + uint32_t tlli = 0xf1223344; + const char *imsi = "0011223344"; + uint8_t ms_class = 1; + uint8_t egprs_ms_class = 1; + gprs_rlcmac_ul_tbf *ul_tbf; + GprsMs *ms; + uint8_t test_data[256]; + + printf("=== start %s ===\n", __func__); + + memset(test_data, 1, sizeof(test_data)); + + setup_bts(&the_bts, ts_no, 4); + the_bts.bts_data()->initial_mcs_dl = 9; + the_bts.bts_data()->egprs_enabled = 1; + + ul_tbf = puan_issue(&the_bts, ts_no, tlli, &fn, qta, + ms_class, egprs_ms_class); + + ms = ul_tbf->ms(); + fprintf(stderr, "Got '%s', TA=%d\n", ul_tbf->name(), ul_tbf->ta()); + fprintf(stderr, + "Got MS: TLLI = 0x%08x, TA = %d\n", ms->tlli(), ms->ta()); + + send_dl_data(&the_bts, tlli, imsi, test_data, sizeof(test_data)); + + printf("=== end %s ===\n", __func__); +} + static void test_tbf_egprs_two_phase_spb(void) { BTS the_bts; @@ -2071,6 +2243,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_puan_issue(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..aa8a087 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -5780,3 +5780,126 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654218 block=8 data=47 94 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +MS requests UL TBF on RACH, so we provide one: +MS requests single block allocation +RX: [PCU <- BTS] RACH qbit-ta=31 ra=0x73, Fn=2654167 (17,25,9), SBFn=2654270 +TX: Immediate Assignment Uplink (AGCH) + - TRX=0 (0) TS=7 TA=7 TSC=0 TFI=-1 USF=7 +Sending data request: trx=0 ts=0 sapi=2 arfcn=0 fn=0 block=0 data=2d 06 3f 10 0f 00 00 73 8b 29 07 00 c0 0c 5a 43 2b 2b 2b 2b 2b 2b 2b +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +MS requests UL TBF in packet resource request of single block, so we provide one: +MS supports EGPRS multislot class 1. +********** TBF starts here ********** +Allocating UL TBF: MS_CLASS=1/1 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 1 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 1 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign uplink TS=7 TFI=0 USF=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 00 +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=ASSIGN EGPRS) starting timer 3169. +Modifying MS object, UL TLLI: 0x00000000 -> 0xf1223344, not yet confirmed +Modifying MS object, TLLI = 0xf1223344, TA 0 -> 7 +Change control TS to 7 until assinment is complete. +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS)s start Packet Uplink Assignment (PACCH) ++++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++ +------------------------- TX : Packet Uplink Assignment ------------------------- +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS): Scheduling polling at FN 2654283 TS 7 +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS) changes state from ASSIGN to WAIT ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Scheduled UL Assignment polling on FN=2654283, TS=7 +Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) (TRX=0, TS=7) +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654270 block=8 data=4f 28 5e 24 46 68 90 f8 0a 39 00 00 88 00 08 2b 2b 2b 2b 2b 2b 2b 2b +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Packet Control Ack +TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) changes state from WAIT ASSIGN to FLOW +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=0 .. V(R)=0) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got CS-1 RLC data block: CV=15, BSN=0, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 0 storing in window (0..63) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 1 +- Taking block 0 out, raising V(Q) to 1 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=0 CV=15 +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1d 08 40 c1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=0, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=1) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=1, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 1 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 2 +- Taking block 1 out, raising V(Q) to 2 +- Assembling frames: (len=37) +-- Frame 1 starts at offset 0, length=37, is_complete=0 +- No gaps in received block, last block: BSN=1 CV=7 +Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) + - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 2, BOW, EOW +Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1d 20 40 c1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=0, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=2 .. V(R)=2) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=4, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 4 storing in window (2..65) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 5 +Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) + - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 5, BOW, EOW +Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got 'TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS)', TA=7 +Got MS: TLLI = 0xf1223344, TA = 7 +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=1/1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign downlink TS=7 TFI=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0xf1223344, TBF = TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 80 +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +Modifying MS object, TLLI: 0xf1223344 confirmed +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) [DOWNLINK] START +Modifying MS object, TLLI = 0xf1223344, IMSI '' -> '0011223344' +Send dowlink assignment on PACCH, because TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) exists +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) starting timer 0. +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) append diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..6b99857 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,5 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_puan_issue === +=== end test_tbf_puan_issue === -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 4 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Mon Aug 22 07:54:17 2016 From: gerrit-no-reply at lists.osmocom.org (pravin) Date: Mon, 22 Aug 2016 07:54:17 +0000 Subject: osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Patch Set 18: (2 comments) https://gerrit.osmocom.org/#/c/416/18/src/egprs_rlc_compression.h File src/egprs_rlc_compression.h: Line 27: extern void *tall_pcu_ctx; > not needed. If I dont declare tall_pcu_ctx as an extern I'm not able to use it in a file egprs_rlc_compression.cpp. https://gerrit.osmocom.org/#/c/416/18/tests/Makefile.am File tests/Makefile.am: Line 38: -Wl,-u,bssgp_prim_cb > Still.. the tree code doesn't depend on GB, GSM, etc.. drop that.. drop the If I remove GB and GSM . I am not able to use LOGP. I am getting error "undefined reference to `install_element', `vty_install_default', `install_node', `logging_vty_add_cmds', `vty_out',`vty_out_rate_ctr_group', 'bssgp_nsi', `gprs_ns_destroy' " while compiling. -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 18 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: pravin Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Mon Aug 22 08:18:02 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Mon, 22 Aug 2016 08:18:02 +0000 Subject: [ABANDON] openbsc[master]: Added slhc.h to Makefile.am In-Reply-To: References: Message-ID: dexter has abandoned this change. Change subject: Added slhc.h to Makefile.am ...................................................................... Abandoned -- To view, visit https://gerrit.osmocom.org/637 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: abandon Gerrit-Change-Id: Ib28596ba5633ae1e9301fd81ed1dbf7236a8805d Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 22 08:31:00 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Mon, 22 Aug 2016 08:31:00 +0000 Subject: [PATCH] openbsc[master]: Adding compression control and final fixups In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/642 to look at the new patch set (#22). Adding compression control and final fixups - Add module to handle compression entities - Add module to control header compression - Introduce VTY commands for heade compression configuration - Add changes in sndcp and llc to integrate header compression Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 --- M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/gprs_llc.h M openbsc/include/openbsc/gprs_sndcp.h A openbsc/include/openbsc/gprs_sndcp_comp.h A openbsc/include/openbsc/gprs_sndcp_pcomp.h M openbsc/include/openbsc/sgsn.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/gprs_llc.c M openbsc/src/gprs/gprs_sndcp.c A openbsc/src/gprs/gprs_sndcp_comp.c A openbsc/src/gprs/gprs_sndcp_pcomp.c M openbsc/src/gprs/sgsn_libgtp.c M openbsc/src/gprs/sgsn_vty.c M openbsc/tests/sgsn/Makefile.am 14 files changed, 1,342 insertions(+), 34 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/42/642/22 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index f402fea..88a7e2c 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,7 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ - slhc.h + slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h index c3b82b1..4cd6c2e 100644 --- a/openbsc/include/openbsc/gprs_llc.h +++ b/openbsc/include/openbsc/gprs_llc.h @@ -174,6 +174,15 @@ * able to create the compression entity. */ struct llist_head *xid; + /* Compression entities */ + struct { + /* In this two list_heads we will store the + * data and protocol compression entities, + * together with their compression states */ + struct llist_head *proto; + struct llist_head *data; + } comp; + /* Internal management */ uint32_t age_timestamp; }; diff --git a/openbsc/include/openbsc/gprs_sndcp.h b/openbsc/include/openbsc/gprs_sndcp.h index fef871a..cd6ee4e 100644 --- a/openbsc/include/openbsc/gprs_sndcp.h +++ b/openbsc/include/openbsc/gprs_sndcp.h @@ -21,6 +21,16 @@ struct llist_head frag_list; struct osmo_timer_list timer; + + /* Holds state to know which compression mode is used + * when the packet is re-assembled */ + uint8_t pcomp; + uint8_t dcomp; + + /* Holds the pointers to the compression entity list + * that is used when the re-assembled packet is decompressed */ + struct llist_head *proto; + struct llist_head *data; }; /* See 6.7.1.2 Reassembly */ @@ -50,4 +60,20 @@ extern struct llist_head gprs_sndcp_entities; +/* Set of SNDCP-XID negotiation (See also: TS 144 065, + * Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_req(struct gprs_llc_lle *lle, uint8_t nsapi); + +/* Process SNDCP-XID indication (See also: TS 144 065, + * Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_ind(struct gprs_llc_xid_field *xid_field_indication, + struct gprs_llc_xid_field *xid_field_response, + struct gprs_llc_lle *lle); + +/* Process SNDCP-XID indication + * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_conf(struct gprs_llc_xid_field *xid_field_confirmation, + struct gprs_llc_xid_field *xid_field_request, + struct gprs_llc_lle *lle); + #endif /* INT_SNDCP_H */ diff --git a/openbsc/include/openbsc/gprs_sndcp_comp.h b/openbsc/include/openbsc/gprs_sndcp_comp.h new file mode 100644 index 0000000..69441fb --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_comp.h @@ -0,0 +1,84 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +/* Header / Data compression entity */ +struct gprs_sndcp_comp { + struct llist_head list; + + /* Serves as an ID in case we want to delete this entity later */ + unsigned int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + + /* Specifies to which NSAPIs the compression entity is assigned */ + uint8_t nsapi_len; /* Number of applicable NSAPIs (default 0) */ + uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */ + + /* Assigned pcomp values */ + uint8_t comp_len; /* Number of contained PCOMP / DCOMP values */ + uint8_t comp[MAX_COMP]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */ + + /* Algorithm parameters */ + int algo; /* Algorithm type (see gprs_sndcp_xid.h) */ + int compclass; /* See gprs_sndcp_xid.h/c */ + void *state; /* Algorithm status and parameters */ +}; + +#define MAX_COMP 16 /* Maximum number of possible pcomp/dcomp values */ +#define MAX_NSAPI 11 /* Maximum number usable NSAPIs */ + +/* Allocate a compression enitiy list */ +struct llist_head *gprs_sndcp_comp_alloc(const void *ctx); + +/* Free a compression entitiy list */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities); + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, unsigned int entity); + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_entities_add(const void *ctx, struct + llist_head *comp_entities, + const struct + gprs_sndcp_comp_field + *comp_field); + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head + *comp_entities, uint8_t comp); + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head + *comp_entities, uint8_t nsapi); + +/* Find a comp_index for a given pcomp/dcomp value */ +int gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp *comp_entity, + int comp); + +/* Find a pcomp/dcomp value for a given comp_index */ +int gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp *comp_entity, + int comp_index); + diff --git a/openbsc/include/openbsc/gprs_sndcp_pcomp.h b/openbsc/include/openbsc/gprs_sndcp_pcomp.h new file mode 100644 index 0000000..2528a86 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_pcomp.h @@ -0,0 +1,44 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field); + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity); + +/* Expand packet header */ +int gprs_sndcp_pcomp_expand(uint8_t *data_o, uint8_t *data_i, unsigned int len, + uint8_t pcomp, + const struct llist_head *comp_entities); + +/* Compress packet header */ +int gprs_sndcp_pcomp_compress(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t *pcomp, + const struct llist_head *comp_entities, + int nsapi); diff --git a/openbsc/include/openbsc/sgsn.h b/openbsc/include/openbsc/sgsn.h index 59126fe..acd3e4b 100644 --- a/openbsc/include/openbsc/sgsn.h +++ b/openbsc/include/openbsc/sgsn.h @@ -89,6 +89,12 @@ int dynamic_lookup; struct oap_config oap; + + /* RFC1144 TCP/IP Header compression */ + struct { + int enabled; + int s01; + } pcomp_rfc1144; }; struct sgsn_instance { diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 245636b..2910c02 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -27,7 +27,7 @@ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ - slhc.c + slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c index 79795d6..34b7afe 100644 --- a/openbsc/src/gprs/gprs_llc.c +++ b/openbsc/src/gprs/gprs_llc.c @@ -39,6 +39,7 @@ #include #include #include +#include #include static struct gprs_llc_llme *llme_alloc(uint32_t tlli); @@ -88,7 +89,9 @@ llist_add(&l3_xid_field->list, &xid_fields); } - llme->xid = gprs_llc_copy_xid(llme->xid, &xid_fields); + /* Store generated XID for later reference */ + talloc_free(llme->xid); + llme->xid = gprs_llc_copy_xid(llme, &xid_fields); return gprs_llc_compile_xid(bytes, bytes_len, &xid_fields); } @@ -120,7 +123,9 @@ llist_add(&xid_iovui.list, &xid_fields); llist_add(&xid_reset.list, &xid_fields); - llme->xid = gprs_llc_copy_xid(llme->xid, &xid_fields); + /* Store generated XID for later reference */ + talloc_free(llme->xid); + llme->xid = gprs_llc_copy_xid(llme, &xid_fields); return gprs_llc_compile_xid(bytes, bytes_len, &xid_fields); } @@ -135,6 +140,16 @@ struct llist_head *xid_fields; struct gprs_llc_xid_field *xid_field; + struct gprs_llc_xid_field *xid_field_request; + struct gprs_llc_xid_field *xid_field_request_l3 = NULL; + + /* Pick layer3 XID from the XID request we have sent last */ + if (lle->llme->xid) { + llist_for_each_entry(xid_field_request, lle->llme->xid, list) { + if (xid_field_request->type == GPRS_LLC_XID_T_L3_PAR) + xid_field_request_l3 = xid_field_request; + } + } /* Parse and analyze XID-Response */ xid_fields = gprs_llc_parse_xid(NULL, bytes, bytes_len); @@ -145,11 +160,10 @@ llist_for_each_entry(xid_field, xid_fields, list) { /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ - if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { - LOGP(DLLC, LOGL_NOTICE, - "Ignoring SNDCP-XID-Field: XID: type=%i, data_len=%i, data=%s\n", - xid_field->type, xid_field->data_len, - xid_field->data); + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR && + xid_field_request_l3) { + sndcp_sn_xid_conf(xid_field, + xid_field_request_l3, lle); } /* Process LLC-XID fields: */ @@ -163,9 +177,10 @@ * inquiry. There is a remainig risk of * malfunction! */ LOGP(DLLC, LOGL_NOTICE, - "Ignoring XID-Field: XID: type=%i, data_len=%i, data=%s\n", + "Ignoring XID-Field: XID: type=%d, data_len=%d, data=%s\n", xid_field->type, xid_field->data_len, - xid_field->data); + osmo_hexdump_nospc(xid_field->data, + xid_field->data_len)); } } talloc_free(xid_fields); @@ -197,10 +212,6 @@ struct gprs_llc_xid_field *xid_field; struct gprs_llc_xid_field *xid_field_response; - /* Flush eventually pending XID fields */ - talloc_free(lle->llme->xid); - lle->llme->xid = NULL; - /* Parse and analyze XID-Request */ xid_fields = gprs_llc_parse_xid(lle->llme, bytes_request, bytes_request_len); @@ -220,7 +231,7 @@ * when a phone submits values which defer from * the default! */ LOGP(DLLC, LOGL_NOTICE, - "Echoing XID-Field: XID: type=%i, data_len=%i, data=%s\n", + "Echoing XID-Field: XID: type=%d, data_len=%d, data=%s\n", xid_field->type, xid_field->data_len, osmo_hexdump_nospc(xid_field->data, xid_field->data_len)); @@ -229,6 +240,23 @@ (lle->llme, xid_field); llist_add(&xid_field_response->list, xid_fields_response); + } + } + + /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ + llist_for_each_entry(xid_field, xid_fields, list) { + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { + + xid_field_response = + talloc_zero(lle->llme, + struct gprs_llc_xid_field); + rc = sndcp_sn_xid_ind(xid_field, + xid_field_response, lle); + if (rc == 0) + llist_add(&xid_field_response->list, + xid_fields_response); + else + talloc_free(xid_field_response); } } @@ -518,11 +546,16 @@ llist_add(&llme->list, &gprs_llc_llmes); + llme->comp.proto = gprs_sndcp_comp_alloc(llme); + llme->comp.data = gprs_sndcp_comp_alloc(llme); + return llme; } static void llme_free(struct gprs_llc_llme *llme) { + gprs_sndcp_comp_free(llme->comp.proto); + gprs_sndcp_comp_free(llme->comp.data); talloc_free(llme->xid); llist_del(&llme->list); talloc_free(llme); diff --git a/openbsc/src/gprs/gprs_sndcp.c b/openbsc/src/gprs/gprs_sndcp.c index 4f71121..9a6d89a 100644 --- a/openbsc/src/gprs/gprs_sndcp.c +++ b/openbsc/src/gprs/gprs_sndcp.c @@ -35,6 +35,59 @@ #include #include #include +#include +#include +#include +#include + +#define DEBUG_IP_PACKETS 0 /* 0=Disabled, 1=Enabled */ + +#if DEBUG_IP_PACKETS == 1 +/* Show some ip packet details */ +static void debug_ip_packet(uint8_t *data, int len, int dir, char *info) +{ + uint8_t tcp_flags; + char flags_debugmsg[256]; + int len_short; + + if(len > 90) + len_short = 90; + else + len_short = len; + + if (dir) + DEBUGP(DSNDCP,"%s: PHONE => NETWORK: %s\n", info, + osmo_hexdump_nospc(data, len_short)); + else + DEBUGP(DSNDCP,"%s: PHONE <= NETWORK: %s\n", info, + osmo_hexdump_nospc(data, len_short)); + + DEBUGP(DSNDCP,"%s: length: %d\n", info, len); + if (data[9] == 0x06) { + DEBUGP(DSNDCP,"%s: Protocol type: TCP\n", info); + tcp_flags = data[33]; + + memset(flags_debugmsg,0,sizeof(flags_debugmsg)); + if (tcp_flags & 1) + strcat(flags_debugmsg,"FIN "); + if (tcp_flags & 2) + strcat(flags_debugmsg,"SYN "); + if (tcp_flags & 4) + strcat(flags_debugmsg,"RST "); + if (tcp_flags & 8) + strcat(flags_debugmsg,"PSH "); + if (tcp_flags & 16) + strcat(flags_debugmsg,"ACK "); + if (tcp_flags & 32) + strcat(flags_debugmsg,"URG "); + DEBUGP(DSNDCP,"%s: FLAGS: %s\n", info, flags_debugmsg); + } else if (data[9] == 0x11) { + DEBUGP(DSNDCP,"%s: Protocol type: UDP\n", info); + } else { + DEBUGP(DSNDCP,"%s: Protocol type: (%02x)\n", info, data[9]); + } +} +#endif /* Chapter 7.2: SN-PDU Formats */ struct sndcp_common_hdr { @@ -143,6 +196,9 @@ struct msgb *msg; unsigned int seg_nr; uint8_t *npdu; + int npdu_len; + int rc; + uint8_t *expnd; LOGP(DSNDCP, LOGL_DEBUG, "TLLI=0x%08x NSAPI=%u: Defragment output PDU %u " "num_seg=%u tot_len=%u\n", sne->lle->llme->tlli, sne->nsapi, @@ -173,16 +229,46 @@ talloc_free(dqe); } + npdu_len = sne->defrag.tot_len; + /* FIXME: cancel timer */ /* actually send the N-PDU to the SGSN core code, which then * hands it off to the correct GTP tunnel + GGSN via gtp_data_req() */ - return sgsn_rx_sndcp_ud_ind(&sne->ra_id, sne->lle->llme->tlli, - sne->nsapi, msg, sne->defrag.tot_len, npdu); + + /* Decompress packet */ +#if DEBUG_IP_PACKETS == 1 + DEBUGP(DSNDCP," \n"); + DEBUGP(DSNDCP,"::::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP,"====================================================\n"); + debug_ip_packet(npdu, npdu_len,1,"defrag_segments()"); +#endif + expnd = talloc_zero_size(msg,msg->len + 64); + rc = gprs_sndcp_pcomp_expand(expnd, npdu, npdu_len, + sne->defrag.pcomp, sne->defrag.proto); + if (rc < 0) { + talloc_free(expnd); + return -EIO; + } + else + npdu_len = rc; +#if DEBUG_IP_PACKETS == 1 + debug_ip_packet(expnd, npdu_len,1,"defrag_segments()"); + DEBUGP(DSNDCP,"====================================================\n"); + DEBUGP(DSNDCP,"::::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP," \n"); +#endif + + /* Hand off packet to gtp */ + rc = sgsn_rx_sndcp_ud_ind(&sne->ra_id, sne->lle->llme->tlli, + sne->nsapi, msg, npdu_len, expnd); + + talloc_free(expnd); + return rc; } -static int defrag_input(struct gprs_sndcp_entity *sne, struct msgb *msg, uint8_t *hdr, - unsigned int len) +static int defrag_input(struct gprs_sndcp_entity *sne, struct msgb *msg, + uint8_t *hdr, unsigned int len) { struct sndcp_common_hdr *sch; struct sndcp_udata_hdr *suh; @@ -343,7 +429,8 @@ }; /* returns '1' if there are more fragments to send, '0' if none */ -static int sndcp_send_ud_frag(struct sndcp_frag_state *fs) +static int sndcp_send_ud_frag(struct sndcp_frag_state *fs, + uint8_t pcomp, uint8_t dcomp) { struct gprs_sndcp_entity *sne = fs->sne; struct gprs_llc_lle *lle = sne->lle; @@ -380,8 +467,8 @@ if (sch->first) { scomph = (struct sndcp_comp_hdr *) msgb_put(fmsg, sizeof(*scomph)); - scomph->pcomp = 0; - scomph->dcomp = 0; + scomph->pcomp = pcomp; + scomph->dcomp = dcomp; } /* append the user-data header */ @@ -446,8 +533,38 @@ struct sndcp_comp_hdr *scomph; struct sndcp_udata_hdr *suh; struct sndcp_frag_state fs; + uint8_t pcomp = 0; + uint8_t dcomp = 0; + int rc; + uint8_t *compr; /* Identifiers from UP: (TLLI, SAPI) + (BVCI, NSEI) */ + + /* Compress packet */ +#if DEBUG_IP_PACKETS == 1 + DEBUGP(DSNDCP," \n"); + DEBUGP(DSNDCP,"::::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP,"====================================================\n"); + debug_ip_packet(msg->data, msg->len,0,"sndcp_initdata_req()"); +#endif + compr = talloc_zero_size(msg, msg->len); + rc = gprs_sndcp_pcomp_compress(compr,msg->data, msg->len, &pcomp, + lle->llme->comp.proto, nsapi); + if (rc < 0) { + talloc_free(compr); + return -EIO; + } + else { + msg->len = rc; + memcpy(msg->data,compr,rc); + } + talloc_free(compr); +#if DEBUG_IP_PACKETS == 1 + debug_ip_packet(msg->data, msg->len,0,"sndcp_initdata_req()"); + DEBUGP(DSNDCP,"====================================================\n"); + DEBUGP(DSNDCP,"::::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP," \n"); +#endif sne = gprs_sndcp_entity_by_lle(lle, nsapi); if (!sne) { @@ -469,7 +586,7 @@ /* call function to generate and send fragments until all * of the N-PDU has been sent */ while (1) { - int rc = sndcp_send_ud_frag(&fs); + int rc = sndcp_send_ud_frag(&fs,pcomp,dcomp); if (rc == 0) return 0; if (rc < 0) @@ -489,8 +606,8 @@ sne->tx_npdu_nr = (sne->tx_npdu_nr + 1) % 0xfff; scomph = (struct sndcp_comp_hdr *) msgb_push(msg, sizeof(*scomph)); - scomph->pcomp = 0; - scomph->dcomp = 0; + scomph->pcomp = pcomp; + scomph->dcomp = dcomp; /* prepend common SNDCP header */ sch = (struct sndcp_common_hdr *) msgb_push(msg, sizeof(*sch)); @@ -512,6 +629,8 @@ uint8_t *npdu; uint16_t npdu_num __attribute__((unused)); int npdu_len; + int rc; + uint8_t *expnd; sch = (struct sndcp_common_hdr *) hdr; if (sch->first) { @@ -540,26 +659,58 @@ /* FIXME: move this RA_ID up to the LLME or even higher */ bssgp_parse_cell_id(&sne->ra_id, msgb_bcid(msg)); + if(scomph) { + sne->defrag.pcomp = scomph->pcomp; + sne->defrag.dcomp = scomph->dcomp; + sne->defrag.proto = lle->llme->comp.proto; + sne->defrag.data = lle->llme->comp.data; + } + /* any non-first segment is by definition something to defragment * as is any segment that tells us there are more segments */ if (!sch->first || sch->more) return defrag_input(sne, msg, hdr, len); - if (scomph && (scomph->pcomp || scomph->dcomp)) { - LOGP(DSNDCP, LOGL_ERROR, "We don't support compression yet\n"); - return -EIO; - } - npdu_num = (suh->npdu_high << 8) | suh->npdu_low; npdu = (uint8_t *)suh + sizeof(*suh); - npdu_len = (msg->data + msg->len) - npdu; + npdu_len = (msg->data + msg->len) - npdu - 3; /* -3 'removes' the FCS */ + if (npdu_len <= 0) { LOGP(DSNDCP, LOGL_ERROR, "Short SNDCP N-PDU: %d\n", npdu_len); return -EIO; } /* actually send the N-PDU to the SGSN core code, which then * hands it off to the correct GTP tunnel + GGSN via gtp_data_req() */ - return sgsn_rx_sndcp_ud_ind(&sne->ra_id, lle->llme->tlli, sne->nsapi, msg, npdu_len, npdu); + + /* Decompress packet */ +#if DEBUG_IP_PACKETS == 1 + DEBUGP(DSNDCP," \n"); + DEBUGP(DSNDCP,"::::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP,"====================================================\n"); + debug_ip_packet(npdu, npdu_len,1,"sndcp_llunitdata_ind()"); +#endif + expnd = talloc_zero_size(msg,npdu_len + 64); + rc = gprs_sndcp_pcomp_expand(expnd, npdu, npdu_len, + sne->defrag.pcomp, sne->defrag.proto); + if (rc < 0) { + talloc_free(expnd); + return -EIO; + } + else + npdu_len = rc; +#if DEBUG_IP_PACKETS == 1 + debug_ip_packet(expnd, npdu_len,1,"sndcp_llunitdata_ind()"); + DEBUGP(DSNDCP,"====================================================\n"); + DEBUGP(DSNDCP,"::::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP," \n"); +#endif + + /* Hand off packet to gtp */ + rc = sgsn_rx_sndcp_ud_ind(&sne->ra_id, lle->llme->tlli, + sne->nsapi, msg, npdu_len, expnd); + + talloc_free(expnd); + return rc; } #if 0 @@ -619,3 +770,328 @@ case LL_STATUS_IND: } #endif + +/* Generate SNDCP-XID message */ +static int gprs_llc_generate_sndcp_xid(uint8_t *bytes, int bytes_len, + uint8_t nsapi) +{ + LLIST_HEAD(comp_fields); + struct gprs_sndcp_pcomp_rfc1144_params rfc1144_params; + struct gprs_sndcp_comp_field rfc1144_comp_field; + + memset(&rfc1144_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + + /* Setup which NSAPIs shall make use of rfc1144 */ + rfc1144_params.nsapi[0] = nsapi; + rfc1144_params.nsapi_len = 1; + + /* Setup rfc1144 operating parameters */ + rfc1144_params.s01 = sgsn->cfg.pcomp_rfc1144.s01; + + /* Setup rfc1144 compression field */ + rfc1144_comp_field.p = 1; + rfc1144_comp_field.entity = 0; + rfc1144_comp_field.algo = RFC_1144; + rfc1144_comp_field.comp[RFC1144_PCOMP1] = 1; + rfc1144_comp_field.comp[RFC1144_PCOMP2] = 2; + rfc1144_comp_field.comp_len = RFC1144_PCOMP_NUM; + rfc1144_comp_field.rfc1144_params = &rfc1144_params; + + /* Add compression field(s) to list */ + if (sgsn->cfg.pcomp_rfc1144.enabled) + llist_add(&rfc1144_comp_field.list, &comp_fields); + + /* Comile bytestream */ + return gprs_sndcp_compile_xid(bytes, bytes_len, &comp_fields); +} + +/* Set of SNDCP-XID bnegotiation (See also: TS 144 065, + * Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_req(struct gprs_llc_lle *lle, uint8_t nsapi) +{ + /* Note: The specification requires the SNDCP-User to set of an + * SNDCP xid request. See also 3GPP TS 44.065, 6.8 XID parameter + * negotiation, Figure 11: SNDCP XID negotiation procedure. In + * our case the SNDCP-User is sgsn_libgtp.c, which calls + * sndcp_sn_xid_req directly. */ + + uint8_t l3params_bytes[1024]; + int sndcp_xid_bytes_len; + struct gprs_llc_xid_field xid_field_request; + + /* Generate compression parameter bytestream */ + sndcp_xid_bytes_len = gprs_llc_generate_sndcp_xid(l3params_bytes, + sizeof + (l3params_bytes), + nsapi); + + /* Send XID with the SNDCP-XID bytetsream included */ + if (sndcp_xid_bytes_len > 0) { + xid_field_request.type = GPRS_LLC_XID_T_L3_PAR; + xid_field_request.data = l3params_bytes; + xid_field_request.data_len = sndcp_xid_bytes_len; + return gprs_ll_xid_req(lle, &xid_field_request); + } + + /* When bytestream can not be generated, proceed without SNDCP-XID */ + else { + return gprs_ll_xid_req(lle, NULL); + } +} + +/* Hanle header compression entites */ +static int handle_pcomp_entities(struct gprs_sndcp_comp_field *comp_field, + struct gprs_llc_lle *lle) +{ + /* Note: This functions also transforms the comp_field into its + * echo form (strips comp values, resets propose bit etc...) + * the processed comp_fields can then be sent back as XID- + * Response without further modification. */ + + /* Delete propose bit */ + comp_field->p = 0; + + /* Process proposed parameters */ + switch (comp_field->algo) { + case RFC_1144: + if (sgsn->cfg.pcomp_rfc1144.enabled && + comp_field->rfc1144_params->nsapi_len > 0) { + LOGP(DSNDCP, LOGL_DEBUG, + "Accepting RFC1144 header conpression...\n"); + gprs_sndcp_comp_entities_add(lle->llme, + lle->llme->comp.proto, + comp_field); + } else { + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting RFC1144 header conpression...\n"); + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + comp_field->rfc1144_params->nsapi_len = 0; + } + break; + case RFC_2507: + /* RFC 2507 is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting RFC2507 header conpression...\n"); + comp_field->rfc2507_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + break; + case ROHC: + /* ROHC is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting ROHC header conpression...\n"); + comp_field->rohc_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + break; + } + + return 0; +} + +/* Hanle data compression entites */ +static int handle_dcomp_entities(struct gprs_sndcp_comp_field *comp_field, + struct gprs_llc_lle *lle) +{ + /* Note: This functions also transforms the comp_field into its + * echo form (strips comp values, resets propose bit etc...) + * the processed comp_fields can then be sent back as XID- + * Response without further modification. */ + + /* Delete propose bit */ + comp_field->p = 0; + + /* Process proposed parameters */ + switch (comp_field->algo) { + case V42BIS: + /* V42BIS is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting V42BIS data conpression...\n"); + comp_field->rfc2507_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + break; + case V44: + /* V44 is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, "Rejecting V44 data conpression...\n"); + comp_field->rohc_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + break; + } + + return 0; + +} + +/* Process SNDCP-XID indication + * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_ind(struct gprs_llc_xid_field *xid_field_indication, + struct gprs_llc_xid_field *xid_field_response, + struct gprs_llc_lle *lle) +{ + /* Note: This function computes the SNDCP-XID response that is sent + * back to the phone when a phone originated XID is received. The + * Input XID fields are directly processed and the result is directly + * handed back. */ + + int rc; + int compclass; + + struct llist_head *comp_fields; + struct gprs_sndcp_comp_field *comp_field; + + OSMO_ASSERT(xid_field_indication); + OSMO_ASSERT(xid_field_response); + OSMO_ASSERT(lle); + + /* Parse SNDCP-CID XID-Field */ + comp_fields = + gprs_sndcp_parse_xid(lle->llme, xid_field_indication->data, + xid_field_indication->data_len, NULL); + if (!comp_fields) + return -EINVAL; + + /* Don't bother with empty indications */ + if (llist_empty(comp_fields)) { + xid_field_response->data = NULL; + xid_field_response->data_len = 0; + DEBUGP(DSNDCP, + "SNDCP-XID indication did not contain any parameters!\n"); + return 0; + } + + /* Handle compression entites */ + DEBUGP(DSNDCP, "Unmodified SNDCP-XID received from the phone:\n"); + gprs_sndcp_dump_comp_fields(comp_fields, LOGL_DEBUG); + + llist_for_each_entry(comp_field, comp_fields, list) { + compclass = gprs_sndcp_get_compression_class(comp_field); + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + rc = handle_pcomp_entities(comp_field, lle); + else if (compclass == SNDCP_XID_DATA_COMPRESSION) + rc = handle_dcomp_entities(comp_field, lle); + else { + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + rc = 0; + } + + if (rc < 0) { + talloc_free(comp_fields); + return -EINVAL; + } + } + + DEBUGP(DSNDCP, + "Modified version of received SNDCP-XID to be sent back from the ggsn:\n"); + gprs_sndcp_dump_comp_fields(comp_fields, LOGL_DEBUG); + + /* Reserve some memory to store the modified SNDCP-XID bytes */ + xid_field_response->data = + talloc_zero_size(lle->llme, xid_field_indication->data_len); + + /* Set Type flag for response */ + xid_field_response->type = GPRS_LLC_XID_T_L3_PAR; + + /* Compile modified SNDCP-XID bytes */ + rc = gprs_sndcp_compile_xid(xid_field_response->data, + xid_field_indication->data_len, + comp_fields); + + if (rc > 0) + xid_field_response->data_len = rc; + else { + talloc_free(xid_field_response->data); + xid_field_response->data = NULL; + xid_field_response->data_len = 0; + return -EINVAL; + } + + talloc_free(comp_fields); + + return 0; +} + +/* Process SNDCP-XID indication + * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_conf(struct gprs_llc_xid_field *xid_field_confirmation, + struct gprs_llc_xid_field *xid_field_request, + struct gprs_llc_lle *lle) +{ + /* Note: This function handles an incomming SNDCP-XID confirmiation. + * Since the confirmation fields may lack important parameters we + * will reconstruct these missing fields using the original request + * we have sent. After that we will create (or delete) the + * compression entites */ + + struct llist_head *comp_fields_req; + struct llist_head *comp_fields_conf; + struct gprs_sndcp_comp_field *comp_field; + int rc; + int compclass; + + /* We need both, the confirmation that is sent back by the phone, + * and the original request we have sent. If one of this is missing + * we can not process the confirmation, the caller must check if + * request and confirmation fields are available. */ + OSMO_ASSERT(xid_field_confirmation); + OSMO_ASSERT(xid_field_request); + + /* Parse SNDCP-CID XID-Field */ + comp_fields_req = gprs_sndcp_parse_xid(lle->llme, + xid_field_request->data, + xid_field_request->data_len, + NULL); + if (!comp_fields_req) + return -EINVAL; + + DEBUGP(DSNDCP, "Unmodified SNDCP-XID sent from the ggsn:\n"); + gprs_sndcp_dump_comp_fields(comp_fields_req, LOGL_DEBUG); + + /* Parse SNDCP-CID XID-Field */ + comp_fields_conf = gprs_sndcp_parse_xid(lle->llme, + xid_field_confirmation->data, + xid_field_confirmation-> + data_len, comp_fields_req); + if (!comp_fields_conf) + return -EINVAL; + + DEBUGP(DSNDCP, + "Modified version of received SNDCP-XID received from the phone:\n"); + gprs_sndcp_dump_comp_fields(comp_fields_conf, LOGL_DEBUG); + + /* Handle compression entites */ + llist_for_each_entry(comp_field, comp_fields_conf, list) { + compclass = gprs_sndcp_get_compression_class(comp_field); + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + rc = handle_pcomp_entities(comp_field, lle); + else if (compclass == SNDCP_XID_DATA_COMPRESSION) + rc = handle_dcomp_entities(comp_field, lle); + else { + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + rc = 0; + } + + if (rc < 0) { + talloc_free(comp_fields_req); + talloc_free(comp_fields_conf); + return -EINVAL; + } + } + + talloc_free(comp_fields_req); + talloc_free(comp_fields_conf); + + return 0; +} diff --git a/openbsc/src/gprs/gprs_sndcp_comp.c b/openbsc/src/gprs/gprs_sndcp_comp.c new file mode 100644 index 0000000..19cd7b1 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_comp.c @@ -0,0 +1,319 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +/* Create a new compression entity from a XID-Field */ +static struct gprs_sndcp_comp *gprs_sndcp_comp_create(const void *ctx, + const struct + gprs_sndcp_comp_field + *comp_field) +{ + OSMO_ASSERT(comp_field); + + struct gprs_sndcp_comp *comp_entity; + comp_entity = talloc_zero(ctx, struct gprs_sndcp_comp); + + /* Copy relevant information from the SNDCP-XID field */ + comp_entity->entity = comp_field->entity; + comp_entity->comp_len = comp_field->comp_len; + memcpy(comp_entity->comp, comp_field->comp, sizeof(comp_entity->comp)); + + if (comp_field->rfc1144_params) { + comp_entity->nsapi_len = comp_field->rfc1144_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc1144_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->rfc2507_params) { + comp_entity->nsapi_len = comp_field->rfc2507_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc2507_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->rohc_params) { + comp_entity->nsapi_len = comp_field->rohc_params->nsapi_len; + memcpy(comp_entity->nsapi, comp_field->rohc_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->v42bis_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->v44_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + sizeof(comp_entity->nsapi)); + } else { + /* The caller is expected to check carefully if the all + * data fields required for compression entity creation + * are present. Otherwise we blow an assertion here */ + OSMO_ASSERT(false); + } + comp_entity->algo = comp_field->algo; + + /* Check if an NSAPI is selected, if not, it does not make sense + * to create the compression entity, since the caller should + * have checked the presence of the NSAPI, we blow an assertion + * in case of missing NSAPIs */ + OSMO_ASSERT(comp_entity->nsapi_len > 0) + + /* Determine of which class our compression entity will be + * (Protocol or Data compresson ?) */ + comp_entity->compclass = + gprs_sndcp_get_compression_class(comp_field); + OSMO_ASSERT(comp_entity->compclass != -1); + + /* Create an algorithm specific compression context */ + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + if (gprs_sndcp_pcomp_init(ctx, comp_entity, comp_field) != 0) { + talloc_free(comp_entity); + comp_entity = NULL; + } + } else { + LOGP(DSNDCP, LOGL_ERROR, + "We don't support data compression yet!\n"); + talloc_free(comp_entity); + return NULL; + } + + /* Display info message */ + if (comp_entity == NULL) { + LOGP(DSNDCP, LOGL_ERROR, + "Header compression entity (%d) creation failed!\n", + comp_entity->entity); + return NULL; + } + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "New header compression entity (%d) created.\n", + comp_entity->entity); + } else { + LOGP(DSNDCP, LOGL_INFO, + "New data compression entity (%d) created.\n", + comp_entity->entity); + } + + return comp_entity; +} + +/* Allocate a compression enitiy list */ +struct llist_head *gprs_sndcp_comp_alloc(const void *ctx) +{ + struct llist_head *lh; + + lh = talloc_zero(ctx, struct llist_head); + INIT_LLIST_HEAD(lh); + + return lh; +} + +/* Free a compression entitiy list */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities) +{ + struct gprs_sndcp_comp *comp_entity; + + /* We expect the caller to take care of allocating a + * compression entity list properly. Attempting to + * free a non existing list clearly points out + * a malfunction. */ + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + /* Free compression entity */ + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %d ...\n", + comp_entity->entity); + gprs_sndcp_pcomp_term(comp_entity); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %d ...\n", + comp_entity->entity); + } + } + + talloc_free(comp_entities); +} + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, + unsigned int entity) +{ + struct gprs_sndcp_comp *comp_entity; + struct gprs_sndcp_comp *comp_entity_to_delete = NULL; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) + comp_entity_to_delete = comp_entity; + } + + if (!comp_entity_to_delete) + return; + + if (comp_entity_to_delete->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %d ...\n", + comp_entity_to_delete->entity); + gprs_sndcp_pcomp_term(comp_entity_to_delete); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %d ...\n", + comp_entity_to_delete->entity); + } + + /* Delete compression entity */ + llist_del(&comp_entity_to_delete->list); + talloc_free(comp_entity_to_delete); +} + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_entities_add(const void *ctx, + struct llist_head + *comp_entities, + const struct + gprs_sndcp_comp_field + *comp_field) +{ + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(comp_entities); + OSMO_ASSERT(comp_field); + + /* Just to be sure, if the entity is already in + * the list it will be deleted now */ + gprs_sndcp_comp_delete(comp_entities, comp_field->entity); + + /* Create and add a new entity to the list */ + comp_entity = gprs_sndcp_comp_create(ctx, comp_field); + + if (!comp_entity) + return NULL; + + llist_add(&comp_entity->list, comp_entities); + return comp_entity; +} + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head + *comp_entities, uint8_t comp) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return comp_entity; + } + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given pcomp/dcomp value %d.\n", + comp); + return NULL; +} + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head + *comp_entities, uint8_t nsapi) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->nsapi_len; i++) { + if (comp_entity->nsapi[i] == nsapi) + return comp_entity; + } + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given nsapi value %d\n", + nsapi); + return NULL; +} + +/* Find a comp_index for a given pcomp/dcomp value */ +int gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp *comp_entity, int comp) +{ + int i; + + OSMO_ASSERT(comp_entity); + + /* A pcomp/dcomp field set to zero always disables + * all sort of compression and is assigned fix. So we + * just return zero in this case */ + if (comp == 0) + return 0; + + /* Look in the pcomp/dcomp list for the index */ + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return i + 1; + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching comp_index for given pcomp/dcomp value %d\n", + comp); + return 0; +} + +/* Find a pcomp/dcomp value for a given comp_index */ +int gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp *comp_entity, + int comp_index) +{ + OSMO_ASSERT(comp_entity); + + /* A comp_index of zero translates to zero right away. */ + if (comp_index == 0) + return 0; + + if (comp_index > comp_entity->comp_len) { + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching pcomp/dcomp value for given comp_index value %d.\n", + comp_index); + return 0; + } + + /* Look in the pcomp/dcomp list for the comp_index */ + return comp_entity->comp[comp_index - 1]; +} diff --git a/openbsc/src/gprs/gprs_sndcp_pcomp.c b/openbsc/src/gprs/gprs_sndcp_pcomp.c new file mode 100644 index 0000000..0fb72b6 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_pcomp.c @@ -0,0 +1,264 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a new header compression + * entity is created by gprs_sndcp.c */ + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + comp_entity->state = + slhc_init(ctx, comp_field->rfc1144_params->s01 + 1, + comp_field->rfc1144_params->s01 + 1); + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression initalized.\n"); + return 0; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a header compression + * entity is deleted by gprs_sndcp.c */ + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + if (comp_entity->state) { + slhc_free((struct slcompress *)comp_entity->state); + comp_entity->state = NULL; + } + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression terminated.\n"); + return; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Compress a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_compress(uint8_t *pcomp_index, + uint8_t *data_o, uint8_t *data_i, + unsigned int len, + struct slcompress *comp) +{ + uint8_t *comp_ptr; /* Required by slhc_compress() */ + int compr_len; + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Run compressor */ + compr_len = slhc_compress(comp, data_i, len, data_o, &comp_ptr, 0); + + /* Generate pcomp_index */ + if (data_o[0] & SL_TYPE_COMPRESSED_TCP) { + *pcomp_index = 2; + data_o[0] &= ~SL_TYPE_COMPRESSED_TCP; + } else if ((data_o[0] & SL_TYPE_UNCOMPRESSED_TCP) == + SL_TYPE_UNCOMPRESSED_TCP) { + *pcomp_index = 1; + data_o[0] &= 0x4F; + } else + *pcomp_index = 0; + + return compr_len; +} + +/* Expand a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_expand(uint8_t *data_o, uint8_t *data_i, + unsigned int len, + uint8_t pcomp_index, + struct slcompress *comp) +{ + int data_decompressed_len; + int type = -1; + + /* Note: this function should never be called with pcomp_index=0, + * since this condition is already filtered + * out by gprs_sndcp_pcomp_expand() */ + + /* Determine the data type by the PCOMP index */ + switch (pcomp_index) { + case 1: + type = SL_TYPE_UNCOMPRESSED_TCP; + break; + case 2: + type = SL_TYPE_COMPRESSED_TCP; + break; + } + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Restore the original version nibble on + * marked uncompressed packets */ + if (type == SL_TYPE_UNCOMPRESSED_TCP) { + /* Just in case the phone tags uncompressed tcp-datas + * (normally this is handled by pcomp so there is + * no need for tagging the datas) */ + data_o[0] &= 0x4F; + data_decompressed_len = slhc_remember(comp, data_o, len); + return data_decompressed_len; + } + + /* Uncompress compressed packets */ + else if (type == SL_TYPE_COMPRESSED_TCP) { + data_decompressed_len = slhc_uncompress(comp, data_o, len); + return data_decompressed_len; + } + + /* Regular or unknown packets will not be touched */ + return len; +} + +/* Expand packet header */ +int gprs_sndcp_pcomp_expand(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t pcomp, + const struct llist_head *comp_entities) +{ + int rc; + uint8_t pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data_o); + OSMO_ASSERT(data_i); + OSMO_ASSERT(comp_entities); + + /* Skip on pcomp=0 */ + if (pcomp == 0) { + memcpy(data_o, data_i, len); + return len; + } + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_comp(comp_entities, pcomp); + + /* Skip compression if no suitable compression entity can be found */ + if (comp_entity == NULL) { + memcpy(data_o, data_i, len); + return len; + } + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION); + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144); + + /* Find pcomp_index */ + pcomp_index = gprs_sndcp_comp_get_idx(comp_entity, pcomp); + + /* Run decompression algo */ + rc = gprs_sndcp_pcomp_rfc1144_expand(data_o, data_i, len, pcomp_index, + comp_entity->state); + slhc_i_status(comp_entity->state); + slhc_o_status(comp_entity->state); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header expansion done, old length=%d, new length=%d\n", len, rc); + + return rc; +} + +/* Compress packet header */ +int gprs_sndcp_pcomp_compress(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t *pcomp, + const struct llist_head *comp_entities, int nsapi) +{ + int rc; + uint8_t pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data_o); + OSMO_ASSERT(data_i); + OSMO_ASSERT(pcomp); + OSMO_ASSERT(comp_entities); + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_nsapi(comp_entities, nsapi); + + /* Skip compression if no suitable compression entity can be found */ + if (!comp_entity) { + *pcomp = 0; + memcpy(data_o, data_i, len); + return len; + } + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION); + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144); + + /* Run compression algo */ + rc = gprs_sndcp_pcomp_rfc1144_compress(&pcomp_index, data_o, data_i, + len, comp_entity->state); + slhc_i_status(comp_entity->state); + slhc_o_status(comp_entity->state); + + /* Find pcomp value */ + *pcomp = gprs_sndcp_comp_get_comp(comp_entity, pcomp_index); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header compression done, old length=%d, new length=%d\n", + len, rc); + return rc; +} diff --git a/openbsc/src/gprs/sgsn_libgtp.c b/openbsc/src/gprs/sgsn_libgtp.c index be7637a..f548dd6 100644 --- a/openbsc/src/gprs/sgsn_libgtp.c +++ b/openbsc/src/gprs/sgsn_libgtp.c @@ -307,6 +307,9 @@ static int send_act_pdp_cont_acc(struct sgsn_pdp_ctx *pctx) { struct sgsn_signal_data sig_data; + int rc_pdp; + int rc_xid; + struct gprs_llc_lle *lle; /* Inform others about it */ memset(&sig_data, 0, sizeof(sig_data)); @@ -314,7 +317,17 @@ osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_ACT, &sig_data); /* Send PDP CTX ACT to MS */ - return gsm48_tx_gsm_act_pdp_acc(pctx); + rc_pdp = gsm48_tx_gsm_act_pdp_acc(pctx); + if(rc_pdp < 0) + return rc_pdp; + + /* Send SNDCP XID to MS */ + lle = &pctx->mm->gb.llme->lle[pctx->sapi]; + rc_xid = sndcp_sn_xid_req(lle,pctx->nsapi); + if(rc_xid < 0) + return rc_xid; + + return rc_pdp; } /* The GGSN has confirmed the creation of a PDP Context */ diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c index e6dc68d..c7cc268 100644 --- a/openbsc/src/gprs/sgsn_vty.c +++ b/openbsc/src/gprs/sgsn_vty.c @@ -269,6 +269,13 @@ vty_out(vty, " timer t3395 %d%s", g_cfg->timers.T3395, VTY_NEWLINE); vty_out(vty, " timer t3397 %d%s", g_cfg->timers.T3397, VTY_NEWLINE); + if (g_cfg->pcomp_rfc1144.enabled) { + vty_out(vty, " compression rfc1144 slots %d%s", + g_cfg->pcomp_rfc1144.s01+1, VTY_NEWLINE); + } else { + vty_out(vty, " no compression rfc1144%s", VTY_NEWLINE); + } + return CMD_SUCCESS; } @@ -1074,6 +1081,28 @@ return CMD_SUCCESS; } +#define COMPRESSION_STR "Configure compression\n" +DEFUN(cfg_no_comp_rfc1144, cfg_no_comp_rfc1144_cmd, + "no compression rfc1144", + NO_STR COMPRESSION_STR + "disable rfc1144 TCP/IP header compression\n") +{ + g_cfg->pcomp_rfc1144.enabled = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_comp_rfc1144, cfg_comp_rfc1144_cmd, + "compression rfc1144 slots <1-256>", + COMPRESSION_STR + "RFC1144 Header compresion scheme\n" + "Number of compression state slots\n" + "Number of compression state slots\n") +{ + g_cfg->pcomp_rfc1144.enabled = 1; + g_cfg->pcomp_rfc1144.s01 = atoi(argv[0]) - 1; + return CMD_SUCCESS; +} + int sgsn_vty_init(void) { install_element_ve(&show_sgsn_cmd); @@ -1128,6 +1157,9 @@ install_element(SGSN_NODE, &cfg_sgsn_T3395_cmd); install_element(SGSN_NODE, &cfg_sgsn_T3397_cmd); + install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd); + install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd); + return 0; } diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 3e66978..1804280 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -33,6 +33,8 @@ $(top_builddir)/src/gprs/gprs_llc_xid.o \ $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ $(top_builddir)/src/gprs/slhc.o \ + $(top_builddir)/src/gprs/gprs_sndcp_comp.o \ + $(top_builddir)/src/gprs/gprs_sndcp_pcomp.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ -- To view, visit https://gerrit.osmocom.org/642 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 Gerrit-PatchSet: 22 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 22 08:31:00 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Mon, 22 Aug 2016 08:31:00 +0000 Subject: [PATCH] openbsc[master]: Adding V42BIS implementation In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/643 to look at the new patch set (#23). Adding V42BIS implementation V42BIS is a data compression method found in modems. It has also been specified for GPRS as data compression algorithm. The implementation has been taken from SPANDSP. There are several sources around. Asterisk and Freeswitch are using SPANDSP and its also available separately. The implementation in this commit has been taken from: https://github.com/jart/spandsp.git commit 6de1983b251806d59bb3149b7a2d7ebc99ace5aa Change-Id: Iabedece9f97ca944a1e3f747bb073e532c4e9dca --- A openbsc/include/openbsc/private_v42bis.h A openbsc/include/openbsc/v42bis.h A openbsc/src/gprs/v42bis.c 3 files changed, 1,036 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/43/643/23 diff --git a/openbsc/include/openbsc/private_v42bis.h b/openbsc/include/openbsc/private_v42bis.h new file mode 100644 index 0000000..96538f2 --- /dev/null +++ b/openbsc/include/openbsc/private_v42bis.h @@ -0,0 +1,151 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * private/v42bis.h + * + * Written by Steve Underwood + * + * Copyright (C) 2005 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: v42bis.h,v 1.1 2008/11/15 14:43:08 steveu Exp $ + */ + +#if !defined(_SPANDSP_PRIVATE_V42BIS_H_) +#define _SPANDSP_PRIVATE_V42BIS_H_ + +/*! + V.42bis dictionary node. +*/ +typedef struct +{ + /*! \brief The prior code for each defined code. */ + uint16_t parent_code; + /*! \brief The number of leaf nodes this node has */ + int16_t leaves; + /*! \brief This leaf octet for each defined code. */ + uint8_t node_octet; + /*! \brief Bit map of the children which exist */ + uint32_t children[8]; +} v42bis_dict_node_t; + +/*! + V.42bis compression. This defines the working state for a single instance + of V.42bis compression. +*/ +typedef struct +{ + /*! \brief Compression mode. */ + int compression_mode; + /*! \brief Callback function to handle received frames. */ + v42bis_frame_handler_t handler; + /*! \brief An opaque pointer passed in calls to frame_handler. */ + void *user_data; + /*! \brief The maximum frame length allowed */ + int max_len; + + uint32_t string_code; + uint32_t latest_code; + int string_length; + uint32_t output_bit_buffer; + int output_bit_count; + int output_octet_count; + uint8_t output_buf[1024]; + v42bis_dict_node_t dict[V42BIS_MAX_CODEWORDS]; + /*! \brief TRUE if we are in transparent (i.e. uncompressable) mode */ + int transparent; + int change_transparency; + /*! \brief IIR filter state, used in assessing compressibility. */ + int compressibility_filter; + int compressibility_persistence; + + /*! \brief Next empty dictionary entry */ + uint32_t v42bis_parm_c1; + /*! \brief Current codeword size */ + int v42bis_parm_c2; + /*! \brief Threshold for codeword size change */ + uint32_t v42bis_parm_c3; + + /*! \brief Mark that this is the first octet/code to be processed */ + int first; + uint8_t escape_code; +} v42bis_compress_state_t; + +/*! + V.42bis decompression. This defines the working state for a single instance + of V.42bis decompression. +*/ +typedef struct +{ + /*! \brief Callback function to handle decompressed data. */ + v42bis_data_handler_t handler; + /*! \brief An opaque pointer passed in calls to data_handler. */ + void *user_data; + /*! \brief The maximum decompressed data block length allowed */ + int max_len; + + uint32_t old_code; + uint32_t last_old_code; + uint32_t input_bit_buffer; + int input_bit_count; + int octet; + int last_length; + int output_octet_count; + uint8_t output_buf[1024]; + v42bis_dict_node_t dict[V42BIS_MAX_CODEWORDS]; + /*! \brief TRUE if we are in transparent (i.e. uncompressable) mode */ + int transparent; + + int last_extra_octet; + + /*! \brief Next empty dictionary entry */ + uint32_t v42bis_parm_c1; + /*! \brief Current codeword size */ + int v42bis_parm_c2; + /*! \brief Threshold for codeword size change */ + uint32_t v42bis_parm_c3; + + /*! \brief Mark that this is the first octet/code to be processed */ + int first; + uint8_t escape_code; + int escaped; +} v42bis_decompress_state_t; + +/*! + V.42bis compression/decompression descriptor. This defines the working state for a + single instance of V.42bis compress/decompression. +*/ +struct v42bis_state_s +{ + /*! \brief V.42bis data compression directions. */ + int v42bis_parm_p0; + + /*! \brief Compression state. */ + v42bis_compress_state_t compress; + /*! \brief Decompression state. */ + v42bis_decompress_state_t decompress; + + /*! \brief Maximum codeword size (bits) */ + int v42bis_parm_n1; + /*! \brief Total number of codewords */ + uint32_t v42bis_parm_n2; + /*! \brief Maximum string length */ + int v42bis_parm_n7; +}; + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/openbsc/include/openbsc/v42bis.h b/openbsc/include/openbsc/v42bis.h new file mode 100644 index 0000000..f13e5c5 --- /dev/null +++ b/openbsc/include/openbsc/v42bis.h @@ -0,0 +1,143 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * v42bis.h + * + * Written by Steve Underwood + * + * Copyright (C) 2005 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: v42bis.h,v 1.27 2009/04/11 18:11:19 steveu Exp $ + */ + +/*! \page v42bis_page V.42bis modem data compression +\section v42bis_page_sec_1 What does it do? +The v.42bis specification defines a data compression scheme, to work in +conjunction with the error correction scheme defined in V.42. + +\section v42bis_page_sec_2 How does it work? +*/ + +#if !defined(_SPANDSP_V42BIS_H_) +#define _SPANDSP_V42BIS_H_ + +#define V42BIS_MAX_BITS 12 +#define V42BIS_MAX_CODEWORDS 4096 /* 2^V42BIS_MAX_BITS */ +#define V42BIS_TABLE_SIZE 5021 /* This should be a prime >(2^V42BIS_MAX_BITS) */ +#define V42BIS_MAX_STRING_SIZE 250 + +enum +{ + V42BIS_P0_NEITHER_DIRECTION = 0, + V42BIS_P0_INITIATOR_RESPONDER, + V42BIS_P0_RESPONDER_INITIATOR, + V42BIS_P0_BOTH_DIRECTIONS +}; + +enum +{ + V42BIS_COMPRESSION_MODE_DYNAMIC = 0, + V42BIS_COMPRESSION_MODE_ALWAYS, + V42BIS_COMPRESSION_MODE_NEVER +}; + +typedef void (*v42bis_frame_handler_t)(void *user_data, const uint8_t *pkt, int len); +typedef void (*v42bis_data_handler_t)(void *user_data, const uint8_t *buf, int len); + +/*! + V.42bis compression/decompression descriptor. This defines the working state for a + single instance of V.42bis compress/decompression. +*/ +typedef struct v42bis_state_s v42bis_state_t; + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/*! Compress a block of octets. + \param s The V.42bis context. + \param buf The data to be compressed. + \param len The length of the data buffer. + \return 0 */ +SPAN_DECLARE(int) v42bis_compress(v42bis_state_t *s, const uint8_t *buf, int len); + +/*! Flush out any data remaining in a compression buffer. + \param s The V.42bis context. + \return 0 */ +SPAN_DECLARE(int) v42bis_compress_flush(v42bis_state_t *s); + +/*! Decompress a block of octets. + \param s The V.42bis context. + \param buf The data to be decompressed. + \param len The length of the data buffer. + \return 0 */ +SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *s, const uint8_t *buf, int len); + +/*! Flush out any data remaining in the decompression buffer. + \param s The V.42bis context. + \return 0 */ +SPAN_DECLARE(int) v42bis_decompress_flush(v42bis_state_t *s); + +/*! Set the compression mode. + \param s The V.42bis context. + \param mode One of the V.42bis compression modes - + V42BIS_COMPRESSION_MODE_DYNAMIC, + V42BIS_COMPRESSION_MODE_ALWAYS, + V42BIS_COMPRESSION_MODE_NEVER */ +SPAN_DECLARE(void) v42bis_compression_control(v42bis_state_t *s, int mode); + +/*! Initialise a V.42bis context. + \param s The V.42bis context. + \param negotiated_p0 The negotiated P0 parameter, from the V.42bis spec. + \param negotiated_p1 The negotiated P1 parameter, from the V.42bis spec. + \param negotiated_p2 The negotiated P2 parameter, from the V.42bis spec. + \param frame_handler Frame callback handler. + \param frame_user_data An opaque pointer passed to the frame callback handler. + \param max_frame_len The maximum length that should be passed to the frame handler. + \param data_handler data callback handler. + \param data_user_data An opaque pointer passed to the data callback handler. + \param max_data_len The maximum length that should be passed to the data handler. + \return The V.42bis context. */ +SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, + int negotiated_p0, + int negotiated_p1, + int negotiated_p2, + v42bis_frame_handler_t frame_handler, + void *frame_user_data, + int max_frame_len, + v42bis_data_handler_t data_handler, + void *data_user_data, + int max_data_len); + +/*! Release a V.42bis context. + \param s The V.42bis context. + \return 0 if OK */ +SPAN_DECLARE(int) v42bis_release(v42bis_state_t *s); + +/*! Free a V.42bis context. + \param s The V.42bis context. + \return 0 if OK */ +SPAN_DECLARE(int) v42bis_free(v42bis_state_t *s); + +#if defined(__cplusplus) +} +#endif + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/openbsc/src/gprs/v42bis.c b/openbsc/src/gprs/v42bis.c new file mode 100644 index 0000000..6d38916 --- /dev/null +++ b/openbsc/src/gprs/v42bis.c @@ -0,0 +1,742 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * v42bis.c + * + * Written by Steve Underwood + * + * Copyright (C) 2005 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: v42bis.c,v 1.37 2009/02/10 13:06:47 steveu Exp $ + */ + +/* THIS IS A WORK IN PROGRESS. IT IS NOT FINISHED. + Currently it performs the core compression and decompression functions OK. + However, a number of the bells and whistles in V.42bis are incomplete. */ + +/*! \file */ + +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "spandsp/telephony.h" +#include "spandsp/logging.h" +#include "spandsp/bit_operations.h" +#include "spandsp/v42bis.h" + +#include "spandsp/private/logging.h" +#include "spandsp/private/v42bis.h" + +/* Fixed parameters from the spec. */ +#define V42BIS_N3 8 /* Character size (bits) */ +#define V42BIS_N4 256 /* Number of characters in the alphabet */ +#define V42BIS_N5 (V42BIS_N4 + V42BIS_N6) /* Index number of first dictionary entry used to store a string */ +#define V42BIS_N6 3 /* Number of control codewords */ + +/* Control code words in compressed mode */ +enum +{ + V42BIS_ETM = 0, /* Enter transparent mode */ + V42BIS_FLUSH = 1, /* Flush data */ + V42BIS_STEPUP = 2 /* Step up codeword size */ +}; + +/* Command codes in transparent mode */ +enum +{ + V42BIS_ECM = 0, /* Enter compression mode */ + V42BIS_EID = 1, /* Escape character in data */ + V42BIS_RESET = 2 /* Force reinitialisation */ +}; + +/*! \brief Find the bit position of the highest set bit in a word + \param bits The word to be searched + \return The bit number of the highest set bit, or -1 if the word is zero. */ +static __inline__ int top_bit(unsigned int bits) +{ +/* Note: This function was taken from spandsp/bit_operations.h */ + int res; + + if (bits == 0) + return -1; + res = 0; + if (bits & 0xFFFF0000) + { + bits &= 0xFFFF0000; + res += 16; + } + if (bits & 0xFF00FF00) + { + bits &= 0xFF00FF00; + res += 8; + } + if (bits & 0xF0F0F0F0) + { + bits &= 0xF0F0F0F0; + res += 4; + } + if (bits & 0xCCCCCCCC) + { + bits &= 0xCCCCCCCC; + res += 2; + } + if (bits & 0xAAAAAAAA) + { + bits &= 0xAAAAAAAA; + res += 1; + } + return res; +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ void push_compressed_raw_octet(v42bis_compress_state_t *ss, int octet) +{ + ss->output_buf[ss->output_octet_count++] = (uint8_t) octet; + if (ss->output_octet_count >= ss->max_len) + { + ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); + ss->output_octet_count = 0; + } +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ void push_compressed_code(v42bis_compress_state_t *ss, int code) +{ + ss->output_bit_buffer |= code << (32 - ss->v42bis_parm_c2 - ss->output_bit_count); + ss->output_bit_count += ss->v42bis_parm_c2; + while (ss->output_bit_count >= 8) + { + push_compressed_raw_octet(ss, ss->output_bit_buffer >> 24); + ss->output_bit_buffer <<= 8; + ss->output_bit_count -= 8; + } +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ void push_compressed_octet(v42bis_compress_state_t *ss, int code) +{ + ss->output_bit_buffer |= code << (32 - 8 - ss->output_bit_count); + ss->output_bit_count += 8; + while (ss->output_bit_count >= 8) + { + push_compressed_raw_octet(ss, ss->output_bit_buffer >> 24); + ss->output_bit_buffer <<= 8; + ss->output_bit_count -= 8; + } +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v42bis_compress(v42bis_state_t *s, const uint8_t *buf, int len) +{ + int ptr; + int i; + uint32_t octet; + uint32_t code; + v42bis_compress_state_t *ss; + + ss = &s->compress; + if ((s->v42bis_parm_p0 & 2) == 0) + { + /* Compression is off - just push the incoming data out */ + for (i = 0; i < len - ss->max_len; i += ss->max_len) + ss->handler(ss->user_data, buf + i, ss->max_len); + if (i < len) + ss->handler(ss->user_data, buf + i, len - i); + return 0; + } + ptr = 0; + if (ss->first && len > 0) + { + octet = buf[ptr++]; + ss->string_code = octet + V42BIS_N6; + if (ss->transparent) + push_compressed_octet(ss, octet); + ss->first = FALSE; + } + while (ptr < len) + { + octet = buf[ptr++]; + if ((ss->dict[ss->string_code].children[octet >> 5] & (1 << (octet & 0x1F)))) + { + /* The leaf exists. Now find it in the table. */ + /* TODO: This is a brute force scan for a match. We need something better. */ + for (code = 0; code < ss->v42bis_parm_c3; code++) + { + if (ss->dict[code].parent_code == ss->string_code && ss->dict[code].node_octet == octet) + break; + } + } + else + { + /* The leaf does not exist. */ + code = s->v42bis_parm_n2; + } + /* 6.3(b) If the string matches a dictionary entry, and the entry is not that entry + created by the last invocation of the string matching procedure, then the + next character shall be read and appended to the string and this step + repeated. */ + if (code < ss->v42bis_parm_c3 && code != ss->latest_code) + { + /* The string was found */ + ss->string_code = code; + ss->string_length++; + } + else + { + /* The string is not in the table. */ + if (!ss->transparent) + { + /* 7.4 Encoding - we now have the longest matchable string, and will need to output the code for it. */ + while (ss->v42bis_parm_c1 >= ss->v42bis_parm_c3 && ss->v42bis_parm_c3 <= s->v42bis_parm_n2) + { + /* We need to increase the codeword size */ + /* 7.4(a) */ + push_compressed_code(ss, V42BIS_STEPUP); + /* 7.4(b) */ + ss->v42bis_parm_c2++; + /* 7.4(c) */ + ss->v42bis_parm_c3 <<= 1; + /* 7.4(d) this might need to be repeated, so we loop */ + } + /* 7.5 Transfer - output the last state of the string */ + push_compressed_code(ss, ss->string_code); + } + /* 7.6 Dictionary updating */ + /* 6.4 Add the string to the dictionary */ + /* 6.4(b) The string is not in the table. */ + if (code != ss->latest_code && ss->string_length < s->v42bis_parm_n7) + { + ss->latest_code = ss->v42bis_parm_c1; + /* 6.4(a) The length of the string is in range for adding to the dictionary */ + /* If the last code was a leaf, it no longer is */ + ss->dict[ss->string_code].leaves++; + ss->dict[ss->string_code].children[octet >> 5] |= (1 << (octet & 0x1F)); + /* The new one is definitely a leaf */ + ss->dict[ss->v42bis_parm_c1].parent_code = (uint16_t) ss->string_code; + ss->dict[ss->v42bis_parm_c1].leaves = 0; + ss->dict[ss->v42bis_parm_c1].node_octet = (uint8_t) octet; + /* 7.7 Node recovery */ + /* 6.5 Recovering a dictionary entry to use next */ + for (;;) + { + /* 6.5(a) and (b) */ + if ((int) (++ss->v42bis_parm_c1) >= s->v42bis_parm_n2) + ss->v42bis_parm_c1 = V42BIS_N5; + /* 6.5(c) We need to reuse a leaf node */ + if (ss->dict[ss->v42bis_parm_c1].leaves) + continue; + if (ss->dict[ss->v42bis_parm_c1].parent_code == 0xFFFF) + break; + /* 6.5(d) Detach the leaf node from its parent, and re-use it */ + /* Possibly make the parent a leaf node again */ + ss->dict[ss->dict[ss->v42bis_parm_c1].parent_code].leaves--; + ss->dict[ss->dict[ss->v42bis_parm_c1].parent_code].children[ss->dict[ss->v42bis_parm_c1].node_octet >> 5] &= ~(1 << (ss->dict[ss->v42bis_parm_c1].node_octet & 0x1F)); + ss->dict[ss->v42bis_parm_c1].parent_code = 0xFFFF; + break; + } + } + else + { + ss->latest_code = 0xFFFFFFFF; + } + /* 7.8 Data compressibility test */ + /* Filter on the balance of what went into the compressor, and what came out */ + ss->compressibility_filter += ((((8*ss->string_length - ss->v42bis_parm_c2) << 20) - ss->compressibility_filter) >> 10); + if (ss->compression_mode == V42BIS_COMPRESSION_MODE_DYNAMIC) + { + /* Work out if it is appropriate to change between transparent and + compressed mode. */ + if (ss->transparent) + { + if (ss->compressibility_filter > 0) + { + if (++ss->compressibility_persistence > 1000) + { + /* Schedule a switch to compressed mode */ + ss->change_transparency = -1; + ss->compressibility_persistence = 0; + } + } + else + { + ss->compressibility_persistence = 0; + } + } + else + { + if (ss->compressibility_filter < 0) + { + if (++ss->compressibility_persistence > 1000) + { + /* Schedule a switch to transparent mode */ + ss->change_transparency = 1; + ss->compressibility_persistence = 0; + } + } + else + { + ss->compressibility_persistence = 0; + } + } + } + if (ss->change_transparency) + { + if (ss->change_transparency < 0) + { + if (ss->transparent) + { + printf("Going compressed\n"); + /* 7.8.1 Transition to compressed mode */ + /* Switch out of transparent now, between codes. We need to send the octet which did not + match, just before switching. */ + if (octet == ss->escape_code) + { + push_compressed_octet(ss, ss->escape_code++); + push_compressed_octet(ss, V42BIS_EID); + } + else + { + push_compressed_octet(ss, octet); + } + push_compressed_octet(ss, ss->escape_code++); + push_compressed_octet(ss, V42BIS_ECM); + ss->transparent = FALSE; + } + } + else + { + if (!ss->transparent) + { + printf("Going transparent\n"); + /* 7.8.2 Transition to transparent mode */ + /* Switch into transparent now, between codes, and the unmatched octet should + go out in transparent mode, just below */ + push_compressed_code(ss, V42BIS_ETM); + ss->transparent = TRUE; + } + } + ss->change_transparency = 0; + } + /* 7.8.3 Reset function - TODO */ + ss->string_code = octet + V42BIS_N6; + ss->string_length = 1; + } + if (ss->transparent) + { + if (octet == ss->escape_code) + { + push_compressed_octet(ss, ss->escape_code++); + push_compressed_octet(ss, V42BIS_EID); + } + else + { + push_compressed_octet(ss, octet); + } + } + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v42bis_compress_flush(v42bis_state_t *s) +{ + v42bis_compress_state_t *ss; + + ss = &s->compress; + if (!ss->transparent) + { + /* Output the last state of the string */ + push_compressed_code(ss, ss->string_code); + /* TODO: We use a positive FLUSH at all times. It is really needed, if the + previous step resulted in no leftover bits. */ + push_compressed_code(ss, V42BIS_FLUSH); + } + while (ss->output_bit_count > 0) + { + push_compressed_raw_octet(ss, ss->output_bit_buffer >> 24); + ss->output_bit_buffer <<= 8; + ss->output_bit_count -= 8; + } + /* Now push out anything remaining. */ + if (ss->output_octet_count > 0) + { + ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); + ss->output_octet_count = 0; + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +#if 0 +SPAN_DECLARE(int) v42bis_compress_dump(v42bis_state_t *s) +{ + int i; + + for (i = 0; i < V42BIS_MAX_CODEWORDS; i++) + { + if (s->compress.dict[i].parent_code != 0xFFFF) + { + printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); + } + } + return 0; +} +/*- End of function --------------------------------------------------------*/ +#endif + +SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *s, const uint8_t *buf, int len) +{ + int ptr; + int i; + int this_length; + uint8_t *string; + uint32_t code; + uint32_t new_code; + int code_len; + v42bis_decompress_state_t *ss; + uint8_t decode_buf[V42BIS_MAX_STRING_SIZE]; + + ss = &s->decompress; + if ((s->v42bis_parm_p0 & 1) == 0) + { + /* Compression is off - just push the incoming data out */ + for (i = 0; i < len - ss->max_len; i += ss->max_len) + ss->handler(ss->user_data, buf + i, ss->max_len); + if (i < len) + ss->handler(ss->user_data, buf + i, len - i); + return 0; + } + ptr = 0; + code_len = (ss->transparent) ? 8 : ss->v42bis_parm_c2; + for (;;) + { + /* Fill up the bit buffer. */ + while (ss->input_bit_count < 32 - 8 && ptr < len) + { + ss->input_bit_count += 8; + ss->input_bit_buffer |= (uint32_t) buf[ptr++] << (32 - ss->input_bit_count); + } + if (ss->input_bit_count < code_len) + break; + new_code = ss->input_bit_buffer >> (32 - code_len); + ss->input_bit_count -= code_len; + ss->input_bit_buffer <<= code_len; + if (ss->transparent) + { + code = new_code; + if (ss->escaped) + { + ss->escaped = FALSE; + if (code == V42BIS_ECM) + { + printf("Hit V42BIS_ECM\n"); + ss->transparent = FALSE; + code_len = ss->v42bis_parm_c2; + } + else if (code == V42BIS_EID) + { + printf("Hit V42BIS_EID\n"); + ss->output_buf[ss->output_octet_count++] = ss->escape_code - 1; + if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) + { + ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); + ss->output_octet_count = 0; + } + } + else if (code == V42BIS_RESET) + { + printf("Hit V42BIS_RESET\n"); + } + else + { + printf("Hit V42BIS_???? - %" PRIu32 "\n", code); + } + } + else if (code == ss->escape_code) + { + ss->escape_code++; + ss->escaped = TRUE; + } + else + { + ss->output_buf[ss->output_octet_count++] = (uint8_t) code; + if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) + { + ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); + ss->output_octet_count = 0; + } + } + } + else + { + if (new_code < V42BIS_N6) + { + /* We have a control code. */ + switch (new_code) + { + case V42BIS_ETM: + printf("Hit V42BIS_ETM\n"); + ss->transparent = TRUE; + code_len = 8; + break; + case V42BIS_FLUSH: + printf("Hit V42BIS_FLUSH\n"); + v42bis_decompress_flush(s); + break; + case V42BIS_STEPUP: + /* We need to increase the codeword size */ + printf("Hit V42BIS_STEPUP\n"); + if (ss->v42bis_parm_c3 >= s->v42bis_parm_n2) + { + /* Invalid condition */ + return -1; + } + code_len = ++ss->v42bis_parm_c2; + ss->v42bis_parm_c3 <<= 1; + break; + } + continue; + } + if (ss->first) + { + ss->first = FALSE; + ss->octet = new_code - V42BIS_N6; + ss->output_buf[0] = (uint8_t) ss->octet; + ss->output_octet_count = 1; + if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) + { + ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); + ss->output_octet_count = 0; + } + ss->old_code = new_code; + continue; + } + /* Start at the end of the buffer, and decode backwards */ + string = &decode_buf[V42BIS_MAX_STRING_SIZE - 1]; + /* Check the received code is valid. It can't be too big, as we pulled only the expected number + of bits from the input stream. It could, however, be unknown. */ + if (ss->dict[new_code].parent_code == 0xFFFF) + return -1; + /* Otherwise we do a straight decode of the new code. */ + code = new_code; + /* Trace back through the octets which form the string, and output them. */ + while (code >= V42BIS_N5) + { +if (code > 4095) {printf("Code is 0x%" PRIu32 "\n", code); exit(2);} + *string-- = ss->dict[code].node_octet; + code = ss->dict[code].parent_code; + } + *string = (uint8_t) (code - V42BIS_N6); + ss->octet = code - V42BIS_N6; + /* Output the decoded string. */ + this_length = V42BIS_MAX_STRING_SIZE - (int) (string - decode_buf); + memcpy(ss->output_buf + ss->output_octet_count, string, this_length); + ss->output_octet_count += this_length; + if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) + { + ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); + ss->output_octet_count = 0; + } + /* 6.4 Add the string to the dictionary */ + if (ss->last_length < s->v42bis_parm_n7) + { + /* 6.4(a) The string does not exceed N7 in length */ + if (ss->last_old_code != ss->old_code + || + ss->last_extra_octet != *string) + { + /* 6.4(b) The string is not in the table. */ + ss->dict[ss->old_code].leaves++; + /* The new one is definitely a leaf */ + ss->dict[ss->v42bis_parm_c1].parent_code = (uint16_t) ss->old_code; + ss->dict[ss->v42bis_parm_c1].leaves = 0; + ss->dict[ss->v42bis_parm_c1].node_octet = (uint8_t) ss->octet; + /* 6.5 Recovering a dictionary entry to use next */ + for (;;) + { + /* 6.5(a) and (b) */ + if (++ss->v42bis_parm_c1 >= s->v42bis_parm_n2) + ss->v42bis_parm_c1 = V42BIS_N5; + /* 6.5(c) We need to reuse a leaf node */ + if (ss->dict[ss->v42bis_parm_c1].leaves) + continue; + /* 6.5(d) This is a leaf node, so re-use it */ + /* Possibly make the parent a leaf node again */ + if (ss->dict[ss->v42bis_parm_c1].parent_code != 0xFFFF) + ss->dict[ss->dict[ss->v42bis_parm_c1].parent_code].leaves--; + ss->dict[ss->v42bis_parm_c1].parent_code = 0xFFFF; + break; + } + } + } + /* Record the addition to the dictionary, so we can check for repeat attempts + at the next code - see II.4.3 */ + ss->last_old_code = ss->old_code; + ss->last_extra_octet = *string; + + ss->old_code = new_code; + ss->last_length = this_length; + } + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v42bis_decompress_flush(v42bis_state_t *s) +{ + v42bis_decompress_state_t *ss; + + ss = &s->decompress; + /* Push out anything remaining. */ + if (ss->output_octet_count > 0) + { + ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); + ss->output_octet_count = 0; + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +#if 0 +SPAN_DECLARE(int) v42bis_decompress_dump(v42bis_state_t *s) +{ + int i; + + for (i = 0; i < V42BIS_MAX_CODEWORDS; i++) + { + if (s->decompress.dict[i].parent_code != 0xFFFF) + { + printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); + } + } + return 0; +} +/*- End of function --------------------------------------------------------*/ +#endif + +SPAN_DECLARE(void) v42bis_compression_control(v42bis_state_t *s, int mode) +{ + s->compress.compression_mode = mode; + switch (mode) + { + case V42BIS_COMPRESSION_MODE_ALWAYS: + s->compress.change_transparency = -1; + break; + case V42BIS_COMPRESSION_MODE_NEVER: + s->compress.change_transparency = 1; + break; + } +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, + int negotiated_p0, + int negotiated_p1, + int negotiated_p2, + v42bis_frame_handler_t frame_handler, + void *frame_user_data, + int max_frame_len, + v42bis_data_handler_t data_handler, + void *data_user_data, + int max_data_len) +{ + int i; + + if (negotiated_p1 < 512 || negotiated_p1 > 65535) + return NULL; + if (negotiated_p2 < 6 || negotiated_p2 > V42BIS_MAX_STRING_SIZE) + return NULL; + if (s == NULL) + { + if ((s = (v42bis_state_t *) malloc(sizeof(*s))) == NULL) + return NULL; + } + memset(s, 0, sizeof(*s)); + + s->compress.handler = frame_handler; + s->compress.user_data = frame_user_data; + s->compress.max_len = (max_frame_len < 1024) ? max_frame_len : 1024; + + s->decompress.handler = data_handler; + s->decompress.user_data = data_user_data; + s->decompress.max_len = (max_data_len < 1024) ? max_data_len : 1024; + + s->v42bis_parm_p0 = negotiated_p0; /* default is both ways off */ + + s->v42bis_parm_n1 = top_bit(negotiated_p1 - 1) + 1; + s->v42bis_parm_n2 = negotiated_p1; + s->v42bis_parm_n7 = negotiated_p2; + + /* 6.5 */ + s->compress.v42bis_parm_c1 = + s->decompress.v42bis_parm_c1 = V42BIS_N5; + + s->compress.v42bis_parm_c2 = + s->decompress.v42bis_parm_c2 = V42BIS_N3 + 1; + + s->compress.v42bis_parm_c3 = + s->decompress.v42bis_parm_c3 = 2*V42BIS_N4; + + s->compress.first = + s->decompress.first = TRUE; + for (i = 0; i < V42BIS_MAX_CODEWORDS; i++) + { + s->compress.dict[i].parent_code = + s->decompress.dict[i].parent_code = 0xFFFF; + s->compress.dict[i].leaves = + s->decompress.dict[i].leaves = 0; + } + /* Point the root nodes for decompression to themselves. It doesn't matter much what + they are set to, as long as they are considered "known" codes. */ + for (i = 0; i < V42BIS_N5; i++) + s->decompress.dict[i].parent_code = (uint16_t) i; + s->compress.string_code = 0xFFFFFFFF; + s->compress.latest_code = 0xFFFFFFFF; + + s->decompress.last_old_code = 0xFFFFFFFF; + s->decompress.last_extra_octet = -1; + + s->compress.compression_mode = V42BIS_COMPRESSION_MODE_DYNAMIC; + + return s; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v42bis_release(v42bis_state_t *s) +{ + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v42bis_free(v42bis_state_t *s) +{ + free(s); + return 0; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ -- To view, visit https://gerrit.osmocom.org/643 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Iabedece9f97ca944a1e3f747bb073e532c4e9dca Gerrit-PatchSet: 23 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 22 08:31:00 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Mon, 22 Aug 2016 08:31:00 +0000 Subject: [PATCH] openbsc[master]: V42BIS integration and unit test In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/644 to look at the new patch set (#28). V42BIS integration and unit test The previously committed SPANDSP v42bis implementation has been edited to function outside the SPANDSP library. Debug printf statements were changed into DEBUGP statements. Als removed the assembely code in top_bit(). Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d --- M openbsc/.gitignore M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/debug.h M openbsc/include/openbsc/v42bis.h R openbsc/include/openbsc/v42bis_private.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/sgsn_main.c M openbsc/src/gprs/v42bis.c M openbsc/tests/Makefile.am M openbsc/tests/testsuite.at A openbsc/tests/v42bis/Makefile.am A openbsc/tests/v42bis/v42bis_test.c A openbsc/tests/v42bis/v42bis_test.ok 14 files changed, 262 insertions(+), 28 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/44/644/28 diff --git a/openbsc/.gitignore b/openbsc/.gitignore index e75b9eb..6fbd463 100644 --- a/openbsc/.gitignore +++ b/openbsc/.gitignore @@ -84,6 +84,7 @@ tests/xid/xid_test tests/sndcp_xid/sndcp_xid_test tests/slhc/slhc_test +tests/v42bis/v42bis_test tests/atconfig tests/atlocal diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 18980b0..1df14fe 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -232,6 +232,7 @@ tests/xid/Makefile tests/sndcp_xid/Makefile tests/slhc/Makefile + tests/v42bis/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 88a7e2c..b3403dd 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,8 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ - slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h + slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h v42bis.h \ + v42bis_private.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 90ddca5..ca3d4ad 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -37,6 +37,7 @@ DGTPHUB, DRANAP, DSUA, + DV42BIS, Debug_LastEntry, }; diff --git a/openbsc/include/openbsc/v42bis.h b/openbsc/include/openbsc/v42bis.h index f13e5c5..0b97603 100644 --- a/openbsc/include/openbsc/v42bis.h +++ b/openbsc/include/openbsc/v42bis.h @@ -33,8 +33,12 @@ \section v42bis_page_sec_2 How does it work? */ +#include + #if !defined(_SPANDSP_V42BIS_H_) #define _SPANDSP_V42BIS_H_ + +#define SPAN_DECLARE(x) x #define V42BIS_MAX_BITS 12 #define V42BIS_MAX_CODEWORDS 4096 /* 2^V42BIS_MAX_BITS */ @@ -114,7 +118,8 @@ \param data_user_data An opaque pointer passed to the data callback handler. \param max_data_len The maximum length that should be passed to the data handler. \return The V.42bis context. */ -SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, +SPAN_DECLARE(v42bis_state_t *) v42bis_init(const void *ctx, + v42bis_state_t *s, int negotiated_p0, int negotiated_p1, int negotiated_p2, diff --git a/openbsc/include/openbsc/private_v42bis.h b/openbsc/include/openbsc/v42bis_private.h similarity index 100% rename from openbsc/include/openbsc/private_v42bis.h rename to openbsc/include/openbsc/v42bis_private.h diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 2910c02..f479d56 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -27,7 +27,7 @@ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ - slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c + slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c v42bis.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c index 894ce84..f01798b 100644 --- a/openbsc/src/gprs/sgsn_main.c +++ b/openbsc/src/gprs/sgsn_main.c @@ -297,6 +297,11 @@ .description = "RFC1144 TCP/IP Header compression (SLHC)", .enabled = 1, .loglevel = LOGL_DEBUG, }, + [DV42BIS] = { + .name = "DV42BIS", + .description = "V.42bis data compression (SNDCP)", + .enabled = 1, .loglevel = LOGL_DEBUG, + } }; static const struct log_info gprs_log_info = { diff --git a/openbsc/src/gprs/v42bis.c b/openbsc/src/gprs/v42bis.c index 6d38916..b8a886d 100644 --- a/openbsc/src/gprs/v42bis.c +++ b/openbsc/src/gprs/v42bis.c @@ -31,9 +31,8 @@ /*! \file */ -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif +#define FALSE 0 +#define TRUE 1 #include #include @@ -44,13 +43,11 @@ #include #include -#include "spandsp/telephony.h" -#include "spandsp/logging.h" -#include "spandsp/bit_operations.h" -#include "spandsp/v42bis.h" +#include +#include +#include +#include -#include "spandsp/private/logging.h" -#include "spandsp/private/v42bis.h" /* Fixed parameters from the spec. */ #define V42BIS_N3 8 /* Character size (bits) */ @@ -310,7 +307,7 @@ { if (ss->transparent) { - printf("Going compressed\n"); + DEBUGP(DV42BIS,"Going compressed\n"); /* 7.8.1 Transition to compressed mode */ /* Switch out of transparent now, between codes. We need to send the octet which did not match, just before switching. */ @@ -332,7 +329,7 @@ { if (!ss->transparent) { - printf("Going transparent\n"); + DEBUGP(DV42BIS,"Going transparent\n"); /* 7.8.2 Transition to transparent mode */ /* Switch into transparent now, between codes, and the unmatched octet should go out in transparent mode, just below */ @@ -401,7 +398,7 @@ { if (s->compress.dict[i].parent_code != 0xFFFF) { - printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); + DEBUGP(DV42BIS,"Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); } } return 0; @@ -454,13 +451,13 @@ ss->escaped = FALSE; if (code == V42BIS_ECM) { - printf("Hit V42BIS_ECM\n"); + DEBUGP(DV42BIS,"Hit V42BIS_ECM\n"); ss->transparent = FALSE; code_len = ss->v42bis_parm_c2; } else if (code == V42BIS_EID) { - printf("Hit V42BIS_EID\n"); + DEBUGP(DV42BIS,"Hit V42BIS_EID\n"); ss->output_buf[ss->output_octet_count++] = ss->escape_code - 1; if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) { @@ -470,11 +467,11 @@ } else if (code == V42BIS_RESET) { - printf("Hit V42BIS_RESET\n"); + DEBUGP(DV42BIS,"Hit V42BIS_RESET\n"); } else { - printf("Hit V42BIS_???? - %" PRIu32 "\n", code); + DEBUGP(DV42BIS,"Hit V42BIS_???? - %" PRIu32 "\n", code); } } else if (code == ss->escape_code) @@ -500,17 +497,17 @@ switch (new_code) { case V42BIS_ETM: - printf("Hit V42BIS_ETM\n"); + DEBUGP(DV42BIS,"Hit V42BIS_ETM\n"); ss->transparent = TRUE; code_len = 8; break; case V42BIS_FLUSH: - printf("Hit V42BIS_FLUSH\n"); + DEBUGP(DV42BIS,"Hit V42BIS_FLUSH\n"); v42bis_decompress_flush(s); break; case V42BIS_STEPUP: /* We need to increase the codeword size */ - printf("Hit V42BIS_STEPUP\n"); + DEBUGP(DV42BIS,"Hit V42BIS_STEPUP\n"); if (ss->v42bis_parm_c3 >= s->v42bis_parm_n2) { /* Invalid condition */ @@ -547,7 +544,7 @@ /* Trace back through the octets which form the string, and output them. */ while (code >= V42BIS_N5) { -if (code > 4095) {printf("Code is 0x%" PRIu32 "\n", code); exit(2);} +if (code > 4095) {DEBUGP(DV42BIS,"Code is 0x%" PRIu32 "\n", code); exit(2);} *string-- = ss->dict[code].node_octet; code = ss->dict[code].parent_code; } @@ -631,7 +628,7 @@ { if (s->decompress.dict[i].parent_code != 0xFFFF) { - printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); + DEBUGP(DV42BIS,"Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); } } return 0; @@ -654,7 +651,8 @@ } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, +SPAN_DECLARE(v42bis_state_t *) v42bis_init(const void *ctx, + v42bis_state_t *s, int negotiated_p0, int negotiated_p1, int negotiated_p2, @@ -673,7 +671,7 @@ return NULL; if (s == NULL) { - if ((s = (v42bis_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (v42bis_state_t *) talloc_zero_size(ctx,sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -735,7 +733,7 @@ SPAN_DECLARE(int) v42bis_free(v42bis_state_t *s) { - free(s); + talloc_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index d5aa356..7acebc0 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid slhc +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid slhc v42bis if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index 5f37b8e..f18b734 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -141,3 +141,9 @@ cat $abs_srcdir/slhc/slhc_test.ok > expout AT_CHECK([$abs_top_builddir/tests/slhc/slhc_test], [], [expout], [ignore]) AT_CLEANUP + +AT_SETUP([v42bis]) +AT_KEYWORDS([v42bis]) +cat $abs_srcdir/v42bis/v42bis_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/v42bis/v42bis_test], [], [expout], [ignore]) +AT_CLEANUP diff --git a/openbsc/tests/v42bis/Makefile.am b/openbsc/tests/v42bis/Makefile.am new file mode 100644 index 0000000..9001c0f --- /dev/null +++ b/openbsc/tests/v42bis/Makefile.am @@ -0,0 +1,21 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) + +EXTRA_DIST = v42bis_test.ok + +noinst_PROGRAMS = v42bis_test + +v42bis_test_SOURCES = v42bis_test.c + +v42bis_test_LDADD = \ + $(top_builddir)/src/gprs/v42bis.o \ + $(top_builddir)/src/libcommon/libcommon.a \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOGB_LIBS) \ + $(LIBCARES_LIBS) \ + $(LIBCRYPTO_LIBS) \ + -lgtp -lrt -lm + + diff --git a/openbsc/tests/v42bis/v42bis_test.c b/openbsc/tests/v42bis/v42bis_test.c new file mode 100644 index 0000000..9270139 --- /dev/null +++ b/openbsc/tests/v42bis/v42bis_test.c @@ -0,0 +1,191 @@ +/* Test v42bis Compression/Decompression */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#define BLOCK_SIZE 100 +#define MAX_BLOCK_SIZE 2048 + +/* A struct to capture the output data of compressor and decompressor */ +struct v42bis_output_buffer { + uint8_t *buf; + uint8_t *buf_pointer; + int len; +}; + +/* A simple testpattern generator */ +static void gen_test_pattern(uint8_t *data, int len) +{ + int i; + for (i = 0; i < len; i++) + data[i] = i & 0xF0; +} + +/* Handler to capture the output data from the compressor */ +void tx_v42bis_frame_handler(void *user_data, const uint8_t *pkt, int len) +{ + struct v42bis_output_buffer *output_buffer = + (struct v42bis_output_buffer *)user_data; + memcpy(output_buffer->buf_pointer, pkt, len); + output_buffer->buf_pointer += len; + output_buffer->len += len; + return; +} + +/* Handler to capture the output data from the decompressor */ +void tx_v42bis_data_handler(void *user_data, const uint8_t *buf, int len) +{ + /* stub */ + return; +} + +/* Handler to capture the output data from the compressor */ +void rx_v42bis_frame_handler(void *user_data, const uint8_t *pkt, int len) +{ + /* stub */ + return; +} + +/* Handler to capture the output data from the decompressor */ +void rx_v42bis_data_handler(void *user_data, const uint8_t *buf, int len) +{ + struct v42bis_output_buffer *output_buffer = + (struct v42bis_output_buffer *)user_data; + memcpy(output_buffer->buf_pointer, buf, len); + output_buffer->buf_pointer += len; + output_buffer->len += len; + return; +} + +/* Test V.42bis compression and decompression */ +static void test_v42bis(const void *ctx) +{ + v42bis_state_t *tx_state; + v42bis_state_t *rx_state; + + uint8_t uncompressed_original[BLOCK_SIZE]; + uint8_t compressed[BLOCK_SIZE]; + uint8_t uncompressed[BLOCK_SIZE]; + + int rc; + struct v42bis_output_buffer compressed_data; + struct v42bis_output_buffer uncompressed_data; + + /* Initalize */ + tx_state = + v42bis_init(ctx, NULL, 3, MAX_BLOCK_SIZE, 6, + &tx_v42bis_frame_handler, NULL, MAX_BLOCK_SIZE, + &tx_v42bis_data_handler, NULL, MAX_BLOCK_SIZE); + OSMO_ASSERT(tx_state); + rx_state = + v42bis_init(ctx, NULL, 3, MAX_BLOCK_SIZE, 6, + &rx_v42bis_frame_handler, NULL, MAX_BLOCK_SIZE, + &rx_v42bis_data_handler, NULL, MAX_BLOCK_SIZE); + OSMO_ASSERT(rx_state); + v42bis_compression_control(tx_state, V42BIS_COMPRESSION_MODE_ALWAYS); + v42bis_compression_control(rx_state, V42BIS_COMPRESSION_MODE_ALWAYS); + + /* Generate test pattern for input */ + gen_test_pattern(uncompressed_original, sizeof(uncompressed_original)); + + /* Run compressor */ + compressed_data.buf = compressed; + compressed_data.buf_pointer = compressed; + compressed_data.len = 0; + tx_state->compress.user_data = (&compressed_data); + rc = v42bis_compress(tx_state, uncompressed_original, + sizeof(uncompressed_original)); + OSMO_ASSERT(rc == 0); + rc = v42bis_compress_flush(tx_state); + OSMO_ASSERT(rc == 0); + + /* Decompress again */ + uncompressed_data.buf = uncompressed; + uncompressed_data.buf_pointer = uncompressed; + uncompressed_data.len = 0; + rx_state->decompress.user_data = (&uncompressed_data); + rc = v42bis_decompress(rx_state, compressed_data.buf, + compressed_data.len); + OSMO_ASSERT(rc == 0); + rc = v42bis_decompress_flush(rx_state); + OSMO_ASSERT(rc == 0); + + /* Check results */ + printf("uncompressed_original= %s\n", + osmo_hexdump_nospc(uncompressed_original, + sizeof(uncompressed_original))); + printf("uncompressed= %s\n", + osmo_hexdump_nospc(uncompressed_data.buf, + uncompressed_data.len)); + printf("compressed= %s\n", + osmo_hexdump_nospc(compressed_data.buf, compressed_data.len)); + rc = memcmp(uncompressed, uncompressed_original, BLOCK_SIZE); + OSMO_ASSERT(rc == 0); + + v42bis_free(tx_state); + v42bis_free(rx_state); +} + +static struct log_info_cat gprs_categories[] = { + [DV42BIS] = { + .name = "DV42BIS", + .description = "V.42bis data compression (SNDCP)", + .enabled = 1,.loglevel = LOGL_DEBUG, + } +}; + +static struct log_info info = { + .cat = gprs_categories, + .num_cat = ARRAY_SIZE(gprs_categories), +}; + +int main(int argc, char **argv) +{ + void *v42bis_ctx; + + osmo_init_logging(&info); + + v42bis_ctx = talloc_named_const(NULL, 0, "v42bis_ctx"); + + test_v42bis(v42bis_ctx); + printf("Done\n"); + + talloc_report_full(v42bis_ctx, stderr); + OSMO_ASSERT(talloc_total_blocks(v42bis_ctx) == 1); + return 0; +} + +/* stubs */ +struct osmo_prim_hdr; +int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) +{ + abort(); +} diff --git a/openbsc/tests/v42bis/v42bis_test.ok b/openbsc/tests/v42bis/v42bis_test.ok new file mode 100644 index 0000000..16c8612 --- /dev/null +++ b/openbsc/tests/v42bis/v42bis_test.ok @@ -0,0 +1,4 @@ +uncompressed_original= 00000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060 +uncompressed= 00000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060 +compressed= 0180e0703824120a1309c1e0f0884424462385c2e190c868cc670f87c4221112190e27138a4522a5329c5e2f188c464c6638d804 +Done -- To view, visit https://gerrit.osmocom.org/644 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d Gerrit-PatchSet: 28 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 22 08:31:00 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Mon, 22 Aug 2016 08:31:00 +0000 Subject: [PATCH] openbsc[master]: Adding SLHC (RFC1144 header compression) code from linux kernel In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/634 to look at the new patch set (#12). Adding SLHC (RFC1144 header compression) code from linux kernel SLHC is an Implementation of RFC1144 TCP/IP header compression. We will need RFC1144 compression to compress GPRS TCP/IP traffic. The implementation pushed with this commit was taken from: git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git commit 29b4817d4018df78086157ea3a55c1d9424a7cfc Change-Id: Ied69c143678dc4a64cecc671f5c4dfebe19d8519 --- A openbsc/include/openbsc/slhc_vj.h A openbsc/src/gprs/slhc.c 2 files changed, 927 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/34/634/12 diff --git a/openbsc/include/openbsc/slhc_vj.h b/openbsc/include/openbsc/slhc_vj.h new file mode 100644 index 0000000..8716d59 --- /dev/null +++ b/openbsc/include/openbsc/slhc_vj.h @@ -0,0 +1,183 @@ +#ifndef _SLHC_H +#define _SLHC_H +/* + * Definitions for tcp compression routines. + * + * $Header: slcompress.h,v 1.10 89/12/31 08:53:02 van Exp $ + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van at helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + * + * + * modified for KA9Q Internet Software Package by + * Katie Stevens (dkstevens at ucdavis.edu) + * University of California, Davis + * Computing Services + * - 01-31-90 initial adaptation + * + * - Feb 1991 Bill_Simpson at um.cc.umich.edu + * variable number of conversation slots + * allow zero or one slots + * separate routines + * status display + */ + +/* + * Compressed packet format: + * + * The first octet contains the packet type (top 3 bits), TCP + * 'push' bit, and flags that indicate which of the 4 TCP sequence + * numbers have changed (bottom 5 bits). The next octet is a + * conversation number that associates a saved IP/TCP header with + * the compressed packet. The next two octets are the TCP checksum + * from the original datagram. The next 0 to 15 octets are + * sequence number changes, one change per bit set in the header + * (there may be no changes and there are two special cases where + * the receiver implicitly knows what changed -- see below). + * + * There are 5 numbers which can change (they are always inserted + * in the following order): TCP urgent pointer, window, + * acknowledgment, sequence number and IP ID. (The urgent pointer + * is different from the others in that its value is sent, not the + * change in value.) Since typical use of SLIP links is biased + * toward small packets (see comments on MTU/MSS below), changes + * use a variable length coding with one octet for numbers in the + * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the + * range 256 - 65535 or 0. (If the change in sequence number or + * ack is more than 65535, an uncompressed packet is sent.) + */ + +/* + * Packet types (must not conflict with IP protocol version) + * + * The top nibble of the first octet is the packet type. There are + * three possible types: IP (not proto TCP or tcp with one of the + * control flags set); uncompressed TCP (a normal IP/TCP packet but + * with the 8-bit protocol field replaced by an 8-bit connection id -- + * this type of packet syncs the sender & receiver); and compressed + * TCP (described above). + * + * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and + * is logically part of the 4-bit "changes" field that follows. Top + * three bits are actual packet type. For backward compatibility + * and in the interest of conserving bits, numbers are chosen so the + * IP protocol version number (4) which normally appears in this nibble + * means "IP packet". + */ + + +#include +#include + +/* SLIP compression masks for len/vers byte */ +#define SL_TYPE_IP 0x40 +#define SL_TYPE_UNCOMPRESSED_TCP 0x70 +#define SL_TYPE_COMPRESSED_TCP 0x80 +#define SL_TYPE_ERROR 0x00 + +/* Bits in first octet of compressed packet */ +#define NEW_C 0x40 /* flag bits for what changed in a packet */ +#define NEW_I 0x20 +#define NEW_S 0x08 +#define NEW_A 0x04 +#define NEW_W 0x02 +#define NEW_U 0x01 + +/* reserved, special-case values of above */ +#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */ +#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */ +#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U) + +#define TCP_PUSH_BIT 0x10 + +/* + * data type and sizes conversion assumptions: + * + * VJ code KA9Q style generic + * u_char byte_t unsigned char 8 bits + * u_short int16 unsigned short 16 bits + * u_int int16 unsigned short 16 bits + * u_long unsigned long unsigned long 32 bits + * int int32 long 32 bits + */ + +typedef __u8 byte_t; +typedef __u32 int32; + +/* + * "state" data for each active tcp conversation on the wire. This is + * basically a copy of the entire IP/TCP header from the last packet + * we saw from the conversation together with a small identifier + * the transmit & receive ends of the line use to locate saved header. + */ +struct cstate { + byte_t cs_this; /* connection id number (xmit) */ + struct cstate *next; /* next in ring (xmit) */ + struct iphdr cs_ip; /* ip/tcp hdr from most recent packet */ + struct tcphdr cs_tcp; + unsigned char cs_ipopt[64]; + unsigned char cs_tcpopt[64]; + int cs_hsize; +}; +#define NULLSLSTATE (struct cstate *)0 + +/* + * all the state data for one serial line (we need one of these per line). + */ +struct slcompress { + struct cstate *tstate; /* transmit connection states (array)*/ + struct cstate *rstate; /* receive connection states (array)*/ + + byte_t tslot_limit; /* highest transmit slot id (0-l)*/ + byte_t rslot_limit; /* highest receive slot id (0-l)*/ + + byte_t xmit_oldest; /* oldest xmit in ring */ + byte_t xmit_current; /* most recent xmit id */ + byte_t recv_current; /* most recent rcvd id */ + + byte_t flags; +#define SLF_TOSS 0x01 /* tossing rcvd frames until id received */ + + int32 sls_o_nontcp; /* outbound non-TCP packets */ + int32 sls_o_tcp; /* outbound TCP packets */ + int32 sls_o_uncompressed; /* outbound uncompressed packets */ + int32 sls_o_compressed; /* outbound compressed packets */ + int32 sls_o_searches; /* searches for connection state */ + int32 sls_o_misses; /* times couldn't find conn. state */ + + int32 sls_i_uncompressed; /* inbound uncompressed packets */ + int32 sls_i_compressed; /* inbound compressed packets */ + int32 sls_i_error; /* inbound error packets */ + int32 sls_i_tossed; /* inbound packets tossed because of error */ + + int32 sls_i_runt; + int32 sls_i_badcheck; +}; +#define NULLSLCOMPR (struct slcompress *)0 + +/* In slhc.c: */ +struct slcompress *slhc_init(int rslots, int tslots); +void slhc_free(struct slcompress *comp); + +int slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, + unsigned char *ocp, unsigned char **cpp, int compress_cid); +int slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize); +int slhc_remember(struct slcompress *comp, unsigned char *icp, int isize); +int slhc_toss(struct slcompress *comp); + +#endif /* _SLHC_H */ diff --git a/openbsc/src/gprs/slhc.c b/openbsc/src/gprs/slhc.c new file mode 100644 index 0000000..27ed252 --- /dev/null +++ b/openbsc/src/gprs/slhc.c @@ -0,0 +1,744 @@ +/* + * Routines to compress and uncompress tcp packets (for transmission + * over low speed serial lines). + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van at helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + * + * + * modified for KA9Q Internet Software Package by + * Katie Stevens (dkstevens at ucdavis.edu) + * University of California, Davis + * Computing Services + * - 01-31-90 initial adaptation (from 1.19) + * PPP.05 02-15-90 [ks] + * PPP.08 05-02-90 [ks] use PPP protocol field to signal compression + * PPP.15 09-90 [ks] improve mbuf handling + * PPP.16 11-02 [karn] substantially rewritten to use NOS facilities + * + * - Feb 1991 Bill_Simpson at um.cc.umich.edu + * variable number of conversation slots + * allow zero or one slots + * separate routines + * status display + * - Jul 1994 Dmitry Gorodchanin + * Fixes for memory leaks. + * - Oct 1994 Dmitry Gorodchanin + * Modularization. + * - Jan 1995 Bjorn Ekwall + * Use ip_fast_csum from ip.h + * - July 1995 Christos A. Polyzols + * Spotted bug in tcp option checking + * + * + * This module is a difficult issue. It's clearly inet code but it's also clearly + * driver code belonging close to PPP and SLIP + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_INET +/* Entire module is for IP only */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned char *encode(unsigned char *cp, unsigned short n); +static long decode(unsigned char **cpp); +static unsigned char * put16(unsigned char *cp, unsigned short x); +static unsigned short pull16(unsigned char **cpp); + +/* Allocate compression data structure + * slots must be in range 0 to 255 (zero meaning no compression) + * Returns pointer to structure or ERR_PTR() on error. + */ +struct slcompress * +slhc_init(int rslots, int tslots) +{ + register short i; + register struct cstate *ts; + struct slcompress *comp; + + if (rslots < 0 || rslots > 255 || tslots < 0 || tslots > 255) + return ERR_PTR(-EINVAL); + + comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL); + if (! comp) + goto out_fail; + + if (rslots > 0) { + size_t rsize = rslots * sizeof(struct cstate); + comp->rstate = kzalloc(rsize, GFP_KERNEL); + if (! comp->rstate) + goto out_free; + comp->rslot_limit = rslots - 1; + } + + if (tslots > 0) { + size_t tsize = tslots * sizeof(struct cstate); + comp->tstate = kzalloc(tsize, GFP_KERNEL); + if (! comp->tstate) + goto out_free2; + comp->tslot_limit = tslots - 1; + } + + comp->xmit_oldest = 0; + comp->xmit_current = 255; + comp->recv_current = 255; + /* + * don't accept any packets with implicit index until we get + * one with an explicit index. Otherwise the uncompress code + * will try to use connection 255, which is almost certainly + * out of range + */ + comp->flags |= SLF_TOSS; + + if ( tslots > 0 ) { + ts = comp->tstate; + for(i = comp->tslot_limit; i > 0; --i){ + ts[i].cs_this = i; + ts[i].next = &(ts[i - 1]); + } + ts[0].next = &(ts[comp->tslot_limit]); + ts[0].cs_this = 0; + } + return comp; + +out_free2: + kfree(comp->rstate); +out_free: + kfree(comp); +out_fail: + return ERR_PTR(-ENOMEM); +} + + +/* Free a compression data structure */ +void +slhc_free(struct slcompress *comp) +{ + if ( comp == NULLSLCOMPR ) + return; + + if ( comp->tstate != NULLSLSTATE ) + kfree( comp->tstate ); + + if ( comp->rstate != NULLSLSTATE ) + kfree( comp->rstate ); + + kfree( comp ); +} + + +/* Put a short in host order into a char array in network order */ +static inline unsigned char * +put16(unsigned char *cp, unsigned short x) +{ + *cp++ = x >> 8; + *cp++ = x; + + return cp; +} + + +/* Encode a number */ +static unsigned char * +encode(unsigned char *cp, unsigned short n) +{ + if(n >= 256 || n == 0){ + *cp++ = 0; + cp = put16(cp,n); + } else { + *cp++ = n; + } + return cp; +} + +/* Pull a 16-bit integer in host order from buffer in network byte order */ +static unsigned short +pull16(unsigned char **cpp) +{ + short rval; + + rval = *(*cpp)++; + rval <<= 8; + rval |= *(*cpp)++; + return rval; +} + +/* Decode a number */ +static long +decode(unsigned char **cpp) +{ + register int x; + + x = *(*cpp)++; + if(x == 0){ + return pull16(cpp) & 0xffff; /* pull16 returns -1 on error */ + } else { + return x & 0xff; /* -1 if PULLCHAR returned error */ + } +} + +/* + * icp and isize are the original packet. + * ocp is a place to put a copy if necessary. + * cpp is initially a pointer to icp. If the copy is used, + * change it to ocp. + */ + +int +slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, + unsigned char *ocp, unsigned char **cpp, int compress_cid) +{ + register struct cstate *ocs = &(comp->tstate[comp->xmit_oldest]); + register struct cstate *lcs = ocs; + register struct cstate *cs = lcs->next; + register unsigned long deltaS, deltaA; + register short changes = 0; + int hlen; + unsigned char new_seq[16]; + register unsigned char *cp = new_seq; + struct iphdr *ip; + struct tcphdr *th, *oth; + __sum16 csum; + + + /* + * Don't play with runt packets. + */ + + if(isizeprotocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x3fff)) { + /* Send as regular IP */ + if(ip->protocol != IPPROTO_TCP) + comp->sls_o_nontcp++; + else + comp->sls_o_tcp++; + return isize; + } + /* Extract TCP header */ + + th = (struct tcphdr *)(((unsigned char *)ip) + ip->ihl*4); + hlen = ip->ihl*4 + th->doff*4; + + /* Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or + * some other control bit is set). Also uncompressible if + * it's a runt. + */ + if(hlen > isize || th->syn || th->fin || th->rst || + ! (th->ack)){ + /* TCP connection stuff; send as regular IP */ + comp->sls_o_tcp++; + return isize; + } + /* + * Packet is compressible -- we're going to send either a + * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way, + * we need to locate (or create) the connection state. + * + * States are kept in a circularly linked list with + * xmit_oldest pointing to the end of the list. The + * list is kept in lru order by moving a state to the + * head of the list whenever it is referenced. Since + * the list is short and, empirically, the connection + * we want is almost always near the front, we locate + * states via linear search. If we don't find a state + * for the datagram, the oldest state is (re-)used. + */ + for ( ; ; ) { + if( ip->saddr == cs->cs_ip.saddr + && ip->daddr == cs->cs_ip.daddr + && th->source == cs->cs_tcp.source + && th->dest == cs->cs_tcp.dest) + goto found; + + /* if current equal oldest, at end of list */ + if ( cs == ocs ) + break; + lcs = cs; + cs = cs->next; + comp->sls_o_searches++; + } + /* + * Didn't find it -- re-use oldest cstate. Send an + * uncompressed packet that tells the other side what + * connection number we're using for this conversation. + * + * Note that since the state list is circular, the oldest + * state points to the newest and we only need to set + * xmit_oldest to update the lru linkage. + */ + comp->sls_o_misses++; + comp->xmit_oldest = lcs->cs_this; + goto uncompressed; + +found: + /* + * Found it -- move to the front on the connection list. + */ + if(lcs == ocs) { + /* found at most recently used */ + } else if (cs == ocs) { + /* found at least recently used */ + comp->xmit_oldest = lcs->cs_this; + } else { + /* more than 2 elements */ + lcs->next = cs->next; + cs->next = ocs->next; + ocs->next = cs; + } + + /* + * Make sure that only what we expect to change changed. + * Check the following: + * IP protocol version, header length & type of service. + * The "Don't fragment" bit. + * The time-to-live field. + * The TCP header length. + * IP options, if any. + * TCP options, if any. + * If any of these things are different between the previous & + * current datagram, we send the current datagram `uncompressed'. + */ + oth = &cs->cs_tcp; + + if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl + || ip->tos != cs->cs_ip.tos + || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000)) + || ip->ttl != cs->cs_ip.ttl + || th->doff != cs->cs_tcp.doff + || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) + || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){ + goto uncompressed; + } + + /* + * Figure out which of the changing fields changed. The + * receiver expects changes in the order: urgent, window, + * ack, seq (the order minimizes the number of temporaries + * needed in this section of code). + */ + if(th->urg){ + deltaS = ntohs(th->urg_ptr); + cp = encode(cp,deltaS); + changes |= NEW_U; + } else if(th->urg_ptr != oth->urg_ptr){ + /* argh! URG not set but urp changed -- a sensible + * implementation should never do this but RFC793 + * doesn't prohibit the change so we have to deal + * with it. */ + goto uncompressed; + } + if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){ + cp = encode(cp,deltaS); + changes |= NEW_W; + } + if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){ + if(deltaA > 0x0000ffff) + goto uncompressed; + cp = encode(cp,deltaA); + changes |= NEW_A; + } + if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){ + if(deltaS > 0x0000ffff) + goto uncompressed; + cp = encode(cp,deltaS); + changes |= NEW_S; + } + + switch(changes){ + case 0: /* Nothing changed. If this packet contains data and the + * last one didn't, this is probably a data packet following + * an ack (normal on an interactive connection) and we send + * it compressed. Otherwise it's probably a retransmit, + * retransmitted ack or window probe. Send it uncompressed + * in case the other side missed the compressed version. + */ + if(ip->tot_len != cs->cs_ip.tot_len && + ntohs(cs->cs_ip.tot_len) == hlen) + break; + goto uncompressed; + case SPECIAL_I: + case SPECIAL_D: + /* actual changes match one of our special case encodings -- + * send packet uncompressed. + */ + goto uncompressed; + case NEW_S|NEW_A: + if(deltaS == deltaA && + deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ + /* special case for echoed terminal traffic */ + changes = SPECIAL_I; + cp = new_seq; + } + break; + case NEW_S: + if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ + /* special case for data xfer */ + changes = SPECIAL_D; + cp = new_seq; + } + break; + } + deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id); + if(deltaS != 1){ + cp = encode(cp,deltaS); + changes |= NEW_I; + } + if(th->psh) + changes |= TCP_PUSH_BIT; + /* Grab the cksum before we overwrite it below. Then update our + * state with this packet's header. + */ + csum = th->check; + memcpy(&cs->cs_ip,ip,20); + memcpy(&cs->cs_tcp,th,20); + /* We want to use the original packet as our compressed packet. + * (cp - new_seq) is the number of bytes we need for compressed + * sequence numbers. In addition we need one byte for the change + * mask, one for the connection id and two for the tcp checksum. + * So, (cp - new_seq) + 4 bytes of header are needed. + */ + deltaS = cp - new_seq; + if(compress_cid == 0 || comp->xmit_current != cs->cs_this){ + cp = ocp; + *cpp = ocp; + *cp++ = changes | NEW_C; + *cp++ = cs->cs_this; + comp->xmit_current = cs->cs_this; + } else { + cp = ocp; + *cpp = ocp; + *cp++ = changes; + } + *(__sum16 *)cp = csum; + cp += 2; +/* deltaS is now the size of the change section of the compressed header */ + memcpy(cp,new_seq,deltaS); /* Write list of deltas */ + memcpy(cp+deltaS,icp+hlen,isize-hlen); + comp->sls_o_compressed++; + ocp[0] |= SL_TYPE_COMPRESSED_TCP; + return isize - hlen + deltaS + (cp - ocp); + + /* Update connection state cs & send uncompressed packet (i.e., + * a regular ip/tcp packet but with the 'conversation id' we hope + * to use on future compressed packets in the protocol field). + */ +uncompressed: + memcpy(&cs->cs_ip,ip,20); + memcpy(&cs->cs_tcp,th,20); + if (ip->ihl > 5) + memcpy(cs->cs_ipopt, ip+1, ((ip->ihl) - 5) * 4); + if (th->doff > 5) + memcpy(cs->cs_tcpopt, th+1, ((th->doff) - 5) * 4); + comp->xmit_current = cs->cs_this; + comp->sls_o_uncompressed++; + memcpy(ocp, icp, isize); + *cpp = ocp; + ocp[9] = cs->cs_this; + ocp[0] |= SL_TYPE_UNCOMPRESSED_TCP; + return isize; +} + + +int +slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) +{ + register int changes; + long x; + register struct tcphdr *thp; + register struct iphdr *ip; + register struct cstate *cs; + int len, hdrlen; + unsigned char *cp = icp; + + /* We've got a compressed packet; read the change byte */ + comp->sls_i_compressed++; + if(isize < 3){ + comp->sls_i_error++; + return 0; + } + changes = *cp++; + if(changes & NEW_C){ + /* Make sure the state index is in range, then grab the state. + * If we have a good state index, clear the 'discard' flag. + */ + x = *cp++; /* Read conn index */ + if(x < 0 || x > comp->rslot_limit) + goto bad; + + comp->flags &=~ SLF_TOSS; + comp->recv_current = x; + } else { + /* this packet has an implicit state index. If we've + * had a line error since the last time we got an + * explicit state index, we have to toss the packet. */ + if(comp->flags & SLF_TOSS){ + comp->sls_i_tossed++; + return 0; + } + } + cs = &comp->rstate[comp->recv_current]; + thp = &cs->cs_tcp; + ip = &cs->cs_ip; + + thp->check = *(__sum16 *)cp; + cp += 2; + + thp->psh = (changes & TCP_PUSH_BIT) ? 1 : 0; +/* + * we can use the same number for the length of the saved header and + * the current one, because the packet wouldn't have been sent + * as compressed unless the options were the same as the previous one + */ + + hdrlen = ip->ihl * 4 + thp->doff * 4; + + switch(changes & SPECIALS_MASK){ + case SPECIAL_I: /* Echoed terminal traffic */ + { + register short i; + i = ntohs(ip->tot_len) - hdrlen; + thp->ack_seq = htonl( ntohl(thp->ack_seq) + i); + thp->seq = htonl( ntohl(thp->seq) + i); + } + break; + + case SPECIAL_D: /* Unidirectional data */ + thp->seq = htonl( ntohl(thp->seq) + + ntohs(ip->tot_len) - hdrlen); + break; + + default: + if(changes & NEW_U){ + thp->urg = 1; + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->urg_ptr = htons(x); + } else + thp->urg = 0; + if(changes & NEW_W){ + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->window = htons( ntohs(thp->window) + x); + } + if(changes & NEW_A){ + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->ack_seq = htonl( ntohl(thp->ack_seq) + x); + } + if(changes & NEW_S){ + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->seq = htonl( ntohl(thp->seq) + x); + } + break; + } + if(changes & NEW_I){ + if((x = decode(&cp)) == -1) { + goto bad; + } + ip->id = htons (ntohs (ip->id) + x); + } else + ip->id = htons (ntohs (ip->id) + 1); + + /* + * At this point, cp points to the first byte of data in the + * packet. Put the reconstructed TCP and IP headers back on the + * packet. Recalculate IP checksum (but not TCP checksum). + */ + + len = isize - (cp - icp); + if (len < 0) + goto bad; + len += hdrlen; + ip->tot_len = htons(len); + ip->check = 0; + + memmove(icp + hdrlen, cp, len - hdrlen); + + cp = icp; + memcpy(cp, ip, 20); + cp += 20; + + if (ip->ihl > 5) { + memcpy(cp, cs->cs_ipopt, (ip->ihl - 5) * 4); + cp += (ip->ihl - 5) * 4; + } + + put_unaligned(ip_fast_csum(icp, ip->ihl), + &((struct iphdr *)icp)->check); + + memcpy(cp, thp, 20); + cp += 20; + + if (thp->doff > 5) { + memcpy(cp, cs->cs_tcpopt, ((thp->doff) - 5) * 4); + cp += ((thp->doff) - 5) * 4; + } + + return len; +bad: + comp->sls_i_error++; + return slhc_toss( comp ); +} + + +int +slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +{ + register struct cstate *cs; + unsigned ihl; + + unsigned char index; + + if(isize < 20) { + /* The packet is shorter than a legal IP header */ + comp->sls_i_runt++; + return slhc_toss( comp ); + } + /* Peek at the IP header's IHL field to find its length */ + ihl = icp[0] & 0xf; + if(ihl < 20 / 4){ + /* The IP header length field is too small */ + comp->sls_i_runt++; + return slhc_toss( comp ); + } + index = icp[9]; + icp[9] = IPPROTO_TCP; + + if (ip_fast_csum(icp, ihl)) { + /* Bad IP header checksum; discard */ + comp->sls_i_badcheck++; + return slhc_toss( comp ); + } + if(index > comp->rslot_limit) { + comp->sls_i_error++; + return slhc_toss(comp); + } + + /* Update local state */ + cs = &comp->rstate[comp->recv_current = index]; + comp->flags &=~ SLF_TOSS; + memcpy(&cs->cs_ip,icp,20); + memcpy(&cs->cs_tcp,icp + ihl*4,20); + if (ihl > 5) + memcpy(cs->cs_ipopt, icp + sizeof(struct iphdr), (ihl - 5) * 4); + if (cs->cs_tcp.doff > 5) + memcpy(cs->cs_tcpopt, icp + ihl*4 + sizeof(struct tcphdr), (cs->cs_tcp.doff - 5) * 4); + cs->cs_hsize = ihl*2 + cs->cs_tcp.doff*2; + /* Put headers back on packet + * Neither header checksum is recalculated + */ + comp->sls_i_uncompressed++; + return isize; +} + +int +slhc_toss(struct slcompress *comp) +{ + if ( comp == NULLSLCOMPR ) + return 0; + + comp->flags |= SLF_TOSS; + return 0; +} + +#else /* CONFIG_INET */ + +int +slhc_toss(struct slcompress *comp) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss"); + return -EINVAL; +} +int +slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress"); + return -EINVAL; +} +int +slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, + unsigned char *ocp, unsigned char **cpp, int compress_cid) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress"); + return -EINVAL; +} + +int +slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember"); + return -EINVAL; +} + +void +slhc_free(struct slcompress *comp) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free"); +} +struct slcompress * +slhc_init(int rslots, int tslots) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init"); + return NULL; +} + +#endif /* CONFIG_INET */ + +/* VJ header compression */ +EXPORT_SYMBOL(slhc_init); +EXPORT_SYMBOL(slhc_free); +EXPORT_SYMBOL(slhc_remember); +EXPORT_SYMBOL(slhc_compress); +EXPORT_SYMBOL(slhc_uncompress); +EXPORT_SYMBOL(slhc_toss); + +MODULE_LICENSE("Dual BSD/GPL"); -- To view, visit https://gerrit.osmocom.org/634 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ied69c143678dc4a64cecc671f5c4dfebe19d8519 Gerrit-PatchSet: 12 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 22 08:31:00 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Mon, 22 Aug 2016 08:31:00 +0000 Subject: [PATCH] openbsc[master]: SLHC (RFC1144 header compression) integration and unit-test In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/635 to look at the new patch set (#13). SLHC (RFC1144 header compression) integration and unit-test The previously pushed slhc implementation has been modified to compile and function outside of the kernel. Also debug log messages were added and datatypes ware matched. The implementation is now ready to be used Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 --- M openbsc/.gitignore M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/debug.h R openbsc/include/openbsc/slhc.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/sgsn_main.c M openbsc/src/gprs/slhc.c M openbsc/tests/Makefile.am M openbsc/tests/sgsn/Makefile.am A openbsc/tests/slhc/Makefile.am A openbsc/tests/slhc/slhc_test.c A openbsc/tests/slhc/slhc_test.ok M openbsc/tests/testsuite.at 14 files changed, 551 insertions(+), 91 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/35/635/13 diff --git a/openbsc/.gitignore b/openbsc/.gitignore index 8ce3b70..e75b9eb 100644 --- a/openbsc/.gitignore +++ b/openbsc/.gitignore @@ -83,6 +83,7 @@ tests/mm_auth/mm_auth_test tests/xid/xid_test tests/sndcp_xid/sndcp_xid_test +tests/slhc/slhc_test tests/atconfig tests/atlocal diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 53072bd..18980b0 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -231,6 +231,7 @@ tests/mm_auth/Makefile tests/xid/Makefile tests/sndcp_xid/Makefile + tests/slhc/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index e200b05..f402fea 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,8 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h + gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ + slhc.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 43ebb19..90ddca5 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -29,6 +29,7 @@ DBSSGP, DLLC, DSNDCP, + DSLHC, DNAT, DCTRL, DSMPP, diff --git a/openbsc/include/openbsc/slhc_vj.h b/openbsc/include/openbsc/slhc.h similarity index 97% rename from openbsc/include/openbsc/slhc_vj.h rename to openbsc/include/openbsc/slhc.h index 8716d59..cd5a47c 100644 --- a/openbsc/include/openbsc/slhc_vj.h +++ b/openbsc/include/openbsc/slhc.h @@ -171,7 +171,8 @@ #define NULLSLCOMPR (struct slcompress *)0 /* In slhc.c: */ -struct slcompress *slhc_init(int rslots, int tslots); +struct slcompress *slhc_init(const void *ctx, int rslots, int tslots); + void slhc_free(struct slcompress *comp); int slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, @@ -180,4 +181,7 @@ int slhc_remember(struct slcompress *comp, unsigned char *icp, int isize); int slhc_toss(struct slcompress *comp); +void slhc_i_status(struct slcompress *comp); +void slhc_o_status(struct slcompress *comp); + #endif /* _SLHC_H */ diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index fa4a3dd..245636b 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -26,7 +26,8 @@ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ - oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c + oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ + slhc.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c index 52fc985..894ce84 100644 --- a/openbsc/src/gprs/sgsn_main.c +++ b/openbsc/src/gprs/sgsn_main.c @@ -292,6 +292,11 @@ .description = "SCCP User Adaptation (SUA)", .enabled = 1, .loglevel = LOGL_DEBUG, }, + [DSLHC] = { + .name = "DSLHC", + .description = "RFC1144 TCP/IP Header compression (SLHC)", + .enabled = 1, .loglevel = LOGL_DEBUG, + }, }; static const struct log_info gprs_log_info = { diff --git a/openbsc/src/gprs/slhc.c b/openbsc/src/gprs/slhc.c index 27ed252..cbdf8db 100644 --- a/openbsc/src/gprs/slhc.c +++ b/openbsc/src/gprs/slhc.c @@ -50,61 +50,77 @@ * driver code belonging close to PPP and SLIP */ -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#ifdef CONFIG_INET -/* Entire module is for IP only */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#define ERR_PTR(x) x + static unsigned char *encode(unsigned char *cp, unsigned short n); static long decode(unsigned char **cpp); static unsigned char * put16(unsigned char *cp, unsigned short x); static unsigned short pull16(unsigned char **cpp); +/* Replacement for kernel space function ip_fast_csum() */ +static uint16_t ip_fast_csum(uint8_t *iph, int ihl) +{ + int i; + uint16_t temp; + uint32_t accumulator = 0xFFFF; + + for(i=0;i0xFFFF) + { + accumulator++; + accumulator&=0xFFFF; + } + } + + return (uint16_t)(htons(~accumulator)&0xFFFF); +} + +/* Replacement for kernel space function put_unaligned() */ +static void put_unaligned(uint16_t val, void *ptr) +{ + memcpy(ptr,&val,sizeof(val)); +} + + /* Allocate compression data structure * slots must be in range 0 to 255 (zero meaning no compression) * Returns pointer to structure or ERR_PTR() on error. */ struct slcompress * -slhc_init(int rslots, int tslots) +slhc_init(const void *ctx, int rslots, int tslots) { register short i; register struct cstate *ts; struct slcompress *comp; if (rslots < 0 || rslots > 255 || tslots < 0 || tslots > 255) - return ERR_PTR(-EINVAL); + return NULL; - comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL); + comp = (struct slcompress *)talloc_zero_size(ctx,sizeof(struct slcompress)); if (! comp) goto out_fail; if (rslots > 0) { size_t rsize = rslots * sizeof(struct cstate); - comp->rstate = kzalloc(rsize, GFP_KERNEL); + comp->rstate = (struct cstate *) talloc_zero_size(ctx, rsize); if (! comp->rstate) goto out_free; comp->rslot_limit = rslots - 1; @@ -112,7 +128,7 @@ if (tslots > 0) { size_t tsize = tslots * sizeof(struct cstate); - comp->tstate = kzalloc(tsize, GFP_KERNEL); + comp->tstate = (struct cstate *) talloc_zero_size(ctx, tsize); if (! comp->tstate) goto out_free2; comp->tslot_limit = tslots - 1; @@ -141,11 +157,11 @@ return comp; out_free2: - kfree(comp->rstate); + talloc_free(comp->rstate); out_free: - kfree(comp); + talloc_free(comp); out_fail: - return ERR_PTR(-ENOMEM); + return NULL; } @@ -153,16 +169,18 @@ void slhc_free(struct slcompress *comp) { + DEBUGP(DSLHC, "slhc_free(): Freeing compression states...\n"); + if ( comp == NULLSLCOMPR ) return; if ( comp->tstate != NULLSLSTATE ) - kfree( comp->tstate ); + talloc_free(comp->tstate ); if ( comp->rstate != NULLSLSTATE ) - kfree( comp->rstate ); + talloc_free( comp->rstate ); - kfree( comp ); + talloc_free( comp ); } @@ -187,6 +205,8 @@ } else { *cp++ = n; } + + DEBUGP(DSLHC, "encode(): n=%04x\n",n); return cp; } @@ -256,6 +276,7 @@ comp->sls_o_nontcp++; else comp->sls_o_tcp++; + DEBUGP(DSLHC, "slhc_compress(): Not a TCP packat, will not touch...\n"); return isize; } /* Extract TCP header */ @@ -271,6 +292,7 @@ ! (th->ack)){ /* TCP connection stuff; send as regular IP */ comp->sls_o_tcp++; + DEBUGP(DSLHC, "slhc_compress(): Packet is part of a TCP connection, will not touch...\n"); return isize; } /* @@ -287,6 +309,9 @@ * states via linear search. If we don't find a state * for the datagram, the oldest state is (re-)used. */ + + DEBUGP(DSLHC, "slhc_compress(): Compressible packet detected!\n"); + for ( ; ; ) { if( ip->saddr == cs->cs_ip.saddr && ip->daddr == cs->cs_ip.daddr @@ -310,11 +335,14 @@ * state points to the newest and we only need to set * xmit_oldest to update the lru linkage. */ + + DEBUGP(DSLHC, "slhc_compress(): Header not yet seen, will memorize header for the next turn...\n"); comp->sls_o_misses++; comp->xmit_oldest = lcs->cs_this; goto uncompressed; found: + DEBUGP(DSLHC, "slhc_compress(): Header already seen, trying to compress...\n"); /* * Found it -- move to the front on the connection list. */ @@ -344,6 +372,39 @@ */ oth = &cs->cs_tcp; + /* Display a little more debug information about which of the + * header fields changed unexpectedly */ + if(ip->version != cs->cs_ip.version) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->version != cs->cs_ip.version\n"); + if(ip->ihl != cs->cs_ip.ihl) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->ihl != cs->cs_ip.ihl\n"); + if(ip->tos != cs->cs_ip.tos) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->tos != cs->cs_ip.tos\n"); + if((ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))\n"); + if(ip->ttl != cs->cs_ip.ttl) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->ttl != cs->cs_ip.ttl\n"); + if(th->doff != cs->cs_tcp.doff) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: th->doff != cs->cs_tcp.doff\n"); + if(ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) { + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0)\n"); + DEBUGP(DSLHC, "slhc_compress(): ip->ihl = %i\n", ip->ihl); + DEBUGP(DSLHC, "slhc_compress(): ip+1 = %s\n", + osmo_hexdump_nospc((uint8_t*)(ip+1),((ip->ihl)-5)*4)); + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: cs->cs_ipopt = %s\n", + osmo_hexdump_nospc((uint8_t*)(cs->cs_ipopt),((ip->ihl)-5)*4)); + } + if(th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0) { + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)\n"); + DEBUGP(DSLHC, "slhc_compress(): th->doff = %i\n", th->doff); + DEBUGP(DSLHC, "slhc_compress(): th+1 = %s\n", + osmo_hexdump_nospc((uint8_t*)(th+1),((th->doff)-5)*4)); + DEBUGP(DSLHC, "slhc_compress(): cs->cs_tcpopt = %s\n", + osmo_hexdump_nospc((uint8_t*)cs->cs_tcpopt, + ((th->doff)-5)*4)); + } + + if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl || ip->tos != cs->cs_ip.tos || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000)) @@ -351,6 +412,7 @@ || th->doff != cs->cs_tcp.doff || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){ + DEBUGP(DSLHC, "slhc_compress(): The header contains unexpected changes, can't compress...\n"); goto uncompressed; } @@ -362,6 +424,7 @@ */ if(th->urg){ deltaS = ntohs(th->urg_ptr); + DEBUGP(DSLHC, "slhc_compress(): flag: Urgent Pointer (U) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_U; } else if(th->urg_ptr != oth->urg_ptr){ @@ -369,21 +432,29 @@ * implementation should never do this but RFC793 * doesn't prohibit the change so we have to deal * with it. */ + DEBUGP(DSLHC, "slhc_compress(): URG not set but urp changed, can't compress...\n"); goto uncompressed; } if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){ + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Window (W) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_W; } if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){ - if(deltaA > 0x0000ffff) + if(deltaA > 0x0000ffff) { + DEBUGP(DSLHC, "slhc_compress(): (deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L, can't compress...\n"); goto uncompressed; + } + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Ack (A) = 1\n"); cp = encode(cp,deltaA); changes |= NEW_A; } if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){ - if(deltaS > 0x0000ffff) + if(deltaS > 0x0000ffff) { + DEBUGP(DSLHC, "slhc_compress(): (deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L, can't compress...\n"); goto uncompressed; + } + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_S; } @@ -399,17 +470,21 @@ if(ip->tot_len != cs->cs_ip.tot_len && ntohs(cs->cs_ip.tot_len) == hlen) break; + DEBUGP(DSLHC, "slhc_compress(): Retransmitted packet detected, can't compress...\n"); goto uncompressed; case SPECIAL_I: case SPECIAL_D: /* actual changes match one of our special case encodings -- * send packet uncompressed. */ + DEBUGP(DSLHC, "slhc_compress(): Special case detected, can't compress...\n"); goto uncompressed; case NEW_S|NEW_A: if(deltaS == deltaA && deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ /* special case for echoed terminal traffic */ + DEBUGP(DSLHC, "slhc_compress(): Special case for echoed terminal traffic detected...\n"); + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1, Delta Window (W) = 1, Urgent Pointer (U) = 1\n"); changes = SPECIAL_I; cp = new_seq; } @@ -417,6 +492,8 @@ case NEW_S: if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ /* special case for data xfer */ + DEBUGP(DSLHC, "slhc_compress(): Special case for data xfer detected...\n"); + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1, Delta Ack (A) = 1, Delta Window (W) = 1, Urgent Pointer (U) = 1\n"); changes = SPECIAL_D; cp = new_seq; } @@ -424,11 +501,14 @@ } deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id); if(deltaS != 1){ + DEBUGP(DSLHC, "slhc_compress(): flag: Delta IP ID (I) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_I; } - if(th->psh) + if(th->psh) { + DEBUGP(DSLHC, "slhc_compress(): flag: Push (P) = 1\n"); changes |= TCP_PUSH_BIT; + } /* Grab the cksum before we overwrite it below. Then update our * state with this packet's header. */ @@ -445,6 +525,7 @@ if(compress_cid == 0 || comp->xmit_current != cs->cs_this){ cp = ocp; *cpp = ocp; + DEBUGP(DSLHC, "slhc_compress(): flag: Connection number (C) = 1\n"); *cp++ = changes | NEW_C; *cp++ = cs->cs_this; comp->xmit_current = cs->cs_this; @@ -456,6 +537,10 @@ *(__sum16 *)cp = csum; cp += 2; /* deltaS is now the size of the change section of the compressed header */ + + DEBUGP(DSLHC, "slhc_compress(): Delta-list length (deltaS) = %li\n",deltaS); + DEBUGP(DSLHC, "slhc_compress(): Original header len (hlen) = %i\n",hlen); + memcpy(cp,new_seq,deltaS); /* Write list of deltas */ memcpy(cp+deltaS,icp+hlen,isize-hlen); comp->sls_o_compressed++; @@ -467,6 +552,7 @@ * to use on future compressed packets in the protocol field). */ uncompressed: + DEBUGP(DSLHC, "slhc_compress(): Packet will be sent uncompressed...\n"); memcpy(&cs->cs_ip,ip,20); memcpy(&cs->cs_tcp,th,20); if (ip->ihl > 5) @@ -538,6 +624,8 @@ switch(changes & SPECIALS_MASK){ case SPECIAL_I: /* Echoed terminal traffic */ + DEBUGP(DSLHC, "slhc_uncompress(): Echoed terminal traffic detected\n"); + { register short i; i = ntohs(ip->tot_len) - hdrlen; @@ -547,11 +635,13 @@ break; case SPECIAL_D: /* Unidirectional data */ + DEBUGP(DSLHC, "slhc_uncompress(): Unidirectional data detected\n"); thp->seq = htonl( ntohl(thp->seq) + ntohs(ip->tot_len) - hdrlen); break; default: + DEBUGP(DSLHC, "slhc_uncompress(): default packet type detected\n"); if(changes & NEW_U){ thp->urg = 1; if((x = decode(&cp)) == -1) { @@ -601,6 +691,7 @@ ip->tot_len = htons(len); ip->check = 0; + DEBUGP(DSLHC, "slhc_uncompress(): making space for the reconstructed header...\n"); memmove(icp + hdrlen, cp, len - hdrlen); cp = icp; @@ -625,6 +716,7 @@ return len; bad: + DEBUGP(DSLHC, "slhc_uncompress(): bad packet detected!\n"); comp->sls_i_error++; return slhc_toss( comp ); } @@ -641,6 +733,7 @@ if(isize < 20) { /* The packet is shorter than a legal IP header */ comp->sls_i_runt++; + DEBUGP(DSLHC, "slhc_remember(): The packet is shorter than a legal IP header ==> slhc_toss()\n"); return slhc_toss( comp ); } /* Peek at the IP header's IHL field to find its length */ @@ -648,6 +741,7 @@ if(ihl < 20 / 4){ /* The IP header length field is too small */ comp->sls_i_runt++; + DEBUGP(DSLHC, "slhc_remember(): The IP header length field is too small ==> slhc_toss()\n"); return slhc_toss( comp ); } index = icp[9]; @@ -656,10 +750,12 @@ if (ip_fast_csum(icp, ihl)) { /* Bad IP header checksum; discard */ comp->sls_i_badcheck++; + DEBUGP(DSLHC, "slhc_remember(): Bad IP header checksum; discard ==> slhc_toss()\n"); return slhc_toss( comp ); } if(index > comp->rslot_limit) { comp->sls_i_error++; + DEBUGP(DSLHC, "slhc_remember(): index > comp->rslot_limit ==> slhc_toss()\n"); return slhc_toss(comp); } @@ -683,6 +779,7 @@ int slhc_toss(struct slcompress *comp) { + DEBUGP(DSLHC, "slhc_toss(): Reset compression state...\n"); if ( comp == NULLSLCOMPR ) return 0; @@ -690,55 +787,27 @@ return 0; } -#else /* CONFIG_INET */ - -int -slhc_toss(struct slcompress *comp) +void slhc_i_status(struct slcompress *comp) { - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss"); - return -EINVAL; -} -int -slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress"); - return -EINVAL; -} -int -slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, - unsigned char *ocp, unsigned char **cpp, int compress_cid) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress"); - return -EINVAL; + if (comp != NULLSLCOMPR) { + DEBUGP(DSLHC, "slhc_i_status(): %d Cmp, %d Uncmp, %d Bad, %d Tossed\n", + comp->sls_i_compressed, + comp->sls_i_uncompressed, + comp->sls_i_error, + comp->sls_i_tossed); + } } -int -slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +void slhc_o_status(struct slcompress *comp) { - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember"); - return -EINVAL; + if (comp != NULLSLCOMPR) { + DEBUGP(DSLHC, "slhc_o_status(): %d Cmp, %d Uncmp, %d AsIs, %d NotTCP %d Searches, %d Misses\n", + comp->sls_o_compressed, + comp->sls_o_uncompressed, + comp->sls_o_tcp, + comp->sls_o_nontcp, + comp->sls_o_searches, + comp->sls_o_misses); + } } -void -slhc_free(struct slcompress *comp) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free"); -} -struct slcompress * -slhc_init(int rslots, int tslots) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init"); - return NULL; -} - -#endif /* CONFIG_INET */ - -/* VJ header compression */ -EXPORT_SYMBOL(slhc_init); -EXPORT_SYMBOL(slhc_free); -EXPORT_SYMBOL(slhc_remember); -EXPORT_SYMBOL(slhc_compress); -EXPORT_SYMBOL(slhc_uncompress); -EXPORT_SYMBOL(slhc_toss); - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index 1debb2d..d5aa356 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid slhc if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 45d1780..3e66978 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -32,6 +32,7 @@ $(top_builddir)/src/gprs/oap_messages.o \ $(top_builddir)/src/gprs/gprs_llc_xid.o \ $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ + $(top_builddir)/src/gprs/slhc.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ diff --git a/openbsc/tests/slhc/Makefile.am b/openbsc/tests/slhc/Makefile.am new file mode 100644 index 0000000..d21990f --- /dev/null +++ b/openbsc/tests/slhc/Makefile.am @@ -0,0 +1,21 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) + +EXTRA_DIST = slhc_test.ok + +noinst_PROGRAMS = slhc_test + +slhc_test_SOURCES = slhc_test.c + +slhc_test_LDADD = \ + $(top_builddir)/src/gprs/slhc.o \ + $(top_builddir)/src/libcommon/libcommon.a \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOGB_LIBS) \ + $(LIBCARES_LIBS) \ + $(LIBCRYPTO_LIBS) \ + -lgtp -lrt -lm + + diff --git a/openbsc/tests/slhc/slhc_test.c b/openbsc/tests/slhc/slhc_test.c new file mode 100644 index 0000000..9880bd8 --- /dev/null +++ b/openbsc/tests/slhc/slhc_test.c @@ -0,0 +1,298 @@ +/* Test SLHC/RFC1144 TCP/IP Header compression/decompression */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include +#include + +#include + +#include +#include +#include + +/* Number of compression slots (S0-1) */ +#define SLOTS 8 + +/* Maximum packet bytes to display */ +#define DISP_MAX_BYTES 100 + +/* Sample packets to test with */ +#define PACKETS_LEN 6 +char *packets[] = { + "4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27", + "4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0", + "4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01", + "4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01", + "4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a", + "4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20" +}; + +/* Compress a packet using Van Jacobson RFC1144 header compression */ +static int compress(uint8_t *data_o, uint8_t *data_i, int len, + struct slcompress *comp) +{ + uint8_t *comp_ptr; /* Not used */ + int compr_len; + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Run compressor */ + compr_len = slhc_compress(comp, data_i, len, data_o, &comp_ptr, 0); + return compr_len; +} + +/* Expand a packet using Van Jacobson RFC1144 header compression */ +static int expand(uint8_t *data_o, uint8_t *data_i, int len, + struct slcompress *comp) +{ + int data_decompressed_len; + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Handle an uncompressed packet (learn header information */ + if ((data_i[0] & SL_TYPE_UNCOMPRESSED_TCP) == SL_TYPE_UNCOMPRESSED_TCP) { + data_o[0] &= 0x4F; + data_decompressed_len = slhc_remember(comp, data_o, len); + return data_decompressed_len; + } + + /* Uncompress compressed packets */ + else if (data_o[0] & SL_TYPE_COMPRESSED_TCP) { + data_decompressed_len = slhc_uncompress(comp, data_o, len); + return data_decompressed_len; + } + + /* Regular or unknown packets will not be touched */ + return len; +} + +/* Calculate TCP/IP checksum */ +static uint16_t calc_ip_csum(uint8_t *data, int len) +{ + int i; + uint32_t accumulator = 0; + uint16_t *pointer = (uint16_t *) data; + + for (i = len; i > 1; i -= 2) { + accumulator += *pointer; + pointer++; + } + + if (len % 2) + accumulator += *pointer; + + accumulator = (accumulator & 0xffff) + ((accumulator >> 16) & 0xffff); + accumulator += (accumulator >> 16) & 0xffff; + return (~accumulator); +} + +/* Calculate TCP/IP checksum */ +static uint16_t calc_tcpip_csum(const void *ctx, uint8_t *packet, int len) +{ + uint8_t *buf; + uint16_t csum; + + buf = talloc_zero_size(ctx, len); + memset(buf, 0, len); + memcpy(buf, packet + 12, 8); + buf[9] = packet[9]; + buf[11] = (len - 20) & 0xFF; + buf[10] = (len - 20) >> 8 & 0xFF; + memcpy(buf + 12, packet + 20, len - 20); + csum = calc_ip_csum(buf, len - 20 + 12); + talloc_free(buf); + return csum; +} + +/* Check TCP/IP packet */ +static void check_packet(const void *ctx, uint8_t *packet, int len) +{ + /* Check IP header */ + OSMO_ASSERT(len > 20); + OSMO_ASSERT(calc_ip_csum(packet, 20) == 0); + + /* Check TCP packet */ + if (packet[9] != 0x06) + return; + OSMO_ASSERT(len > 40); + OSMO_ASSERT(calc_tcpip_csum(ctx, packet, len) == 0); +} + +/* Strip TCP options from TCP/IP packet */ +static int strip_tcp_options(const void *ctx, uint8_t *packet, int len) +{ + uint8_t doff; + uint16_t csum; + + /* Check if the packet can be handled here */ + if (len < 37) + return len; + if (packet[9] != 0x06) + return len; + + /* Strip TCP/IP options from packet */ + doff = ((packet[32] >> 4) & 0x0F) * 4; + memmove(packet + 40, packet + doff + 20, len - 40 - (doff - 20)); + len = len - (doff - 20); + + /* Repair data offset (TCP header length) */ + packet[32] &= 0x0F; + packet[32] |= 0x50; + + /* Repair checksum */ + packet[36] = 0; + packet[37] = 0; + csum = calc_tcpip_csum(ctx, packet, len); + packet[36] = csum & 0xFF; + packet[37] = csum >> 8 & 0xFF; + + /* Repair total length */ + packet[3] = len & 0xFF; + packet[2] = len >> 8 & 0xFF; + + /* Repair IP header checksum */ + packet[10] = 0; + packet[11] = 0; + csum = calc_ip_csum(packet, 20); + packet[10] = csum & 0xFF; + packet[11] = csum >> 8 & 0xFF; + printf("csum=%04x\n", csum); + + return len; +} + +/* Compress / Decompress packets */ +static void test_slhc(const void *ctx) +{ + char packet_ascii[2048]; + int i; + + struct slcompress *comp; + uint8_t packet[1024]; + int packet_len; + uint8_t packet_compr[1024]; + int packet_compr_len; + uint8_t packet_decompr[1024]; + int packet_decompr_len; + + printf("Allocating compression state...\n"); + comp = slhc_init(ctx, SLOTS, SLOTS); + OSMO_ASSERT(comp); + + for(i=0;i DISP_MAX_BYTES) + packet_compr_len = DISP_MAX_BYTES; + if (packet_len > DISP_MAX_BYTES) + packet_len = DISP_MAX_BYTES; + if (packet_decompr_len > DISP_MAX_BYTES) + packet_decompr_len = DISP_MAX_BYTES; + printf("Original Packet: (%i bytes) %s\n", packet_len, + osmo_hexdump_nospc(packet, packet_len)); + printf("DecompressedPacket: (%i bytes) %s\n", + packet_decompr_len, osmo_hexdump_nospc(packet_decompr, + packet_decompr_len)); + printf("CompressedPacket: (%i bytes) %s\n", packet_compr_len, + osmo_hexdump_nospc(packet_compr, packet_compr_len)); + slhc_o_status(comp); + slhc_o_status(comp); + + printf("\n"); + } + + printf("Freeing compression state...\n"); + slhc_free(comp); + printf("\n"); +} + +static struct log_info_cat gprs_categories[] = { + [DSNDCP] = { + .name = "DSNDCP", + .description = + "GPRS Sub-Network Dependent Control Protocol (SNDCP)", + .enabled = 1,.loglevel = LOGL_DEBUG, + }, + [DSLHC] = { + .name = "DSLHC", + .description = + "Van Jacobson RFC1144 TCP/IP header compression (SLHC)", + .enabled = 1,.loglevel = LOGL_DEBUG, + } +}; + +static struct log_info info = { + .cat = gprs_categories, + .num_cat = ARRAY_SIZE(gprs_categories), +}; + +int main(int argc, char **argv) +{ + void *ctx; + + osmo_init_logging(&info); + + ctx = talloc_named_const(NULL, 0, "slhc_ctx"); + + test_slhc(ctx); + + printf("Done\n"); + + talloc_report_full(ctx, stderr); + OSMO_ASSERT(talloc_total_blocks(ctx) == 1); + return 0; +} + +/* stubs */ +struct osmo_prim_hdr; +int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) +{ + abort(); +} diff --git a/openbsc/tests/slhc/slhc_test.ok b/openbsc/tests/slhc/slhc_test.ok new file mode 100644 index 0000000..636241d --- /dev/null +++ b/openbsc/tests/slhc/slhc_test.ok @@ -0,0 +1,52 @@ +Allocating compression state... +csum=b3a9 +Compressing... +Decompressing... +Results: +Original Packet: (52 bytes) 4510003446dd40004006a9b3c0a8646ec0a864640017ad8b81980100f3ac984d501800e371410000fffd18fffd20fffd23fffd27 +DecompressedPacket: (52 bytes) 4510003446dd40004006a9b3c0a8646ec0a864640017ad8b81980100f3ac984d501800e371410000fffd18fffd20fffd23fffd27 +CompressedPacket: (52 bytes) 7510003446dd40004000a9b3c0a8646ec0a864640017ad8b81980100f3ac984d501800e371410000fffd18fffd20fffd23fffd27 + +csum=97a9 +Compressing... +Decompressing... +Results: +Original Packet: (79 bytes) 4510004f46de40004006a997c0a8646ec0a864640017ad8b8198010cf3ac984d501800e3cda40000fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 +DecompressedPacket: (79 bytes) 4510004f46de40004006a997c0a8646ec0a864640017ad8b8198010cf3ac984d501800e3cda40000fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 +CompressedPacket: (43 bytes) df00cda4fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 + +csum=baa9 +Compressing... +Decompressing... +Results: +Original Packet: (43 bytes) 4510002b46df40004006a9bac0a8646ec0a864640017ad8b81980133f3ac989f501800e3a70a0000fffd01 +DecompressedPacket: (43 bytes) 4510002b46df40004006a9bac0a8646ec0a864640017ad8b81980133f3ac989f501800e3a70a0000fffd01 +CompressedPacket: (9 bytes) dc00a70a5227fffd01 + +csum=b9a9 +Compressing... +Decompressing... +Results: +Original Packet: (43 bytes) 4510002b46e040004006a9b9c0a8646ec0a864640017ad8b81980136f3ac98a2501800e3a7060000fffb01 +DecompressedPacket: (43 bytes) 4510002b46e040004006a9b9c0a8646ec0a864640017ad8b81980136f3ac98a2501800e3a7060000fffb01 +CompressedPacket: (7 bytes) db00a706fffb01 + +csum=7ba9 +Compressing... +Decompressing... +Results: +Original Packet: (100 bytes) 4510006846e140004006a97bc0a8646ec0a864640017ad8b81980139f3ac98a5501800e3c2d000000d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d +DecompressedPacket: (100 bytes) 4510006846e140004006a97bc0a8646ec0a864640017ad8b81980139f3ac98a5501800e3c2d000000d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d +CompressedPacket: (68 bytes) db00c2d00d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a + +csum=aca9 +Compressing... +Decompressing... +Results: +Original Packet: (54 bytes) 4510003646e240004006a9acc0a8646ec0a864640017ad8b81980179f3ac98a5501800e321fb0000706f6c6c7578206c6f67696e3a20 +DecompressedPacket: (54 bytes) 4510003646e240004006a9acc0a8646ec0a864640017ad8b81980179f3ac98a5501800e321fb0000706f6c6c7578206c6f67696e3a20 +CompressedPacket: (18 bytes) df0021fb706f6c6c7578206c6f67696e3a20 + +Freeing compression state... + +Done diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index 85a81d6..5f37b8e 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -136,3 +136,8 @@ AT_CHECK([$abs_top_builddir/tests/sndcp_xid/sndcp_xid_test], [], [expout], [ignore]) AT_CLEANUP +AT_SETUP([slhc]) +AT_KEYWORDS([slhc]) +cat $abs_srcdir/slhc/slhc_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/slhc/slhc_test], [], [expout], [ignore]) +AT_CLEANUP -- To view, visit https://gerrit.osmocom.org/635 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 Gerrit-PatchSet: 13 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 22 09:31:19 2016 From: gerrit-no-reply at lists.osmocom.org (pravin) Date: Mon, 22 Aug 2016 09:31:19 +0000 Subject: [PATCH] osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Hello Max, Neels Hofmeyr, Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/416 to look at the new patch set (#19). Add decoding of compressed bitmap in EPDAN Implemented tree based algorithm to decode compressed bitmap in EPDAN as described in section 9.1.10 of 3GPP 44.060. This algorithm intends to improve the performance over existing method. New Regression test is added under bitcomp directory. Test case is added to validate decompressed result of the bitmap Present in EPDAN. Test is done for multiple bitmaps of varying length. Invalid inputs are also part of the test vector. Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce --- M src/Makefile.am M src/decoding.cpp A src/egprs_rlc_compression.cpp A src/egprs_rlc_compression.h M tests/Makefile.am A tests/bitcomp/BitcompTest A tests/bitcomp/BitcompTest.cpp A tests/bitcomp/BitcompTest.err A tests/bitcomp/BitcompTest.ok M tests/testsuite.at 10 files changed, 774 insertions(+), 18 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/16/416/19 diff --git a/src/Makefile.am b/src/Makefile.am index 9bdec2f..9b047e7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -62,7 +62,8 @@ rlc.cpp \ osmobts_sock.cpp \ gprs_codel.c \ - gprs_coding_scheme.cpp + gprs_coding_scheme.cpp \ + egprs_rlc_compression.cpp bin_PROGRAMS = \ osmo-pcu @@ -94,7 +95,8 @@ pcu_utils.h \ cxx_linuxlist.h \ gprs_codel.h \ - gprs_coding_scheme.h + gprs_coding_scheme.h \ + egprs_rlc_compression.h osmo_pcu_SOURCES = pcu_main.cpp diff --git a/src/decoding.cpp b/src/decoding.cpp index 7c00ff7..2b00a07 100644 --- a/src/decoding.cpp +++ b/src/decoding.cpp @@ -20,6 +20,7 @@ #include #include #include +#include extern "C" { #include @@ -652,10 +653,10 @@ int num_blocks = 0; struct bitvec urbb; int i; + int rc; bool have_bitmap; int implicitly_acked_blocks; int ssn = desc->STARTING_SEQUENCE_NUMBER; - int rc; if (desc->FINAL_ACK_INDICATION) return handle_final_ack(bits, bsn_begin, bsn_end, window); @@ -695,24 +696,20 @@ if (crbb_len > 0) { int old_len = bits->cur_bit; - struct bitvec crbb; - crbb.data = (uint8_t *)desc->CRBB; - crbb.data_len = sizeof(desc->CRBB); - crbb.cur_bit = desc->CRBB_LENGTH; - - rc = osmo_t4_decode(&crbb, desc->CRBB_STARTING_COLOR_CODE, - bits); - + LOGP(DRLCMACDL, LOGL_DEBUG, "Compress bitmap exist," + "CRBB LEN =%d and Starting color code =%d", + desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE); + rc = decompress_crbb(desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE, + desc->CRBB, bits); if (rc < 0) { LOGP(DRLCMACUL, LOGL_NOTICE, - "Failed to decode CRBB: " - "length %d, data '%s'\n", - desc->CRBB_LENGTH, - osmo_hexdump(crbb.data, crbb.data_len)); + "Failed to decode CRBB: length %d, data '%s'\n", + desc->CRBB_LENGTH, osmo_hexdump( + desc->CRBB, (desc->CRBB_LENGTH + 7)/8)); /* We don't know the SSN offset for the URBB, - * return what we have so far and assume the - * bitmap has stopped here */ + * return what we have so far and assume the + * bitmap has stopped here */ goto aborted; } diff --git a/src/egprs_rlc_compression.cpp b/src/egprs_rlc_compression.cpp new file mode 100644 index 0000000..b781331 --- /dev/null +++ b/src/egprs_rlc_compression.cpp @@ -0,0 +1,332 @@ +/* egprs_rlc_compression.h +* Routines for EGPRS RLC bitmap compression handling +*/ +#include +#include +#include + +extern "C" { +#include +#include +#include +} + +egprs_compress *egprs_compress::s_instance = 0; + +/* Function to create tree node */ +Node *egprs_compress::create_tree_node(void *parent) +{ + Node *new_node; + + new_node = talloc_zero(parent, Node); + new_node->left = NULL; + new_node->right = NULL; + new_node->run_length = -1; + return new_node; +} + +/* Function to build the codeword tree + * \param iter[in] Iterate the node on the tree + * \param len[in] Length of the code word + * \param i[in] Iterator + * \param idx[in] Iterate index of the code word table + */ +void egprs_compress::build_codeword(Node *root, const char *cdwd[]) +{ + Node *iter; + int len; + int i; + int idx; + + for (idx = 0; idx < MAX_CDWDTBL_LEN; idx++) { + len = strlen((const char *)cdwd[idx]); + iter = root; + for (i = 0; i < len; i++) { + if (cdwd[idx][i] == '0') { + if (!iter->left) + iter->left = create_tree_node(root); + iter = iter->left; + } else if (cdwd[idx][i] == '1') { + if (!iter->right) + iter->right = create_tree_node(root); + iter = iter->right; + } + } + if (iter) { + if (idx < 64) + (iter->run_length) = idx; + else + (iter->run_length) = (idx - 63) * 64; + } + } +} + +const char *one_run_len_code_list[MAX_CDWDTBL_LEN] = { + "00110101", + "000111", + "0111", + "1000", + "1011", + "1100", + "1110", + "1111", + "10011", + "10100", + "00111", + "01000", + "001000", + "000011", + "110100", + "110101", + "101010", + "101011", + "0100111", + "0001100", + "0001000", + "0010111", + "0000011", + "0000100", + "0101000", + "0101011", + "0010011", + "0100100", + "0011000", + "00000010", + "00000011", + "00011010", + "00011011", + "00010010", + "00010011", + "00010100", + "00010101", + "00010110", + "00010111", + "00101000", + "00101001", + "00101010", + "00101011", + "00101100", + "00101101", + "00000100", + "00000101", + "00001010", + "00001011", + "01010010", + "01010011", + "01010100", + "01010101", + "00100100", + "00100101", + "01011000", + "01011001", + "01011010", + "01011011", + "01001010", + "01001011", + "00110010", + "00110011", + "00110100", + "11011", + "10010", + "010111", + "0110111", + "00110110", + "00110111", + "01100100", + "01100101", + "01101000", + "01100111", + "011001100", + "011001101", + "011010010", + "011010011", + "011010100" +}; + +const char *zero_run_len_code_list[MAX_CDWDTBL_LEN] = { + "0000110111", + "10", + "11", + "010", + "011", + "0011", + "0010", + "00011", + "000101", + "000100", + "0000100", + "0000101", + "0000111", + "00000100", + "00000111", + "000011000", + "0000010111", + "0000011000", + "0000001000", + "00001100111", + "00001101000", + "00001101100", + "00000110111", + "00000101000", + "00000010111", + "00000011000", + "000011001010", + "000011001011", + "000011001100", + "000011001101", + "000001101000", + "000001101001", + "000001101010", + "000001101011", + "000011010010", + "000011010011", + "000011010100", + "000011010101", + "000011010110", + "000011010111", + "000001101100", + "000001101101", + "000011011010", + "000011011011", + "000001010100", + "000001010101", + "000001010110", + "000001010111", + "000001100100", + "000001100101", + "000001010010", + "000001010011", + "000000100100", + "000000110111", + "000000111000", + "000000100111", + "000000101000", + "000001011000", + "000001011001", + "000000101011", + "000000101100", + "000001011010", + "000001100110", + "000001100111", + "0000001111", + "000011001000", + "000011001001", + "000001011011", + "000000110011", + "000000110100", + "000000110101", + "0000001101100", + "0000001101101", + "0000001001010", + "0000001001011", + "0000001001100", + "0000001001101", + "0000001110010", + "0000001110011" +}; + +/* search_runlen function will return the runlength for the codeword + * \param root[in] Root of Ones or Zeros tree + * \param bmbuf[in] Recevied compressed bitmap buf + * \param bit_pos[in] The start bit pos to read codeword + * \param len_codewd[in] Length of code word + * \param rlen[out] Run length value + */ +static int search_runlen( + Node *root, + const uint8_t *bmbuf, + uint8_t bit_pos, + uint8_t *len_codewd, + uint16_t *rlen) +{ + Node *iter; + uint8_t dir; + + iter = root; + *len_codewd = 0; + + while (iter->run_length == -1) { + if ((!iter->left) && (!iter->right)) + return -1; + /* get the bit value at the bitpos and put it in right most of dir */ + dir = ((bmbuf[BITS_TO_BYTES(bit_pos)-1] + >>(7-(MOD8(bit_pos)))) & 0x01); + (bit_pos)++; + (*len_codewd)++; + if (((dir&0x01) == 0) && (iter->left != NULL)) + iter = iter->left; + else if (((dir&0x01) == 1) && (iter->right != NULL)) + iter = iter->right; + else + return -1; + } + (*rlen) = (iter->run_length); + return 1; +} + +/* Function to decompress crbb + * \param[in] Compressed bitmap length + * \clr_code_bit[in] Color code 1 for Ones runlength 0 for Zero runlength + * \orig_crbb_buf[in] Received block crbb bitmap + * \dest[out] Uncompressed bitvector + */ +int decompress_crbb( + int8_t compress_bmap_len, + uint8_t clr_code_bit, + const uint8_t *orig_crbb_buf, + bitvec *dest) +{ + + uint8_t bit_pos = 0; + uint8_t data = 0x0; + node *list = NULL; + uint8_t nbits = 0; /* number of bits of codeword */ + uint16_t run_length = 0; + uint16_t cbmaplen = 0; /* compressed bitmap part after decompression */ + unsigned wp = dest->cur_bit; + int rc = 0; + egprs_compress *compress = egprs_compress::instance(); + + while (compress_bmap_len > 0) { + if (clr_code_bit == 1) { + data = 0xff; + list = compress->ones_list; + } else { + data = 0x00; + list = compress->zeros_list; + } + rc = search_runlen(list, orig_crbb_buf, + bit_pos, &nbits, &run_length); + if (rc == -1) + return -1; + /* If run length > 64, need makeup and terminating code */ + if (run_length < 64) + clr_code_bit ? clr_code_bit = 0 : clr_code_bit = 1; + cbmaplen = cbmaplen + run_length; + /* put run length of Ones in uncompressed bitmap */ + while (run_length != 0) { + if (run_length > 8) { + bitvec_write_field(dest, wp, data, 8); + run_length = run_length - 8; + } else { + bitvec_write_field(dest, wp, data, run_length); + run_length = 0; + } + } + bit_pos = bit_pos + nbits; + compress_bmap_len = compress_bmap_len - nbits; + } + return 0; +} + +/* init function to build codeword */ +int egprs_compress::decode_tree_init() +{ + ones_list = create_tree_node(tall_pcu_ctx); + zeros_list = create_tree_node(tall_pcu_ctx); + build_codeword( + ones_list, one_run_len_code_list); + build_codeword( + zeros_list, zero_run_len_code_list); + return 0; +} diff --git a/src/egprs_rlc_compression.h b/src/egprs_rlc_compression.h new file mode 100644 index 0000000..cf56350 --- /dev/null +++ b/src/egprs_rlc_compression.h @@ -0,0 +1,64 @@ +/* egprs_rlc_compression.h + * Routines for EGPRS RLC bitmap compression handling + */ + +#pragma once + +#include +#include + +extern "C" { +#include +} + +#include +#include +#include + +#define MAX_CDWDTBL_LEN 79 /* total number of codewords */ +#define BITS_TO_BYTES(X) ((X ? (X/8):0)+1) +#define MOD8(X) (((X)+8) & (0x07)) + +typedef struct node { + struct node *left; + struct node *right; + int run_length; +} Node; + +extern const char *one_run_len_code_list[MAX_CDWDTBL_LEN]; +extern const char *zero_run_len_code_list[MAX_CDWDTBL_LEN]; +extern void *tall_pcu_ctx; + +int decompress_crbb(int8_t compress_bmap_len, uint8_t clr_code_bit, + const uint8_t *orig_buf, bitvec *dest); + +/* Creating singleton class + */ +class egprs_compress +{ + static egprs_compress *s_instance; + + egprs_compress() + { + if (decode_tree_init() < 0) { + fprintf(stderr, "Error initializing tree\n"); + exit(1); + } + } + Node *create_tree_node(void *); + void build_codeword(Node *root, const char *cdwd[]); + ~egprs_compress(); +public: + Node *ones_list; + Node *zeros_list; + + int decode_tree_init(void); + + static egprs_compress *instance() + { + if (!s_instance) + s_instance = new egprs_compress; + + return s_instance; + } +}; diff --git a/tests/Makefile.am b/tests/Makefile.am index 2a3415e..5c68bea 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,7 +1,7 @@ AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGB_CFLAGS) $(LIBOSMOGSM_CFLAGS) -I$(top_srcdir)/src/ AM_LDFLAGS = -lrt -check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest llc/LlcTest codel/codel_test edge/EdgeTest +check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest llc/LlcTest codel/codel_test edge/EdgeTest bitcomp/BitcompTest noinst_PROGRAMS = emu/pcu_emu rlcmac_RLCMACTest_SOURCES = rlcmac/RLCMACTest.cpp @@ -25,6 +25,18 @@ $(LIBOSMOGSM_LIBS) \ $(LIBOSMOCORE_LIBS) \ $(COMMON_LA) + +bitcomp_BitcompTest_SOURCES = bitcomp/BitcompTest.cpp +bitcomp_BitcompTest_LDADD = \ + $(top_builddir)/src/libgprs.la \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGB_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(COMMON_LA) + +bitcomp_BitcompTest_LDFLAGS = \ + -Wl,-u,bssgp_prim_cb + edge_EdgeTest_SOURCES = edge/EdgeTest.cpp edge_EdgeTest_LDADD = \ @@ -108,6 +120,7 @@ rlcmac/RLCMACTest.ok rlcmac/RLCMACTest.err \ alloc/AllocTest.ok alloc/AllocTest.err \ tbf/TbfTest.ok tbf/TbfTest.err \ + bitcomp/BitcompTest.ok bitcomp/BitcompTest.err \ types/TypesTest.ok types/TypesTest.err \ ms/MsTest.ok ms/MsTest.err \ llc/LlcTest.ok llc/LlcTest.err \ diff --git a/tests/bitcomp/BitcompTest b/tests/bitcomp/BitcompTest new file mode 100755 index 0000000..7c7838c --- /dev/null +++ b/tests/bitcomp/BitcompTest Binary files differ diff --git a/tests/bitcomp/BitcompTest.cpp b/tests/bitcomp/BitcompTest.cpp new file mode 100644 index 0000000..00d6ea8 --- /dev/null +++ b/tests/bitcomp/BitcompTest.cpp @@ -0,0 +1,246 @@ +#include "egprs_rlc_compression.h" +#include "decoding.h" +#include "bts.h" +#include "tbf.h" +#include "gprs_debug.h" +#include "pcu_utils.h" +#include "gprs_bssgp_pcu.h" +#include "pcu_l1_if.h" + +extern "C" { +#include "pcu_vty.h" + +#include +#include +#include +#include +#include +#include +} + +#define NEW 1 +#define MASK(n) (0xFF << (8-n)) +#define MAX_CRBB_LEN 23 +#define MAX_URBB_LEN 40 + +void *tall_pcu_ctx; +int16_t spoof_mnc = 0, spoof_mcc = 0; + +struct test_data { + int8_t crbb_len; + uint8_t cc; + uint8_t crbb_data[MAX_CRBB_LEN]; /* compressed data */ + uint8_t ucmp_data[MAX_URBB_LEN]; /* uncompressed data */ + int ucmp_len; + int verify; +} test[] = { + { .crbb_len = 67, .cc = 1, + .crbb_data = { + 0x02, 0x0c, 0xa0, 0x30, 0xcb, 0x1a, 0x0c, 0xe3, 0x6c + }, + .ucmp_data = { + 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x01, 0xff, 0xff, + 0xff, 0xf8, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, + 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xdb + }, + .ucmp_len = 194, .verify = 1 + }, + { .crbb_len = 40, .cc = 1, + .crbb_data = { + 0x53, 0x06, 0xc5, 0x40, 0x6d + }, + .ucmp_data = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x03 + }, + .ucmp_len = 182, .verify = 1 + }, + { .crbb_len = 8, .cc = 1, + .crbb_data = {0x02}, + .ucmp_data = {0xff, 0xff, 0xff, 0xf8}, + .ucmp_len = 29, .verify = 1 + }, + { .crbb_len = 103, .cc = 1, + .crbb_data = { + 0x02, 0x0c, 0xe0, 0x41, 0xa0, 0x0c, 0x36, 0x0d, 0x03, + 0x71, 0xb0, 0x6e, 0x24 + }, + .ucmp_data = { + 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xf8, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, + 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff + }, + .ucmp_len = 288, .verify = 1 + }, + /* Test vector from libosmocore test */ + { .crbb_len = 35, .cc = 0, + .crbb_data = {0xde, 0x88, 0x75, 0x65, 0x80}, + .ucmp_data = {0x37, 0x47, 0x81, 0xf0}, + .ucmp_len = 28, .verify = 1 + }, + { .crbb_len = 18, .cc = 1, + .crbb_data = {0xdd, 0x41, 0x00}, + .ucmp_data = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00 + }, + .ucmp_len = 90, .verify = 1 + }, + /*Invalid inputs*/ + { .crbb_len = 18, .cc = 1, + .crbb_data = {0x1E, 0x70, 0xc0}, + .ucmp_data = {0x0}, + .ucmp_len = 0, .verify = 0 + }, + { .crbb_len = 14, .cc = 1, + .crbb_data = {0x00, 0x1E, 0x7c}, + .ucmp_data = {0x0}, + .ucmp_len = 0, .verify = 0 + }, + { .crbb_len = 24, .cc = 0, + .crbb_data = {0x00, 0x00, 0x00}, + .ucmp_data = {0x0}, + .ucmp_len = 0, .verify = 0 + } + }; + +static const struct log_info_cat default_categories[] = { + {"DCSN1", "\033[1;31m", "Concrete Syntax Notation One (CSN1)", LOGL_INFO, 0}, + {"DL1IF", "\033[1;32m", "GPRS PCU L1 interface (L1IF)", LOGL_DEBUG, 1}, + {"DRLCMAC", "\033[0;33m", "GPRS RLC/MAC layer (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACDATA", "\033[0;33m", "GPRS RLC/MAC layer Data (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACDL", "\033[1;33m", "GPRS RLC/MAC layer Downlink (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACUL", "\033[1;36m", "GPRS RLC/MAC layer Uplink (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACSCHED", "\033[0;36m", "GPRS RLC/MAC layer Scheduling (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACMEAS", "\033[1;31m", "GPRS RLC/MAC layer Measurements (RLCMAC)", LOGL_INFO, 1}, + {"DNS", "\033[1;34m", "GPRS Network Service Protocol (NS)", LOGL_INFO, 1}, + {"DBSSGP", "\033[1;34m", "GPRS BSS Gateway Protocol (BSSGP)", LOGL_INFO, 1}, + {"DPCU", "\033[1;35m", "GPRS Packet Control Unit (PCU)", LOGL_NOTICE, 1}, +}; + +static int filter_fn(const struct log_context *ctx, + struct log_target *tar) +{ + return 1; +} + +/* To verify the result with expected result */ +int check_result(bitvec bits, uint8_t *exp_data, int exp_len) +{ + if (bits.cur_bit != exp_len) + return 0; + size_t n = (exp_len / 8); + int rem = (exp_len % 8); + + if (memcmp(exp_data, bits.data, n) == 0) { + if (rem == 0) + return 1; + if ((bits.data[n] & MASK(rem)) == ((*(exp_data + n)) & MASK(rem))) + return 1; + else + return 0; + } else + return 0; +} + +/* To test decoding of compressed bitmap by Tree based method + * and to verify the result with expected result + * for invalid input verfication is suppressed + */ +static void test_EPDAN_decode_tree(void) +{ + bitvec dest; + int init_flag = 1; + int itr; + int rc; + uint8_t bits_data[RLC_EGPRS_MAX_WS/8]; + + printf("=== start %s ===\n", __func__); + + for (itr = 0 ; itr < (sizeof(test) / sizeof(test_data)) ; itr++) { + dest.data = bits_data; + dest.data_len = sizeof(bits_data); + dest.cur_bit = 0; + memset(dest.data, 0, sizeof(bits_data)); + LOGP(DRLCMACDL, LOGL_DEBUG, "\nTest:%d\nTree based decoding:" + "\nuncompressed data = %s\nlen = %d\n", itr + 1, + osmo_hexdump(test[itr].crbb_data, + (test[itr].crbb_len + 7)/8), test[itr].crbb_len + ); + rc = decompress_crbb(test[itr].crbb_len, test[itr].cc, + test[itr].crbb_data, &dest + ); + if (rc < 0) { + LOGP(DRLCMACUL, LOGL_NOTICE, + "\nFailed to decode CRBB: length %d, data %s", + test[itr].crbb_len, osmo_hexdump( + test[itr].crbb_data, (test[itr].crbb_len + 7)/8)); + } + if (init_flag) + init_flag = 0; + if (test[itr].verify) { + if (check_result(dest, test[itr].ucmp_data, + test[itr].ucmp_len) == 0) { + LOGP(DRLCMACDL, LOGL_DEBUG, "\nTree based decoding" + ":Error\nexpected data = %s\nexpected" + " len = %d\ndecoded data = %s\n" + "decoded len = %d\n", + osmo_hexdump(test[itr].ucmp_data, + (test[itr].ucmp_len + 7)/8), + test[itr].ucmp_len, osmo_hexdump(dest.data, + (dest.cur_bit + 7)/8), dest.cur_bit + ); + OSMO_ASSERT(0); + } + } + LOGP(DRLCMACDL, LOGL_DEBUG, "\nexpected data = %s\nexpected len = %d" + "\ndecoded data = %s\ndecoded len = %d\n", + osmo_hexdump(test[itr].ucmp_data, + (test[itr].ucmp_len + 7)/8), + test[itr].ucmp_len, osmo_hexdump(dest.data, + (dest.cur_bit + 7)/8), dest.cur_bit + ); + } + + printf("=== end %s ===\n", __func__); +} + +const struct log_info debug_log_info = { + filter_fn, + (struct log_info_cat *)default_categories, + ARRAY_SIZE(default_categories), +}; + +int main(int argc, char **argv) +{ + struct vty_app_info pcu_vty_info = {0}; + + osmo_init_logging(&debug_log_info); + log_set_use_color(osmo_stderr_target, 0); + log_set_print_filename(osmo_stderr_target, 0); + bssgp_set_log_ss(DBSSGP); + + vty_init(&pcu_vty_info); + pcu_vty_init(&debug_log_info); + + tall_pcu_ctx = talloc_named_const(NULL, 1, "moiji-mobile TbfTest context"); + if (!tall_pcu_ctx) + abort(); + test_EPDAN_decode_tree(); + if (getenv("TALLOC_REPORT_FULL")) + talloc_report_full(tall_pcu_ctx, stderr); + talloc_free(tall_pcu_ctx); + return EXIT_SUCCESS; +} +/* + * stubs that should not be reached + */ +extern "C" { +void l1if_pdch_req() { abort(); } +void l1if_connect_pdch() { abort(); } +void l1if_close_pdch() { abort(); } +void l1if_open_pdch() { abort(); } +} + diff --git a/tests/bitcomp/BitcompTest.err b/tests/bitcomp/BitcompTest.err new file mode 100644 index 0000000..a9078d0 --- /dev/null +++ b/tests/bitcomp/BitcompTest.err @@ -0,0 +1,92 @@ + +Test:1 +Tree based decoding: +uncompressed data = 02 0c a0 30 cb 1a 0c e3 6c +len = 67 + +expected data = ff ff ff f8 00 00 01 ff ff ff f8 00 00 00 ff ff ff fe 00 00 3f ff ff ff db +expected len = 194 +decoded data = ff ff ff f8 00 00 01 ff ff ff f8 00 00 00 ff ff ff fe 00 00 3f ff ff ff db +decoded len = 194 + +Test:2 +Tree based decoding: +uncompressed data = 53 06 c5 40 6d +len = 40 + +expected data = ff ff ff ff ff ff c0 00 00 00 00 3f ff ff ff ff ff f8 00 00 00 00 03 +expected len = 182 +decoded data = ff ff ff ff ff ff c0 00 00 00 00 3f ff ff ff ff ff f8 00 00 00 00 03 +decoded len = 182 + +Test:3 +Tree based decoding: +uncompressed data = 02 +len = 8 + +expected data = ff ff ff f8 +expected len = 29 +decoded data = ff ff ff f8 +decoded len = 29 + +Test:4 +Tree based decoding: +uncompressed data = 02 0c e0 41 a0 0c 36 0d 03 71 b0 6e 24 +len = 103 + +expected data = ff ff ff f8 00 00 ff ff ff f8 00 00 7f ff ff fe 00 00 0f ff ff ff e0 00 00 7f ff ff ff 80 00 01 ff ff ff ff +expected len = 288 +decoded data = ff ff ff f8 00 00 ff ff ff f8 00 00 7f ff ff fe 00 00 0f ff ff ff e0 00 00 7f ff ff ff 80 00 01 ff ff ff ff +decoded len = 288 + +Test:5 +Tree based decoding: +uncompressed data = de 88 75 65 80 +len = 35 + +expected data = 37 47 81 f0 +expected len = 28 +decoded data = 37 47 81 f0 +decoded len = 28 + +Test:6 +Tree based decoding: +uncompressed data = dd 41 00 +len = 18 + +expected data = ff ff ff ff ff ff ff ff ff ff 00 00 +expected len = 90 +decoded data = ff ff ff ff ff ff ff ff ff ff 00 00 +decoded len = 90 + +Test:7 +Tree based decoding: +uncompressed data = 1e 70 c0 +len = 18 + +expected data = +expected len = 0 +decoded data = +decoded len = 19 + +Test:8 +Tree based decoding: +uncompressed data = 00 1e +len = 14 + +Failed to decode CRBB: length 14, data 00 1e +expected data = +expected len = 0 +decoded data = +decoded len = 0 + +Test:9 +Tree based decoding: +uncompressed data = 00 00 00 +len = 24 + +Failed to decode CRBB: length 24, data 00 00 00 +expected data = +expected len = 0 +decoded data = +decoded len = 0 diff --git a/tests/bitcomp/BitcompTest.ok b/tests/bitcomp/BitcompTest.ok new file mode 100644 index 0000000..f7720fc --- /dev/null +++ b/tests/bitcomp/BitcompTest.ok @@ -0,0 +1,2 @@ +=== start test_EPDAN_decode_tree === +=== end test_EPDAN_decode_tree === diff --git a/tests/testsuite.at b/tests/testsuite.at index 1049b31..3ab39cc 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -23,6 +23,14 @@ AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/tbf/TbfTest], [0], [expout], [experr]) AT_CLEANUP + +AT_SETUP([bitcomp]) +AT_KEYWORDS([bitcomp]) +cat $abs_srcdir/bitcomp/BitcompTest.ok > expout +cat $abs_srcdir/bitcomp/BitcompTest.err > experr +AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/bitcomp/BitcompTest], [0], [expout], [experr]) +AT_CLEANUP + AT_SETUP([edge]) AT_KEYWORDS([edge]) cat $abs_srcdir/edge/EdgeTest.ok > expout -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 19 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: pravin From gerrit-no-reply at lists.osmocom.org Mon Aug 22 10:59:07 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 10:59:07 +0000 Subject: osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Patch Set 18: (3 comments) https://gerrit.osmocom.org/#/c/416/18/src/egprs_rlc_compression.h File src/egprs_rlc_compression.h: Line 27: extern void *tall_pcu_ctx; > If I dont declare tall_pcu_ctx as an extern I'm not able to use it in a fil you should rather declare tall_pcu_ctx in the .cpp file then. https://gerrit.osmocom.org/#/c/416/18/tests/Makefile.am File tests/Makefile.am: Line 38: -Wl,-u,bssgp_prim_cb > If I remove GB and GSM . I am not able to use LOGP. I am getting error "und That might be because you apparently have copied the TbfTest and scaled it down, instead of building up a new test from scratch? I have taken a closer look and indeed you need far less linking and #including in this test than this patch proposes. Please take a look at branch neels/416 http://git.osmocom.org/osmo-pcu/log/?h=neels/416 where I have * far less and more concise #includes; * no vty (seems to be a speciality of TbfTest, our tests usually don't include a vty); * no linking of libgprs.a, but only the single cpp file needed. Hence I don't need to link libgb and libgsm there. Does that look ok to you? I have also dropped the Bitcomptest binary from your patch and indicated a whitespace error. (If you decide to use the branch, of course all should be submitted in one patch, not three.) https://gerrit.osmocom.org/#/c/416/19/tests/bitcomp/BitcompTest File tests/bitcomp/BitcompTest: You have committed the test binary! This must not be part of the commit, instead add the binary to .gitignore. -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 18 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: pravin Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Mon Aug 22 11:23:09 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Mon, 22 Aug 2016 11:23:09 +0000 Subject: [PATCH] osmo-pcu[master]: Describe the issue with EGPRS PUAN encoding In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/702 to look at the new patch set (#5). Describe the issue with EGPRS PUAN encoding This patch is related to bug https://osmocom.org/issues/1793 Currently PCU doesn?t encode EGPRS PUAN message for VQ not equal to VR case. This patch adds a test case which expects the current bug. Which is corrected in the subsequent commit related to this topic including the fix. Below is the Gerrit Id for the fix https://gerrit.osmocom.org/#/c/703. The test_tbf_puan_issue test describes the issue with initially sending the BSN 1 which generated the PUAN message as below 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b. Later test_tbf_puan_issue test sends BSN 4 and PUAN generated is below 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b which is same as previous PUAN message. Please see the Generated test file. This is considerable issue with OTA. Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 --- M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 3 files changed, 298 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/02/702/5 diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..5a73a43 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -618,6 +618,143 @@ &ulreq, tbf->poll_fn); } +static gprs_rlcmac_ul_tbf *puan_issue(BTS *the_bts, + uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, + uint8_t ms_class, uint8_t egprs_ms_class) +{ + GprsMs *ms; + uint32_t rach_fn = *fn - 51; + uint32_t sba_fn = *fn + 52; + uint8_t trx_no = 0; + int tfi = 0, i = 0; + gprs_rlcmac_ul_tbf *ul_tbf; + struct gprs_rlcmac_pdch *pdch; + gprs_rlcmac_bts *bts; + RlcMacUplink_t ulreq = {0}; + struct pcu_l1_meas meas; + struct gprs_rlc_ul_header_egprs_3 *egprs3 = NULL; + GprsCodingScheme cs; + + meas.set_rssi(31); + bts = the_bts->bts_data(); + + /* needed to set last_rts_fn in the PDCH object */ + request_dl_rlc_block(bts, trx_no, ts_no, fn); + + /* + * simulate RACH, this sends an Immediate + * Assignment Uplink on the AGCH + */ + the_bts->rcv_rach(0x73, rach_fn, qta); + + /* get next free TFI */ + tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1); + + /* fake a resource request */ + ulreq.u.MESSAGE_TYPE = MT_PACKET_RESOURCE_REQUEST; + ulreq.u.Packet_Resource_Request.PayloadType = GPRS_RLCMAC_CONTROL_BLOCK; + ulreq.u.Packet_Resource_Request.ID.UnionType = 1; /* != 0 */ + ulreq.u.Packet_Resource_Request.ID.u.TLLI = tlli; + ulreq.u.Packet_Resource_Request.Exist_MS_Radio_Access_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + Count_MS_RA_capability_value = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Exist_Multislot_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + Exist_GPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + GPRS_multislot_class = ms_class; + if (egprs_ms_class) { + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Multislot_capability.Exist_EGPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Multislot_capability.EGPRS_multislot_class = ms_class; + } + + send_ul_mac_block(the_bts, trx_no, ts_no, &ulreq, sba_fn); + + /* check the TBF */ + ul_tbf = the_bts->ul_tbf_by_tfi(tfi, trx_no, ts_no); + OSMO_ASSERT(ul_tbf); + OSMO_ASSERT(ul_tbf->ta() == qta / 4); + + /* send packet uplink assignment */ + *fn = sba_fn; + request_dl_rlc_block(ul_tbf, fn); + + /* send real acknowledgement */ + send_control_ack(ul_tbf); + + check_tbf(ul_tbf); + /* send fake data */ + uint8_t data_msg[42] = { + 0xf << 2, /* GPRS_RLCMAC_DATA_BLOCK << 6, CV = 15 */ + tfi << 1, + 1, /* BSN:7, E:1 */ + }; + + pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no]; + pdch->rcv_block(&data_msg[0], 23, *fn, &meas); + + ms = the_bts->ms_by_tlli(tlli); + OSMO_ASSERT(ms != NULL); + OSMO_ASSERT(ms->ta() == qta/4); + OSMO_ASSERT(ms->ul_tbf() == ul_tbf); + + /* + * TS 44.060, B.8.1 + * first seg received first, later second seg + */ + cs = GprsCodingScheme::MCS3; + egprs3 = (struct gprs_rlc_ul_header_egprs_3 *) data_msg; + egprs3->si = 0; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 1; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 0; + egprs3->pi = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + struct msgb *msg1 = ul_tbf->create_ul_ack(*fn, ts_no); + + egprs3->si = 0; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 4; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + struct msgb *msg2 = ul_tbf->create_ul_ack(*fn, ts_no); + + /* TODO: Need to modify the assert */ + OSMO_ASSERT(!memcmp(msg2->data, msg1->data, msg1->data_len)); + + return ul_tbf; +} + static gprs_rlcmac_ul_tbf *establish_ul_tbf_two_phase_spb(BTS *the_bts, uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, uint8_t ms_class, uint8_t egprs_ms_class) @@ -1631,6 +1768,41 @@ gprs_bssgp_destroy(); } +static void test_tbf_puan_issue(void) +{ + BTS the_bts; + int ts_no = 7; + uint32_t fn = 2654218; + uint16_t qta = 31; + uint32_t tlli = 0xf1223344; + const char *imsi = "0011223344"; + uint8_t ms_class = 1; + uint8_t egprs_ms_class = 1; + gprs_rlcmac_ul_tbf *ul_tbf; + GprsMs *ms; + uint8_t test_data[256]; + + printf("=== start %s ===\n", __func__); + + memset(test_data, 1, sizeof(test_data)); + + setup_bts(&the_bts, ts_no, 4); + the_bts.bts_data()->initial_mcs_dl = 9; + the_bts.bts_data()->egprs_enabled = 1; + + ul_tbf = puan_issue(&the_bts, ts_no, tlli, &fn, qta, + ms_class, egprs_ms_class); + + ms = ul_tbf->ms(); + fprintf(stderr, "Got '%s', TA=%d\n", ul_tbf->name(), ul_tbf->ta()); + fprintf(stderr, + "Got MS: TLLI = 0x%08x, TA = %d\n", ms->tlli(), ms->ta()); + + send_dl_data(&the_bts, tlli, imsi, test_data, sizeof(test_data)); + + printf("=== end %s ===\n", __func__); +} + static void test_tbf_egprs_two_phase_spb(void) { BTS the_bts; @@ -2071,6 +2243,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_puan_issue(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..aa8a087 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -5780,3 +5780,126 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654218 block=8 data=47 94 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +MS requests UL TBF on RACH, so we provide one: +MS requests single block allocation +RX: [PCU <- BTS] RACH qbit-ta=31 ra=0x73, Fn=2654167 (17,25,9), SBFn=2654270 +TX: Immediate Assignment Uplink (AGCH) + - TRX=0 (0) TS=7 TA=7 TSC=0 TFI=-1 USF=7 +Sending data request: trx=0 ts=0 sapi=2 arfcn=0 fn=0 block=0 data=2d 06 3f 10 0f 00 00 73 8b 29 07 00 c0 0c 5a 43 2b 2b 2b 2b 2b 2b 2b +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +MS requests UL TBF in packet resource request of single block, so we provide one: +MS supports EGPRS multislot class 1. +********** TBF starts here ********** +Allocating UL TBF: MS_CLASS=1/1 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 1 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 1 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign uplink TS=7 TFI=0 USF=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 00 +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=ASSIGN EGPRS) starting timer 3169. +Modifying MS object, UL TLLI: 0x00000000 -> 0xf1223344, not yet confirmed +Modifying MS object, TLLI = 0xf1223344, TA 0 -> 7 +Change control TS to 7 until assinment is complete. +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS)s start Packet Uplink Assignment (PACCH) ++++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++ +------------------------- TX : Packet Uplink Assignment ------------------------- +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS): Scheduling polling at FN 2654283 TS 7 +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS) changes state from ASSIGN to WAIT ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Scheduled UL Assignment polling on FN=2654283, TS=7 +Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) (TRX=0, TS=7) +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654270 block=8 data=4f 28 5e 24 46 68 90 f8 0a 39 00 00 88 00 08 2b 2b 2b 2b 2b 2b 2b 2b +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Packet Control Ack +TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) changes state from WAIT ASSIGN to FLOW +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=0 .. V(R)=0) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got CS-1 RLC data block: CV=15, BSN=0, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 0 storing in window (0..63) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 1 +- Taking block 0 out, raising V(Q) to 1 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=0 CV=15 +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1d 08 40 c1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=0, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=1) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=1, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 1 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 2 +- Taking block 1 out, raising V(Q) to 2 +- Assembling frames: (len=37) +-- Frame 1 starts at offset 0, length=37, is_complete=0 +- No gaps in received block, last block: BSN=1 CV=7 +Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) + - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 2, BOW, EOW +Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1d 20 40 c1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=0, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=2 .. V(R)=2) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=4, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 4 storing in window (2..65) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 5 +Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) + - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 5, BOW, EOW +Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got 'TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS)', TA=7 +Got MS: TLLI = 0xf1223344, TA = 7 +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=1/1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign downlink TS=7 TFI=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0xf1223344, TBF = TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 80 +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +Modifying MS object, TLLI: 0xf1223344 confirmed +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) [DOWNLINK] START +Modifying MS object, TLLI = 0xf1223344, IMSI '' -> '0011223344' +Send dowlink assignment on PACCH, because TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) exists +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) starting timer 0. +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) append diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..6b99857 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,5 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_puan_issue === +=== end test_tbf_puan_issue === -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 5 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Mon Aug 22 11:23:09 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Mon, 22 Aug 2016 11:23:09 +0000 Subject: [PATCH] osmo-pcu[master]: Fix EGPRS PUAN encoding: use correct urbb_len In-Reply-To: References: Message-ID: Hello Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/703 to look at the new patch set (#2). Fix EGPRS PUAN encoding: use correct urbb_len Earlier there was an incorrect encoding of PUAN when VQ is not equal VR case for EGPRS UL RLC window. The PCU was encoding the same PUAN message always irrespective of radio condition. This was a bottle neck for performance testing. Which has been fixed in this patch. "Related: OS#1793". unit test assertion in the previous commit is fixed in this patch. Change-Id: Iba7b1995028bd81749ffb080616b2ad5f2540d57 --- M src/encoding.cpp M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err 3 files changed, 5 insertions(+), 5 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/03/703/2 diff --git a/src/encoding.cpp b/src/encoding.cpp index 63049ac..41e0d10 100644 --- a/src/encoding.cpp +++ b/src/encoding.cpp @@ -575,7 +575,8 @@ eow = false; urbb_len = rest_bits - 9; /* TODO: use compression (see above) */ - } + } else + urbb_len = num_blocks; if (urbb_len + crbb_len == rest_bits) len = -1; diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 5a73a43..c423058 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -749,8 +749,7 @@ struct msgb *msg2 = ul_tbf->create_ul_ack(*fn, ts_no); - /* TODO: Need to modify the assert */ - OSMO_ASSERT(!memcmp(msg2->data, msg1->data, msg1->data_len)); + OSMO_ASSERT(memcmp(msg2->data, msg1->data, msg1->data_len)); return ul_tbf; } diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index aa8a087..fa0927c 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -5875,8 +5875,8 @@ TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - Raising V(R) to 5 Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) - - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 5, BOW, EOW -Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b + - EGPRS URBB, len = 2, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 5, BOW, EOW +Uplink Ack/Nack bit count 100, max 184, message = 40 24 01 3f 3e 24 46 68 90 88 b0 06 8b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b Got 'TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS)', TA=7 Got MS: TLLI = 0xf1223344, TA = 7 ********** TBF starts here ********** -- To view, visit https://gerrit.osmocom.org/703 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Iba7b1995028bd81749ffb080616b2ad5f2540d57 Gerrit-PatchSet: 2 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 22 11:28:40 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Mon, 22 Aug 2016 11:28:40 +0000 Subject: osmo-pcu[master]: Describe the issue with EGPRS PUAN encoding In-Reply-To: References: Message-ID: Patch Set 5: Holger & Neels, I have taken care of all the review comments raised for this patch series. Please have a look and merge to master if everything is fine. Thanks, Aravind Sirsikar -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 5 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 22 11:38:01 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 11:38:01 +0000 Subject: [PATCH] libosmocore[master]: osmo_sock_init(): include host and port in error messages Message-ID: Review at https://gerrit.osmocom.org/725 osmo_sock_init(): include host and port in error messages For programs like osmo-hnbgw with numerous sockets, the message that some unspecified connection was refused is not very helpful. Also output the host and port where an error occured. Instead of perror, use fprintf(stderr, ..., strerror()) to be able to include a format string and print host and port as passed to osmo_sock_init(). Change-Id: I8d0343f51310699b78fcb83fd76fd93764acf3dc --- M src/socket.c 1 file changed, 16 insertions(+), 5 deletions(-) git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/25/725/1 diff --git a/src/socket.c b/src/socket.c index 7e610bf..a36aee7 100644 --- a/src/socket.c +++ b/src/socket.c @@ -71,8 +71,11 @@ char portbuf[16]; if ((flags & (OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT)) == - (OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT)) + (OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT)) { + fprintf(stderr, "invalid: both bind and connect flags set:" + " %s:%u: %s\n", host, port); return -EINVAL; + } sprintf(portbuf, "%u", port); memset(&hints, 0, sizeof(struct addrinfo)); @@ -93,7 +96,8 @@ rc = getaddrinfo(host, portbuf, &hints, &result); if (rc != 0) { - perror("getaddrinfo returned NULL"); + fprintf(stderr, "getaddrinfo returned NULL: %s:%u: %s\n", + host, port, strerror(errno)); return -EINVAL; } @@ -109,7 +113,10 @@ continue; if (flags & OSMO_SOCK_F_NONBLOCK) { if (ioctl(sfd, FIONBIO, (unsigned char *)&on) < 0) { - perror("cannot set this socket unblocking"); + fprintf(stderr, + "cannot set this socket unblocking:" + " %s:%u: %s\n", + host, port, strerror(errno)); close(sfd); return -EINVAL; } @@ -122,7 +129,10 @@ rc = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); if (rc < 0) { - perror("cannot setsockopt socket"); + fprintf(stderr, + "cannot setsockopt socket:" + " %s:%u: %s\n", + host, port, strerror(errno)); break; } if (bind(sfd, rp->ai_addr, rp->ai_addrlen) != -1) @@ -133,7 +143,8 @@ freeaddrinfo(result); if (rp == NULL) { - perror("unable to connect/bind socket"); + fprintf(stderr, "unable to connect/bind socket: %s:%u: %s\n", + host, port, strerror(errno)); return -ENODEV; } -- To view, visit https://gerrit.osmocom.org/725 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I8d0343f51310699b78fcb83fd76fd93764acf3dc Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 22 11:52:37 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Mon, 22 Aug 2016 11:52:37 +0000 Subject: [PATCH] osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/655 to look at the new patch set (#21). Modify EGPRS DL TBF flow to support SPB Modify the EGPRS DL TBF flow to support Split block during Retx. This patch will also Upgrade the test suite with test cases to validate the EGPRS Downlink SPB for Retransmission Scenarios like MCS6->MCS3, MCS4->MCS1, MCS5->MCS2, MCS9->MCS3 MCS7->MCS2, MCS8->MCS3 have been simulated and Integration tested in NuRAN 1.0 hardware thoroughly. Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 --- M src/gprs_coding_scheme.h M src/pcu_main.cpp M src/pcu_vty.c M src/rlc.cpp M src/rlc.h M src/tbf.h M src/tbf_dl.cpp M tests/edge/EdgeTest.cpp M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 11 files changed, 958 insertions(+), 80 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/55/655/21 diff --git a/src/gprs_coding_scheme.h b/src/gprs_coding_scheme.h index 60a8e79..3b15372 100644 --- a/src/gprs_coding_scheme.h +++ b/src/gprs_coding_scheme.h @@ -113,7 +113,8 @@ static const char *modeName(Mode mode); static Scheme get_retx_mcs(const GprsCodingScheme mcs, - const GprsCodingScheme retx_mcs); + const GprsCodingScheme retx_mcs, + const unsigned arq_type); static enum Scheme egprs_mcs_retx_tbl[MAX_NUM_ARQ] [MAX_NUM_MCS][MAX_NUM_MCS]; @@ -232,8 +233,9 @@ } inline GprsCodingScheme::Scheme GprsCodingScheme::get_retx_mcs( const GprsCodingScheme mcs, - const GprsCodingScheme demanded_mcs) + const GprsCodingScheme demanded_mcs, + const unsigned arq_type) { - return egprs_mcs_retx_tbl[EGPRS_ARQ2][mcs.to_num() - 1] + return egprs_mcs_retx_tbl[arq_type][mcs.to_num() - 1] [demanded_mcs.to_num() - 1]; } diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2d86cda..e34d534 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -210,6 +210,12 @@ bts->dl_tbf_idle_msec = 2000; bts->llc_idle_ack_csec = 10; + /* + * By default resegmentation is supported in DL + * can also be configured through VTY + */ + bts->dl_arq_type = EGPRS_ARQ1; + msgb_set_talloc_ctx(tall_pcu_ctx); osmo_init_logging(&gprs_log_info); diff --git a/src/pcu_vty.c b/src/pcu_vty.c index 58fea99..e550544 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -129,6 +129,10 @@ vty_out(vty, " window-size %d %d%s", bts->ws_base, bts->ws_pdch, VTY_NEWLINE); + if (bts->dl_arq_type) + vty_out(vty, " egprs dl arq-type %s%s", "arq2", + VTY_NEWLINE); + if (bts->force_llc_lifetime == 0xffff) vty_out(vty, " queue lifetime infinite%s", VTY_NEWLINE); else if (bts->force_llc_lifetime) @@ -476,6 +480,25 @@ bts->max_mcs_dl = 0; bts->max_mcs_ul = 0; + + return CMD_SUCCESS; +} + +#define DL_STR "DL specific configuration\n" + +DEFUN(cfg_pcu_dl_arq_type, + cfg_pcu_dl_arq_cmd, + "egprs dl arq-type (spb|arq2)", + EGPRS_STR DL_STR "ARQ options\n" + "enable SPB(ARQ1) support\n" + "enable ARQ2 support") +{ + struct gprs_rlcmac_bts *bts = bts_main_data(); + + if (!strcmp(argv[0], "arq2")) + bts->dl_arq_type = 1; + else + bts->dl_arq_type = 0; return CMD_SUCCESS; } @@ -954,6 +977,7 @@ install_element(PCU_NODE, &cfg_pcu_no_cs_downgrade_thrsh_cmd); install_element(PCU_NODE, &cfg_pcu_cs_lqual_ranges_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_cmd); + install_element(PCU_NODE, &cfg_pcu_dl_arq_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_max_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_max_cmd); diff --git a/src/rlc.cpp b/src/rlc.cpp index 6770043..e69d1fc 100644 --- a/src/rlc.cpp +++ b/src/rlc.cpp @@ -285,7 +285,8 @@ } static void gprs_rlc_data_header_init(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding, unsigned int header_bits) + GprsCodingScheme cs, bool with_padding, unsigned int header_bits, + const unsigned int spb) { unsigned int i; unsigned int padding_bits = with_padding ? cs.optionalPaddingBits() : 0; @@ -300,7 +301,7 @@ for (i = 0; i < rlc->num_data_blocks; i++) { gprs_rlc_data_block_info_init(&rlc->block_info[i], cs, - with_padding); + with_padding, spb); rlc->data_offs_bits[i] = header_bits + padding_bits + @@ -310,21 +311,25 @@ } void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsDL()); + cs.numDataHeaderBitsDL(), spb); } void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding) { + /* + * last parameter is sent as 0 since common function used + * for both DL and UL + */ return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsUL()); + cs.numDataHeaderBitsUL(), 0); } void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { unsigned int data_len = cs.maxDataBlockBytes(); if (with_padding) @@ -336,7 +341,7 @@ rdbi->e = 1; rdbi->cv = 15; rdbi->pi = 0; - rdbi->spb = 0; + rdbi->spb = spb; } unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, @@ -411,8 +416,18 @@ enum egprs_puncturing_values gprs_get_punct_scheme( enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current) + const GprsCodingScheme &cs_current, + const enum egprs_rlcmac_dl_spb spb) { + + /* + * 10.4.8b of TS 44.060 + * If it is second segment of the block + * dont change the puncturing scheme + */ + if (spb == EGPRS_RLCMAC_DL_SEC_SEG) + return punct; + /* TS 44.060 9.3.2.1.1 */ if ((GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS9) && (GprsCodingScheme::Scheme(cs_current) == GprsCodingScheme::MCS6)) { diff --git a/src/rlc.h b/src/rlc.h index b1a1fba..b693418 100644 --- a/src/rlc.h +++ b/src/rlc.h @@ -213,18 +213,19 @@ }; void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding); void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, enum egprs_puncturing_values punct, enum egprs_puncturing_values punct2, int with_padding); void gprs_rlc_mcs_cps_decode(unsigned int cps, GprsCodingScheme cs, int *punct, int *punct2, int *with_padding); enum egprs_puncturing_values gprs_get_punct_scheme(enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current_trans); + const GprsCodingScheme &cs_current_trans, + const enum egprs_rlcmac_dl_spb spb); void gprs_update_punct_scheme(enum egprs_puncturing_values *punct, const GprsCodingScheme &cs); /* diff --git a/src/tbf.h b/src/tbf.h index 1bd7878..2a1bfe8 100644 --- a/src/tbf.h +++ b/src/tbf.h @@ -421,6 +421,11 @@ int analyse_errors(char *show_rbb, uint8_t ssn, ana_result *res); void schedule_next_frame(); + enum egprs_rlc_dl_reseg_bsn_state egprs_dl_get_data + (int bsn, uint8_t **block_data); + unsigned int get_egprs_dl_spb_status(int bsn); + enum egprs_rlcmac_dl_spb get_egprs_dl_spb(int bsn); + struct osmo_timer_list m_llc_timer; }; diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp index 07a747a..a24cc21 100644 --- a/src/tbf_dl.cpp +++ b/src/tbf_dl.cpp @@ -375,21 +375,28 @@ return -1; if (is_egprs_enabled()) { + /* Table 8.1.1.2 and Table 8.1.1.1 of 44.060 */ m_rlc.block(bsn)->cs_current_trans = - GprsCodingScheme::get_retx_mcs( - m_rlc.block(bsn)->cs_last, ms()->current_cs_dl()); + GprsCodingScheme::get_retx_mcs( + m_rlc.block(bsn)->cs_init, + ms()->current_cs_dl(), + bts->bts_data()->dl_arq_type); LOGP(DRLCMACDL, LOGL_DEBUG, - "- current_cs_dl(%d) demanded_mcs(%d) cs_trans(%d)\n", - m_rlc.block(bsn)->cs_last.to_num(), - ms()->current_cs_dl().to_num(), - m_rlc.block(bsn)->cs_current_trans.to_num()); + "- initial_cs_dl(%d) last_mcs(%d)" + " demanded_mcs(%d) cs_trans(%d)" + " arq_type(%d) bsn(%d)\n", + m_rlc.block(bsn)->cs_init.to_num(), + m_rlc.block(bsn)->cs_last.to_num(), + ms()->current_cs_dl().to_num(), + m_rlc.block(bsn)->cs_current_trans.to_num(), + bts->bts_data()->dl_arq_type, bsn); /* TODO: Need to remove this check when MCS-8 -> MCS-6 * transistion is handled. * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 */ - if (m_rlc.block(bsn)->cs_last == GprsCodingScheme::MCS8) + if (m_rlc.block(bsn)->cs_init == GprsCodingScheme::MCS8) m_rlc.block(bsn)->cs_current_trans = GprsCodingScheme::MCS8; } else @@ -523,6 +530,11 @@ data = rlc_data->prepare(block_data_len); rlc_data->cs_last = cs; rlc_data->cs_current_trans = cs; + + /* Initialise the variable related to DL SPB */ + rlc_data->spb_status.block_status_dl = EGPRS_RESEG_DL_DEFAULT; + rlc_data->cs_init = cs; + rlc_data->len = block_data_len; rdbi = &(rlc_data->block_info); @@ -616,7 +628,8 @@ unsigned num_bsns; enum egprs_puncturing_values punct[ARRAY_SIZE(rlc.block_info)]; bool need_padding = false; - + enum egprs_rlcmac_dl_spb spb = EGPRS_RLCMAC_DL_NO_RETX; + unsigned int spb_status = get_egprs_dl_spb_status(index); /* * TODO: This is an experimental work-around to put 2 BSN into * MSC-7 to MCS-9 encoded messages. It just sends the same BSN @@ -626,6 +639,7 @@ * the current limit. */ cs = m_rlc.block(index)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(index)->cs_init; bsns[0] = index; num_bsns = 1; @@ -634,7 +648,17 @@ num_bsns += 1; } - if (num_bsns == 1) { + /* + * if the intial mcs is 8 and retransmission mcs is either 6 or 3 + * we have to include the padding of 6 octets in first segment + */ + if ((GprsCodingScheme::Scheme(cs_init) == GprsCodingScheme::MCS8) && + (GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS6 || + GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS3)) { + if (spb_status == EGPRS_RESEG_DL_DEFAULT || + spb_status == EGPRS_RESEG_SECOND_SEG_SENT) + need_padding = true; + } else if (num_bsns == 1) { /* TODO: remove the conditional when MCS-6 padding isn't * failing to be decoded by MEs anymore */ /* TODO: support of MCS-8 -> MCS-6 transition should be @@ -646,7 +670,14 @@ cs.decToSingleBlock(&need_padding); } - gprs_rlc_data_info_init_dl(&rlc, cs, need_padding); + spb = get_egprs_dl_spb(index); + + LOGP(DRLCMACDL, LOGL_DEBUG, "- need_padding %d spb_status %d spb %d" + "(BSN1 %d BSN2 %d)\n", + need_padding, + spb_status, spb, index, index2); + + gprs_rlc_data_info_init_dl(&rlc, cs, need_padding, spb); rlc.usf = 7; /* will be set at scheduler */ rlc.pr = 0; /* FIXME: power reduction */ @@ -665,10 +696,9 @@ data_block_idx++) { int bsn; - GprsCodingScheme cs_enc; uint8_t *block_data; gprs_rlc_data_block_info *rdbi, *block_info; - enum egprs_puncturing_values punct_scheme; + enum egprs_rlc_dl_reseg_bsn_state reseg_status; /* Check if there are more blocks than BSNs */ if (data_block_idx < num_bsns) @@ -676,38 +706,43 @@ else bsn = bsns[0]; - cs_enc = m_rlc.block(bsn)->cs_current_trans; - /* get data and header from current block */ - block_data = m_rlc.block(bsn)->block; - /* Get current puncturing scheme from block */ - punct_scheme = gprs_get_punct_scheme( + + m_rlc.block(bsn)->next_ps = gprs_get_punct_scheme( m_rlc.block(bsn)->next_ps, - m_rlc.block(bsn)->cs_last, cs); + m_rlc.block(bsn)->cs_last, cs, spb); if (cs.isEgprs()) { - OSMO_ASSERT(punct_scheme >= EGPRS_PS_1); - OSMO_ASSERT(punct_scheme <= EGPRS_PS_3); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps >= EGPRS_PS_1); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps <= EGPRS_PS_3); } - punct[data_block_idx] = punct_scheme; + punct[data_block_idx] = m_rlc.block(bsn)->next_ps; rdbi = &rlc.block_info[data_block_idx]; block_info = &m_rlc.block(bsn)->block_info; - if(rdbi->data_len != m_rlc.block(bsn)->len) { - LOGP(DRLCMACDL, LOGL_ERROR, - "ERROR: Expected len = %d for %s instead of " - "%d in data unit %d (BSN %d, %s)\n", - rdbi->data_len, cs.name(), m_rlc.block(bsn)->len, - data_block_idx, bsn, cs_enc.name()); - OSMO_ASSERT(rdbi->data_len == m_rlc.block(bsn)->len); - } - - /* TODO: Need to handle 2 same bsns - * in header type 1 + /* + * get data and header from current block + * function returns the reseg status */ - gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, - cs); + reseg_status = egprs_dl_get_data(bsn, &block_data); + m_rlc.block(bsn)->spb_status.block_status_dl = reseg_status; + + /* + * If it is first segment of the split block set the state of + * bsn to nacked. If it is the first segment dont update the + * next ps value of bsn. since next segment also needs same cps + */ + if (spb == EGPRS_RLCMAC_DL_FIRST_SEG) + m_window.m_v_b.mark_nacked(bsn); + else { + /* + * TODO: Need to handle 2 same bsns + * in header type 1 + */ + gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, + cs); + } m_rlc.block(bsn)->cs_last = cs; rdbi->e = block_info->e; @@ -1169,3 +1204,118 @@ keep_time_frames = msecs_to_frames(bts_data()->dl_tbf_idle_msec); return frames_since_last_drain(fn) <= keep_time_frames; } + +/* + * This function returns the pointer to data which needs + * to be copied. Also updates the status of the block related to + * Split block handling in the RLC/MAC block. + */ +enum egprs_rlc_dl_reseg_bsn_state + gprs_rlcmac_dl_tbf::egprs_dl_get_data(int bsn, uint8_t **block_data) +{ + gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state *block_status_dl = + &rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + *block_data = &rlc_data->block[0]; + + /* + * Table 10.3a.0.1 of 44.060 + * MCS6,9: second segment starts at 74/2 = 37 + * MCS5,7: second segment starts at 56/2 = 28 + * MCS8: second segment starts at 31 + * MCS4: second segment starts at 44/2 = 22 + */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + if (*block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + switch (GprsCodingScheme::Scheme(cs_init)) { + case GprsCodingScheme::MCS6 : + case GprsCodingScheme::MCS9 : + *block_data = &rlc_data->block[37]; + break; + case GprsCodingScheme::MCS7 : + case GprsCodingScheme::MCS5 : + *block_data = &rlc_data->block[28]; + break; + case GprsCodingScheme::MCS8 : + *block_data = &rlc_data->block[31]; + break; + case GprsCodingScheme::MCS4 : + *block_data = &rlc_data->block[22]; + break; + default: + LOGP(DRLCMACDL, LOGL_ERROR, "Software error: " + "--%s hit invalid condition. headerType(%d) " + " blockstatus(%d) cs(%s) PLEASE FIX!\n", name(), + cs_current_trans.headerTypeData(), + *block_status_dl, cs_init.name()); + break; + + } + return EGPRS_RESEG_SECOND_SEG_SENT; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } + } + return EGPRS_RESEG_DL_DEFAULT; +} + +/* + * This function returns the status of split block + * for RLC/MAC block. + */ +unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_status(const int bsn) +{ + const gprs_rlc_data *rlc_data = m_rlc.block(bsn); + + return rlc_data->spb_status.block_status_dl; +} + +/* + * This function returns the spb value to be sent OTA + * for RLC/MAC block. + */ +enum egprs_rlcmac_dl_spb gprs_rlcmac_dl_tbf::get_egprs_dl_spb(const int bsn) +{ + struct gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state block_status_dl = + rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + + /* Table 10.4.8b.1 of 44.060 */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + /* + * if we are sending the second segment the spb should be 3 + * other wise it should be 2 + */ + if (block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + return EGPRS_RLCMAC_DL_SEC_SEG; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RLCMAC_DL_FIRST_SEG; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RLCMAC_DL_FIRST_SEG; + } + } + /* Non SPB cases 0 is reurned */ + return EGPRS_RLCMAC_DL_NO_RETX; +} diff --git a/tests/edge/EdgeTest.cpp b/tests/edge/EdgeTest.cpp index 807102c..9081d4d 100644 --- a/tests/edge/EdgeTest.cpp +++ b/tests/edge/EdgeTest.cpp @@ -517,7 +517,7 @@ /* TS 44.060, B.1 */ cs = GprsCodingScheme::CS4; - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -570,7 +570,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -592,7 +592,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -630,7 +630,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -669,7 +669,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -694,7 +694,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -719,7 +719,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -740,7 +740,7 @@ OSMO_ASSERT(data[0] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -777,7 +777,7 @@ cs = GprsCodingScheme::MCS4; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -835,7 +835,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -872,7 +872,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -923,7 +923,7 @@ OSMO_ASSERT(data[3] == 0); /* Block 3 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -967,7 +967,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -993,7 +993,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1020,7 +1020,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1074,7 +1074,7 @@ block_idx++) { struct gprs_rlc_data_info rlc; - gprs_rlc_data_info_init_dl(&rlc, cs, false); + gprs_rlc_data_info_init_dl(&rlc, cs, false, 0); memset(bits, pattern, sizeof(bits)); Decoding::rlc_copy_to_aligned_buffer( @@ -1118,12 +1118,14 @@ struct gprs_rlc_data_info rlc; printf("=== start %s ===\n", __func__); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::CS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::CS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 24); OSMO_ASSERT(rlc.block_info[0].data_len == 20); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::MCS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::MCS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 33); OSMO_ASSERT(rlc.block_info[0].data_len == 22); diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..5e45506 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -1814,6 +1814,203 @@ } +static void egprs_spb_to_normal_validation(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + uint16_t bsn1, bsn2, bsn3; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + struct gprs_rlc_dl_header_egprs_2 *egprs2; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + if (!(mcs == 6 && demanded_mcs == 3)) + return; + + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + bsn1 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) + || (egprs2->bsn1_lo); + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(bsn1 == 0); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + bsn2 = (egprs3->bsn1_hi << 9) || (egprs3->bsn1_mid << 1) || + (egprs3->bsn1_lo); + OSMO_ASSERT(bsn2 == bsn1); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Handle (MCS3, MCS3) -> MCS6 case */ + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + mcs)); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs2->cps == 0); + bsn3 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) || + (egprs2->bsn1_lo); + OSMO_ASSERT(bsn3 == bsn2); + + tbf_cleanup(dl_tbf); +} +static void establish_and_use_egprs_dl_tbf_for_spb(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + /* TODO: Need to support of MCS8 -> MCS6 ->MCS3 transistion + * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 + * dated 2016-02-07 23:45:40 (UTC) + */ + if (!(((mcs == 5) && (demanded_mcs == 2)) || + ((mcs == 6) && (demanded_mcs == 3)) || + ((mcs == 4) && (demanded_mcs == 1)))) + return; + + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + tbf_cleanup(dl_tbf); +} + static void establish_and_use_egprs_dl_tbf_for_retx(BTS *the_bts, int mcs, int demanded_mcs) { @@ -1972,6 +2169,9 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; + /* First parameter is current MCS, second one is demanded_mcs */ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 6); @@ -1981,6 +2181,38 @@ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 9); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 7, 5); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 9, 6); + + printf("=== end %s ===\n", __func__); +} + +static void test_tbf_egprs_spb_dl(void) +{ + BTS the_bts; + gprs_rlcmac_bts *bts; + uint8_t ts_no = 4; + int i, j; + + printf("=== start %s ===\n", __func__); + + bts = the_bts.bts_data(); + bts->cs_downgrade_threshold = 0; + setup_bts(&the_bts, ts_no); + bts->dl_tbf_idle_msec = 200; + bts->egprs_enabled = 1; + + /* ARQ I resegmentation support */ + bts->dl_arq_type = EGPRS_ARQ1; + + /* + * First parameter is current MCS, second one is demanded_mcs + * currently only MCS5->MCS2, MCS6->3, MCS4->MCS1 is tested in UT + * rest scenarios has been integration tested + */ + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 6, 3); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 5, 2); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 4, 1); + /* check MCS6->(MCS3+MCS3)->MCS6 case */ + egprs_spb_to_normal_validation(&the_bts, 6, 3); printf("=== end %s ===\n", __func__); } @@ -1999,6 +2231,8 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; for (i = 1; i <= 9; i++) establish_and_use_egprs_dl_tbf(&the_bts, i); @@ -2071,6 +2305,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_egprs_spb_dl(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..1ba4189 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -72,6 +72,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -81,6 +82,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -157,6 +159,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -166,6 +169,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -242,6 +246,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -251,6 +256,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -259,6 +265,7 @@ - Sending new block at BSN 2, CS=CS-1 -- Chunk with length 160 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=13 block=3 data=07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b @@ -267,6 +274,7 @@ - Sending new block at BSN 3, CS=CS-1 -- Chunk with length 140 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=17 block=4 data=07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @@ -275,6 +283,7 @@ - Sending new block at BSN 4, CS=CS-1 -- Chunk with length 120 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=21 block=5 data=07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 @@ -283,6 +292,7 @@ - Sending new block at BSN 5, CS=CS-1 -- Chunk with length 100 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=26 block=6 data=07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 @@ -291,6 +301,7 @@ - Sending new block at BSN 6, CS=CS-1 -- Chunk with length 80 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=30 block=7 data=07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b @@ -299,6 +310,7 @@ - Sending new block at BSN 7, CS=CS-1 -- Chunk with length 60 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=34 block=8 data=07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f @@ -307,6 +319,7 @@ - Sending new block at BSN 8, CS=CS-1 -- Chunk with length 40 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=39 block=9 data=07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 @@ -315,6 +328,7 @@ - Sending new block at BSN 9, CS=CS-1 -- Chunk with length 20 would exactly fit into space (20): add length header with LI=0, to make frame extend to next block, and we are done data block (BSN 9, CS-1): 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=43 block=10 data=07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 @@ -326,6 +340,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=47 block=11 data=07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 @@ -334,6 +349,7 @@ - Sending new block at BSN 11, CS=CS-1 -- Chunk with length 182 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=52 block=0 data=07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 @@ -342,6 +358,7 @@ - Sending new block at BSN 12, CS=CS-1 -- Chunk with length 162 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=56 block=1 data=07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 @@ -350,6 +367,7 @@ - Sending new block at BSN 13, CS=CS-1 -- Chunk with length 142 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 13, CS-1): 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=60 block=2 data=07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d @@ -358,6 +376,7 @@ - Sending new block at BSN 14, CS=CS-1 -- Chunk with length 122 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=65 block=3 data=07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 @@ -366,6 +385,7 @@ - Sending new block at BSN 15, CS=CS-1 -- Chunk with length 102 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=69 block=4 data=07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 @@ -374,6 +394,7 @@ - Sending new block at BSN 16, CS=CS-1 -- Chunk with length 82 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=73 block=5 data=07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 @@ -382,6 +403,7 @@ - Sending new block at BSN 17, CS=CS-1 -- Chunk with length 62 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=78 block=6 data=07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d @@ -390,6 +412,7 @@ - Sending new block at BSN 18, CS=CS-1 -- Chunk with length 42 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=82 block=7 data=07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 @@ -398,6 +421,7 @@ - Sending new block at BSN 19, CS=CS-1 -- Chunk with length 22 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=86 block=8 data=07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 @@ -411,6 +435,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=16 data block (BSN 20, CS-1): 0a 41 c6 c7 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -449,6 +474,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 data block (BSN 21, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -468,6 +494,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 22, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FINISHED) @@ -1481,6 +1508,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 0, CS-1): 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 MSG = 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 @@ -1491,6 +1519,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 1, CS-1): 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 MSG = 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 @@ -1501,6 +1530,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FINISHED data block (BSN 2, CS-1): 4d 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling cannot be scheduled in this TS 7 (first control TS 4) @@ -1784,6 +1814,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=10 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 0, CS-4): 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654292 TS 7 @@ -1797,6 +1828,7 @@ TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) downlink (V(A)==0 .. V(S)==1) - Restarting at BSN 0, because all blocks have been transmitted. - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-4): 07 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 @@ -2365,6 +2397,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654279 block=10 data=00 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 @@ -2384,6 +2417,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -2406,6 +2440,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654288 block=0 data=00 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 @@ -2425,6 +2460,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654292 block=1 data=00 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2447,6 +2483,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654296 block=2 data=00 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c @@ -2466,6 +2503,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654301 block=3 data=00 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b @@ -2488,6 +2526,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 6, CS-1): 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654305 block=4 data=00 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 @@ -2507,6 +2546,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654309 block=5 data=00 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 @@ -2526,6 +2566,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654314 block=6 data=00 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 @@ -2548,6 +2589,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654318 block=7 data=00 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 @@ -2567,6 +2609,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654322 block=8 data=00 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2589,6 +2632,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654327 block=9 data=00 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c @@ -2608,6 +2652,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654331 block=10 data=00 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b @@ -2630,6 +2675,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 13, CS-1): 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654335 block=11 data=00 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 @@ -2649,6 +2695,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654340 block=0 data=00 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 @@ -2668,6 +2715,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654344 block=1 data=00 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 @@ -2690,6 +2738,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654348 block=2 data=00 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 @@ -2709,6 +2758,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654353 block=3 data=00 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2731,6 +2781,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654357 block=4 data=00 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c @@ -2750,6 +2801,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654361 block=5 data=00 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b @@ -2772,6 +2824,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 20, CS-1): 16 35 45 54 20 32 38 4c 4c 43 20 50 41 43 4b 45 54 20 32 39 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because 20 blocks sent. TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW): Scheduling polling at FN 2654379 TS 7 @@ -2795,6 +2848,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 21, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) msg block (BSN 21, CS-1): 07 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654370 block=7 data=00 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 @@ -2814,6 +2868,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 22, CS-1): 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) msg block (BSN 22, CS-1): 07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654374 block=8 data=07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 @@ -2836,6 +2891,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 23, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) msg block (BSN 23, CS-1): 07 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654379 block=9 data=00 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 @@ -2855,6 +2911,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 24, CS-1): 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) msg block (BSN 24, CS-1): 07 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654383 block=10 data=00 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2877,6 +2934,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 25, CS-1): 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 25 BSN2 -1) - Copying data unit 0 (BSN 25) msg block (BSN 25, CS-1): 07 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654387 block=11 data=00 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c @@ -2896,6 +2954,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 26, CS-1): 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 26 BSN2 -1) - Copying data unit 0 (BSN 26) msg block (BSN 26, CS-1): 07 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654392 block=0 data=00 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b @@ -2918,6 +2977,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 27, CS-1): 16 35 45 54 20 33 38 4c 4c 43 20 50 41 43 4b 45 54 20 33 39 +- need_padding 0 spb_status 0 spb 0(BSN1 27 BSN2 -1) - Copying data unit 0 (BSN 27) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) @@ -3028,6 +3088,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654405 block=3 data=00 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 @@ -3047,6 +3108,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654409 block=4 data=00 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 @@ -3066,6 +3128,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (16) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654413 block=5 data=00 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 @@ -3085,6 +3148,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (14) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654418 block=6 data=00 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 @@ -3104,6 +3168,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654422 block=7 data=00 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -3123,6 +3188,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654426 block=8 data=00 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 @@ -3142,6 +3208,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654431 block=9 data=00 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b @@ -3161,6 +3228,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654435 block=10 data=00 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 @@ -3180,6 +3248,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654439 block=11 data=00 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 @@ -3199,6 +3268,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654444 block=0 data=00 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c @@ -3218,6 +3288,7 @@ Complete DL frame for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=21 TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 10, CS-1): 4d 43 20 50 41 43 4b 45 54 20 30 39 20 28 54 42 46 20 32 29 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654461 TS 7 @@ -3698,6 +3769,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 0, MCS-1): 14 15 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3711,6 +3783,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3721,6 +3794,7 @@ - Sending new block at BSN 2, CS=MCS-1 -- Chunk with length 490 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3731,6 +3805,7 @@ - Sending new block at BSN 3, CS=MCS-1 -- Chunk with length 468 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3741,6 +3816,7 @@ - Sending new block at BSN 4, CS=MCS-1 -- Chunk with length 446 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3751,6 +3827,7 @@ - Sending new block at BSN 5, CS=MCS-1 -- Chunk with length 424 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3761,6 +3838,7 @@ - Sending new block at BSN 6, CS=MCS-1 -- Chunk with length 402 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3771,6 +3849,7 @@ - Sending new block at BSN 7, CS=MCS-1 -- Chunk with length 380 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3781,6 +3860,7 @@ - Sending new block at BSN 8, CS=MCS-1 -- Chunk with length 358 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3791,6 +3871,7 @@ - Sending new block at BSN 9, CS=MCS-1 -- Chunk with length 336 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3801,6 +3882,7 @@ - Sending new block at BSN 10, CS=MCS-1 -- Chunk with length 314 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3811,6 +3893,7 @@ - Sending new block at BSN 11, CS=MCS-1 -- Chunk with length 292 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3821,6 +3904,7 @@ - Sending new block at BSN 12, CS=MCS-1 -- Chunk with length 270 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3831,6 +3915,7 @@ - Sending new block at BSN 13, CS=MCS-1 -- Chunk with length 248 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3841,6 +3926,7 @@ - Sending new block at BSN 14, CS=MCS-1 -- Chunk with length 226 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3851,6 +3937,7 @@ - Sending new block at BSN 15, CS=MCS-1 -- Chunk with length 204 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3861,6 +3948,7 @@ - Sending new block at BSN 16, CS=MCS-1 -- Chunk with length 182 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3871,6 +3959,7 @@ - Sending new block at BSN 17, CS=MCS-1 -- Chunk with length 160 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3881,6 +3970,7 @@ - Sending new block at BSN 18, CS=MCS-1 -- Chunk with length 138 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3891,6 +3981,7 @@ - Sending new block at BSN 19, CS=MCS-1 -- Chunk with length 116 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 19, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3901,6 +3992,7 @@ - Sending new block at BSN 20, CS=MCS-1 -- Chunk with length 94 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 20, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3911,6 +4003,7 @@ - Sending new block at BSN 21, CS=MCS-1 -- Chunk with length 72 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 21, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3921,6 +4014,7 @@ - Sending new block at BSN 22, CS=MCS-1 -- Chunk with length 50 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 22, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3931,6 +4025,7 @@ - Sending new block at BSN 23, CS=MCS-1 -- Chunk with length 28 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 23, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3946,6 +4041,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 24, MCS-1): 0c 1d 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4006,6 +4102,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=16 data block (BSN 0, MCS-2): 14 21 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4019,6 +4116,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4029,6 +4127,7 @@ - Sending new block at BSN 2, CS=MCS-2 -- Chunk with length 484 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4039,6 +4138,7 @@ - Sending new block at BSN 3, CS=MCS-2 -- Chunk with length 456 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4049,6 +4149,7 @@ - Sending new block at BSN 4, CS=MCS-2 -- Chunk with length 428 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4059,6 +4160,7 @@ - Sending new block at BSN 5, CS=MCS-2 -- Chunk with length 400 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4069,6 +4171,7 @@ - Sending new block at BSN 6, CS=MCS-2 -- Chunk with length 372 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4079,6 +4182,7 @@ - Sending new block at BSN 7, CS=MCS-2 -- Chunk with length 344 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4089,6 +4193,7 @@ - Sending new block at BSN 8, CS=MCS-2 -- Chunk with length 316 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4099,6 +4204,7 @@ - Sending new block at BSN 9, CS=MCS-2 -- Chunk with length 288 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4109,6 +4215,7 @@ - Sending new block at BSN 10, CS=MCS-2 -- Chunk with length 260 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4119,6 +4226,7 @@ - Sending new block at BSN 11, CS=MCS-2 -- Chunk with length 232 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4129,6 +4237,7 @@ - Sending new block at BSN 12, CS=MCS-2 -- Chunk with length 204 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4139,6 +4248,7 @@ - Sending new block at BSN 13, CS=MCS-2 -- Chunk with length 176 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4149,6 +4259,7 @@ - Sending new block at BSN 14, CS=MCS-2 -- Chunk with length 148 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4159,6 +4270,7 @@ - Sending new block at BSN 15, CS=MCS-2 -- Chunk with length 120 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4169,6 +4281,7 @@ - Sending new block at BSN 16, CS=MCS-2 -- Chunk with length 92 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4179,6 +4292,7 @@ - Sending new block at BSN 17, CS=MCS-2 -- Chunk with length 64 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4189,6 +4303,7 @@ - Sending new block at BSN 18, CS=MCS-2 -- Chunk with length 36 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4204,6 +4319,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=18 data block (BSN 19, MCS-2): 10 25 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4264,6 +4380,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=25 data block (BSN 0, MCS-3): 14 33 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4277,6 +4394,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4287,6 +4405,7 @@ - Sending new block at BSN 2, CS=MCS-3 -- Chunk with length 475 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4297,6 +4416,7 @@ - Sending new block at BSN 3, CS=MCS-3 -- Chunk with length 438 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4307,6 +4427,7 @@ - Sending new block at BSN 4, CS=MCS-3 -- Chunk with length 401 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4317,6 +4438,7 @@ - Sending new block at BSN 5, CS=MCS-3 -- Chunk with length 364 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4327,6 +4449,7 @@ - Sending new block at BSN 6, CS=MCS-3 -- Chunk with length 327 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4337,6 +4460,7 @@ - Sending new block at BSN 7, CS=MCS-3 -- Chunk with length 290 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4347,6 +4471,7 @@ - Sending new block at BSN 8, CS=MCS-3 -- Chunk with length 253 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4357,6 +4482,7 @@ - Sending new block at BSN 9, CS=MCS-3 -- Chunk with length 216 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4367,6 +4493,7 @@ - Sending new block at BSN 10, CS=MCS-3 -- Chunk with length 179 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4377,6 +4504,7 @@ - Sending new block at BSN 11, CS=MCS-3 -- Chunk with length 142 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4387,6 +4515,7 @@ - Sending new block at BSN 12, CS=MCS-3 -- Chunk with length 105 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4397,6 +4526,7 @@ - Sending new block at BSN 13, CS=MCS-3 -- Chunk with length 68 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4410,6 +4540,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-3): 3f 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4425,6 +4556,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=34 data block (BSN 15, MCS-3): 02 45 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4485,6 +4617,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=32 data block (BSN 0, MCS-4): 14 41 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4498,6 +4631,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4508,6 +4642,7 @@ - Sending new block at BSN 2, CS=MCS-4 -- Chunk with length 468 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4518,6 +4653,7 @@ - Sending new block at BSN 3, CS=MCS-4 -- Chunk with length 424 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4528,6 +4664,7 @@ - Sending new block at BSN 4, CS=MCS-4 -- Chunk with length 380 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4538,6 +4675,7 @@ - Sending new block at BSN 5, CS=MCS-4 -- Chunk with length 336 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4548,6 +4686,7 @@ - Sending new block at BSN 6, CS=MCS-4 -- Chunk with length 292 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4558,6 +4697,7 @@ - Sending new block at BSN 7, CS=MCS-4 -- Chunk with length 248 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4568,6 +4708,7 @@ - Sending new block at BSN 8, CS=MCS-4 -- Chunk with length 204 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4578,6 +4719,7 @@ - Sending new block at BSN 9, CS=MCS-4 -- Chunk with length 160 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4588,6 +4730,7 @@ - Sending new block at BSN 10, CS=MCS-4 -- Chunk with length 116 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4598,6 +4741,7 @@ - Sending new block at BSN 11, CS=MCS-4 -- Chunk with length 72 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4613,6 +4757,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 12, MCS-4): 38 1d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4673,6 +4818,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-5): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4686,6 +4832,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4696,6 +4843,7 @@ - Sending new block at BSN 2, CS=MCS-5 -- Chunk with length 456 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4706,6 +4854,7 @@ - Sending new block at BSN 3, CS=MCS-5 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4716,6 +4865,7 @@ - Sending new block at BSN 4, CS=MCS-5 -- Chunk with length 344 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4726,6 +4876,7 @@ - Sending new block at BSN 5, CS=MCS-5 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4736,6 +4887,7 @@ - Sending new block at BSN 6, CS=MCS-5 -- Chunk with length 232 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4746,6 +4898,7 @@ - Sending new block at BSN 7, CS=MCS-5 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4756,6 +4909,7 @@ - Sending new block at BSN 8, CS=MCS-5 -- Chunk with length 120 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4766,6 +4920,7 @@ - Sending new block at BSN 9, CS=MCS-5 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4781,6 +4936,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-5): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4841,6 +4997,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-6): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4854,6 +5011,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4864,6 +5022,7 @@ - Sending new block at BSN 2, CS=MCS-6 -- Chunk with length 438 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4874,6 +5033,7 @@ - Sending new block at BSN 3, CS=MCS-6 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4884,6 +5044,7 @@ - Sending new block at BSN 4, CS=MCS-6 -- Chunk with length 290 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4894,6 +5055,7 @@ - Sending new block at BSN 5, CS=MCS-6 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4904,6 +5066,7 @@ - Sending new block at BSN 6, CS=MCS-6 -- Chunk with length 142 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4917,6 +5080,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-6): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4932,6 +5096,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-6): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4993,6 +5158,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-7): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5002,12 +5168,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(7) last_mcs(5) demanded_mcs(7) cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-7 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5022,6 +5189,7 @@ - Sending new block at BSN 3, CS=MCS-7 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5036,6 +5204,7 @@ - Sending new block at BSN 5, CS=MCS-7 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5050,6 +5219,7 @@ - Sending new block at BSN 7, CS=MCS-7 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5064,6 +5234,7 @@ - Sending new block at BSN 9, CS=MCS-7 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 9) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5081,6 +5252,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-7): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5142,6 +5314,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=56 data block (BSN 0, MCS-8): 14 71 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5152,12 +5325,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(8) demanded_mcs(8) cs_trans(8) +- initial_cs_dl(8) last_mcs(8) demanded_mcs(8) cs_trans(8) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-8 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5172,6 +5346,7 @@ - Sending new block at BSN 3, CS=MCS-8 -- Chunk with length 376 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5186,6 +5361,7 @@ - Sending new block at BSN 5, CS=MCS-8 -- Chunk with length 240 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5200,6 +5376,7 @@ - Sending new block at BSN 7, CS=MCS-8 -- Chunk with length 104 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5217,6 +5394,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=30 data block (BSN 8, MCS-8): 48 3d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5279,6 +5457,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-9): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5288,12 +5467,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(9) last_mcs(6) demanded_mcs(9) cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-9 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5308,6 +5488,7 @@ - Sending new block at BSN 3, CS=MCS-9 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5322,6 +5503,7 @@ - Sending new block at BSN 5, CS=MCS-9 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5339,6 +5521,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-9): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5356,6 +5539,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-9): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5402,11 +5586,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(6) cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5450,11 +5636,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 96 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(1) demanded_mcs(1) cs_trans(1) +- initial_cs_dl(1) last_mcs(1) demanded_mcs(1) cs_trans(1) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 98 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5498,11 +5686,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-2): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 92 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(2) demanded_mcs(2) cs_trans(2) +- initial_cs_dl(2) last_mcs(2) demanded_mcs(2) cs_trans(2) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 94 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5546,6 +5736,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5557,6 +5748,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-5): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5564,10 +5756,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-5): 0f 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7) cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7) cs_trans(7) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-7): 07 00 00 02 c0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 @@ -5612,6 +5805,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5623,6 +5817,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-6): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5630,10 +5825,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-6): 0f 40 00 00 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9) cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9) cs_trans(9) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-9): 07 00 00 02 28 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 @@ -5686,6 +5882,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-7): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5694,13 +5891,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-7): 0f 00 00 02 a0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5) cs_trans(5) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5) cs_trans(5) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-5): 07 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5752,6 +5951,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-9): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5760,13 +5960,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-9): 0f 00 00 02 00 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6) cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6) cs_trans(6) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-6): 07 40 00 02 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5780,3 +5982,233 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-5 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(2) cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 d2 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(2) demanded_mcs(2) cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 f2 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-4 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (44) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-4): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-4): 07 00 00 80 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(4) demanded_mcs(1) cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 d6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(1) demanded_mcs(1) cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 f6 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(6) cs_trans(6) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 2 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..c38417d 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,9 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_egprs_spb_dl === +Testing retx for MCS 6 to reseg_mcs 3 +Testing retx for MCS 5 to reseg_mcs 2 +Testing retx for MCS 4 to reseg_mcs 1 +Testing retx for MCS 6 to reseg_mcs 3 +=== end test_tbf_egprs_spb_dl === -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 21 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Mon Aug 22 11:56:03 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Mon, 22 Aug 2016 11:56:03 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 21: (1 comment) https://gerrit.osmocom.org/#/c/655/15/src/pcu_vty.c File src/pcu_vty.c: Line 490: cfg_pcu_dl_arq_cmd, > I think the problem is that you use EGPRS_STR (intended for all commands st Hi Harald, Thanks for helping me out. I have modified as per your suggestion. Please have a look. @Neels: Please review the updated changes. Thanks, Aravind Sirsikar -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 21 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Mon Aug 22 12:02:48 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Mon, 22 Aug 2016 12:02:48 +0000 Subject: osmo-pcu[master]: Remove warning while using 'egprs only' command in VTY In-Reply-To: References: Message-ID: Patch Set 1: Hi Holger, > Can you please clarify? Yes. You are right with both the queries about EGPRS limitation. But the command is related to EGPRS ONLY. So when "egprs only" is enabled we see no issue related to EGPRS call. so the warning for "egprs only" command is in appropriate. Please let me know if any other queries. Thanks, Aravind Sirsikar -- To view, visit https://gerrit.osmocom.org/704 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I62278f998adc691b9a3563ac2a46d756e7bfb66c Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 22 12:36:05 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 12:36:05 +0000 Subject: [PATCH] openbsc[master]: cosmetic: gprs_sgsn.c: move pdp.h include to top Message-ID: Review at https://gerrit.osmocom.org/726 cosmetic: gprs_sgsn.c: move pdp.h include to top Change-Id: I9a9b34d714235462ba72cdb65b7c8c9824dfa9c6 --- M openbsc/src/gprs/gprs_sgsn.c 1 file changed, 2 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/26/726/1 diff --git a/openbsc/src/gprs/gprs_sgsn.c b/openbsc/src/gprs/gprs_sgsn.c index 502ba4a..147facf 100644 --- a/openbsc/src/gprs/gprs_sgsn.c +++ b/openbsc/src/gprs/gprs_sgsn.c @@ -40,6 +40,8 @@ #include #include "openbsc/gprs_llc.h" +#include + #include #include @@ -333,7 +335,6 @@ return pdp; } -#include /* * This function will not trigger any GSM DEACT PDP ACK messages, so you * probably want to call sgsn_delete_pdp_ctx() instead if the connection -- To view, visit https://gerrit.osmocom.org/726 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I9a9b34d714235462ba72cdb65b7c8c9824dfa9c6 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Mon Aug 22 12:36:05 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 12:36:05 +0000 Subject: [PATCH] openbsc[master]: gprs_gmm: Fix bit mask when determining update/attach type Message-ID: Review at https://gerrit.osmocom.org/727 gprs_gmm: Fix bit mask when determining update/attach type Bit 4 is reserved in 3GPP TS 04.08 so exclude it from the type. In 3GPP TS 24.008 it indicates if a follow-on request is pending by the MS, but only in Iu mode. According to the spec it is not required to react to that request with a follow-on proceed so this field can be ignored for now. See 3GPP TS 24.008 Ch. 4.4: "Unless it has specific permission from the network (follow-on proceed) the mobile station side should await the release of the RR connection used for a MM specific procedure before a new MM specific procedure or MM connection establishment is started." as well as Ch. 4.4.4.6: "If the network wishes to prolong the RR connection to allow the mobile station to initiate MM connection establishment (for example if the mobile station has indicated in the LOCATION UPDATING REQUEST that it has a follow-on request pending) the network shall send "follow on proceed" in the LOCATION UPDATING ACCEPT and start timer T3255." Change-Id: If1dff960c406060e257dafc54132687ffc42ad8f --- M openbsc/src/gprs/gprs_gmm.c 1 file changed, 6 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/27/727/1 diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index aa49919..d4cf896 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -872,8 +872,10 @@ goto err_inval; cur += msnc_len; + /* TODO: In iu mode - handle follow-on request */ + /* aTTACH Type 10.5.5.2 */ - att_type = *cur++ & 0x0f; + att_type = *cur++ & 0x07; /* DRX parameter 10.5.5.6 */ drx_par = *cur++ << 8; @@ -1169,8 +1171,10 @@ enum gsm48_gmm_cause reject_cause; int rc; + /* TODO: In iu mode - handle follow-on request */ + /* Update Type 10.5.5.18 */ - upd_type = *cur++ & 0x0f; + upd_type = *cur++ & 0x07; rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ROUTING_AREA_REQUEST]); LOGP(DMM, LOGL_INFO, "-> GMM RA UPDATE REQUEST type=\"%s\"\n", -- To view, visit https://gerrit.osmocom.org/727 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: If1dff960c406060e257dafc54132687ffc42ad8f Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: daniel Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Mon Aug 22 12:36:05 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 12:36:05 +0000 Subject: [PATCH] openbsc[master]: IuPS: track msg->dst aka ue_conn_ctx, comment Message-ID: Review at https://gerrit.osmocom.org/728 IuPS: track msg->dst aka ue_conn_ctx, comment For Iu connections, msg->dst will point to the ue_conn_ctx, and we need to make sure to keep msg->dst intact when copying from/to msgb and from/to MM context. Change-Id: I90c7ca6c3655d447aaca958e0086ae6ce6f6045a --- M openbsc/src/gprs/gprs_gmm.c 1 file changed, 4 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/28/728/1 diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index d4cf896..1a030fb 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -148,6 +148,7 @@ msgb_tlli(msg) = msgb_tlli(old); msgb_bvci(msg) = msgb_bvci(old); msgb_nsei(msg) = msgb_nsei(old); + msg->dst = old->dst; } /* Store BVCI/NSEI in MM context */ @@ -155,6 +156,8 @@ { mm->gb.bvci = msgb_bvci(msg); mm->gb.nsei = msgb_nsei(msg); + /* In case a Iu connection is reconnected we need to update the ue ctx */ + mm->iu.ue_ctx = msg->dst; } /* Store BVCI/NSEI in MM context */ @@ -163,6 +166,7 @@ msgb_tlli(msg) = mm->gb.tlli; msgb_bvci(msg) = mm->gb.bvci; msgb_nsei(msg) = mm->gb.nsei; + msg->dst = mm->iu.ue_ctx; } static void mm_ctx_cleanup_free(struct sgsn_mm_ctx *ctx, const char *log_text) -- To view, visit https://gerrit.osmocom.org/728 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I90c7ca6c3655d447aaca958e0086ae6ce6f6045a Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: daniel Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Mon Aug 22 12:36:06 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 12:36:06 +0000 Subject: [PATCH] openbsc[master]: IuPS: osmo-sgsn: add core IuPS impl, call iu_init() Message-ID: Review at https://gerrit.osmocom.org/729 IuPS: osmo-sgsn: add core IuPS impl, call iu_init() Add: * gsm0408_gprs_rcvmsg_iu() * sgsn_mm_ctx_by_ue_ctx() * sgsn_mm_ctx_alloc_iu() * sgsn_ranap_iu_event() * sgsn_ranap_rab_ass_resp() Call iu_init() from sgsn_main.c. Add asn_debug impl ("extern" from libasn1c). osmo-sgsn build: add libiu and libasn1c, libosmo-sigtran, libosmo-ranap Change-Id: I469ae6ca9ef254d04ee0d2d79bdd65aebcd027b5 --- M openbsc/include/openbsc/gprs_gmm.h M openbsc/include/openbsc/gprs_sgsn.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/gprs_gmm.c M openbsc/src/gprs/gprs_sgsn.c M openbsc/src/gprs/sgsn_libgtp.c M openbsc/src/gprs/sgsn_main.c 7 files changed, 233 insertions(+), 3 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/29/729/1 diff --git a/openbsc/include/openbsc/gprs_gmm.h b/openbsc/include/openbsc/gprs_gmm.h index 8a3ffea..28467d7 100644 --- a/openbsc/include/openbsc/gprs_gmm.h +++ b/openbsc/include/openbsc/gprs_gmm.h @@ -14,6 +14,8 @@ int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme, bool drop_cipherable); +int gsm0408_gprs_rcvmsg_iu(struct msgb *msg, struct gprs_ra_id *ra_id, + uint16_t *sai); int gsm0408_gprs_force_reattach(struct sgsn_mm_ctx *mmctx); int gsm0408_gprs_force_reattach_oldmsg(struct msgb *msg, struct gprs_llc_llme *llme); diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h index b0dd75f..18cbab8 100644 --- a/openbsc/include/openbsc/gprs_sgsn.h +++ b/openbsc/include/openbsc/gprs_sgsn.h @@ -226,6 +226,7 @@ const struct gprs_ra_id *raid); struct sgsn_mm_ctx *sgsn_mm_ctx_by_ptmsi(uint32_t tmsi); struct sgsn_mm_ctx *sgsn_mm_ctx_by_imsi(const char *imsi); +struct sgsn_mm_ctx *sgsn_mm_ctx_by_ue_ctx(const void *uectx); /* look-up by matching TLLI and P-TMSI (think twice before using this) */ struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli_and_ptmsi(uint32_t tlli, @@ -234,6 +235,8 @@ /* Allocate a new SGSN MM context */ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t tlli, const struct gprs_ra_id *raid); +struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_iu(void *uectx); + void sgsn_mm_ctx_cleanup_free(struct sgsn_mm_ctx *ctx); struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx, diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 6dc7e16..cc135f7 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -3,6 +3,10 @@ $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOCTRL_CFLAGS) \ $(LIBOSMOABIS_CFLAGS) $(LIBOSMOGB_CFLAGS) $(COVERAGE_CFLAGS) \ $(LIBCARES_CFLAGS) $(LIBCRYPTO_CFLAGS) $(LIBGTP_CFLAGS) +if BUILD_IU +AM_CFLAGS += $(LIBASN1C_CFLAGS) $(LIBOSMOSIGTRAN_CFLAGS) $(LIBOSMORANAP_CFLAGS) +endif + OSMO_LIBS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) \ $(LIBOSMOCTRL_LIBS) $(LIBOSMOGB_LIBS) @@ -30,9 +34,15 @@ sgsn_cdr.c sgsn_ares.c \ oap.c oap_messages.c osmo_sgsn_LDADD = \ - $(top_builddir)/src/libcommon/libcommon.a \ - -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ + $(top_builddir)/src/libcommon/libcommon.a +if BUILD_IU +osmo_sgsn_LDADD += $(top_builddir)/src/libiu/libiu.a +endif +osmo_sgsn_LDADD += -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ $(LIBCRYPTO_LIBS) -lrt +if BUILD_IU +osmo_sgsn_LDADD += $(LIBOSMOSIGTRAN_LIBS) $(LIBOSMORANAP_LIBS) $(LIBASN1C_LIBS) +endif osmo_gtphub_SOURCES = gtphub_main.c gtphub.c gtphub_sock.c gtphub_ares.c \ gtphub_vty.c sgsn_ares.c gprs_utils.c diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index 1a030fb..e67ee10 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -33,6 +33,8 @@ #include +#include "bscconfig.h" + #include #include #include @@ -44,6 +46,10 @@ #include #include + +#ifdef BUILD_IU +#include +#endif #include #include @@ -57,6 +63,10 @@ #include #include #include + +#ifdef BUILD_IU +#include +#endif #include @@ -96,6 +106,45 @@ }; static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx); + +#ifdef BUILD_IU +int sgsn_ranap_rab_ass_resp(struct sgsn_mm_ctx *ctx, RANAP_RAB_SetupOrModifiedItemIEs_t *setup_ies); +int sgsn_ranap_iu_event(struct ue_conn_ctx *ctx, enum iu_event_type type, void *data) +{ + struct sgsn_mm_ctx *mm; + int rc = -1; + + mm = sgsn_mm_ctx_by_ue_ctx(ctx); + if (!mm) { + LOGP(DRANAP, LOGL_NOTICE, "Cannot find mm ctx for IU event %i!\n", type); + return rc; + } + + switch (type) { + case IU_EVENT_RAB_ASSIGN: + rc = sgsn_ranap_rab_ass_resp(mm, (RANAP_RAB_SetupOrModifiedItemIEs_t *)data); + break; + case IU_EVENT_IU_RELEASE: + /* fall thru */ + case IU_EVENT_LINK_INVALIDATED: + /* Clean up ue_conn_ctx here */ + LOGMMCTXP(LOGL_INFO, mm, "IU release for imsi %s\n", mm->imsi); + rc = 0; + break; + case IU_EVENT_SECURITY_MODE_COMPLETE: + /* Continue authentication here */ + mm->iu.ue_ctx->integrity_active = 1; + rc = gsm48_gmm_authorize(mm); + break; + default: + LOGP(DRANAP, LOGL_NOTICE, "Unknown event received: %i\n", type); + rc = -1; + break; + } + return rc; +} +#endif + /* Our implementation, should be kept in SGSN */ @@ -2191,6 +2240,45 @@ return rc; } +/* Main entry point for incoming 04.08 GPRS messages from Iu */ +int gsm0408_gprs_rcvmsg_iu(struct msgb *msg, struct gprs_ra_id *ra_id, + uint16_t *sai) +{ + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); + uint8_t pdisc = gsm48_hdr_pdisc(gh); + struct sgsn_mm_ctx *mmctx; + int rc = -EINVAL; + + mmctx = sgsn_mm_ctx_by_ue_ctx(msg->dst); + if (mmctx) { + rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]); + if (ra_id) + memcpy(&mmctx->ra, ra_id, sizeof(mmctx->ra)); + } + + /* MMCTX can be NULL */ + + switch (pdisc) { + case GSM48_PDISC_MM_GPRS: + rc = gsm0408_rcv_gmm(mmctx, msg, NULL, false); +#warning "set drop_cipherable arg for gsm0408_rcv_gmm() from IuPS?" + break; + case GSM48_PDISC_SM_GPRS: + rc = gsm0408_rcv_gsm(mmctx, msg, NULL); + break; + default: + LOGMMCTXP(LOGL_NOTICE, mmctx, + "Unknown GSM 04.08 discriminator 0x%02x: %s\n", + pdisc, osmo_hexdump((uint8_t *)gh, msgb_l3len(msg))); + /* FIXME: return status message */ + break; + } + + /* MMCTX can be invalid */ + + return rc; +} + /* Main entry point for incoming 04.08 GPRS messages from Gb */ int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme, bool drop_cipherable) diff --git a/openbsc/src/gprs/gprs_sgsn.c b/openbsc/src/gprs/gprs_sgsn.c index 147facf..4036025 100644 --- a/openbsc/src/gprs/gprs_sgsn.c +++ b/openbsc/src/gprs/gprs_sgsn.c @@ -39,6 +39,7 @@ #include #include #include "openbsc/gprs_llc.h" +#include #include @@ -124,6 +125,20 @@ void sgsn_rate_ctr_init() { sgsn->rate_ctrs = rate_ctr_group_alloc(tall_bsc_ctx, &sgsn_ctrg_desc, 0); +} + +/* look-up an SGSN MM context based on Iu UE context (struct ue_conn_ctx)*/ +struct sgsn_mm_ctx *sgsn_mm_ctx_by_ue_ctx(const void *uectx) +{ + struct sgsn_mm_ctx *ctx; + + llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) { + if (ctx->ran_type == MM_CTX_T_UTRAN_Iu + && uectx == ctx->iu.ue_ctx) + return ctx; + } + + return NULL; } /* look-up a SGSN MM context based on TLLI + RAI */ @@ -214,6 +229,32 @@ return ctx; } +/* Allocate a new SGSN MM context */ +struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_iu(void *uectx) +{ + struct sgsn_mm_ctx *ctx; + + ctx = talloc_zero(tall_bsc_ctx, struct sgsn_mm_ctx); + if (!ctx) + return NULL; + + ctx->ran_type = MM_CTX_T_UTRAN_Iu; + ctx->iu.ue_ctx = uectx; + ctx->mm_state = GMM_DEREGISTERED; + ctx->auth_triplet.key_seq = GSM_KEY_SEQ_INVAL; + ctx->ctrg = rate_ctr_group_alloc(ctx, &mmctx_ctrg_desc, 0); + + /* Need to get RAID from IU conn */ + ctx->ra = ctx->iu.ue_ctx->ra_id; + + INIT_LLIST_HEAD(&ctx->pdp_list); + + llist_add(&ctx->list, &sgsn_mm_ctxts); + + return ctx; +} + + /* this is a hard _free_ function, it doesn't clean up the PDP contexts * in libgtp! */ static void sgsn_mm_ctx_free(struct sgsn_mm_ctx *mm) diff --git a/openbsc/src/gprs/sgsn_libgtp.c b/openbsc/src/gprs/sgsn_libgtp.c index be7637a..4a14cf6 100644 --- a/openbsc/src/gprs/sgsn_libgtp.c +++ b/openbsc/src/gprs/sgsn_libgtp.c @@ -34,6 +34,8 @@ #include #include +#include "bscconfig.h" + #include #include #include @@ -47,6 +49,11 @@ #include #include #include + +#ifdef BUILD_IU +#include +#include +#endif #include #include @@ -218,7 +225,10 @@ memcpy(pdp->gsnlc.v, &sgsn->cfg.gtp_listenaddr.sin_addr, sizeof(sgsn->cfg.gtp_listenaddr.sin_addr)); - /* SGSN address for user plane */ + /* SGSN address for user plane + * Default to the control plane addr for now. If we are connected to a + * hnbgw via IuPS we'll need to send a PDP context update with the + * correct IP address after the RAB Assignment is complete */ pdp->gsnlu.l = sizeof(sgsn->cfg.gtp_listenaddr.sin_addr); memcpy(pdp->gsnlu.v, &sgsn->cfg.gtp_listenaddr.sin_addr, sizeof(sgsn->cfg.gtp_listenaddr.sin_addr)); @@ -383,6 +393,72 @@ return EOF; } +#ifdef BUILD_IU +/* Callback for RAB assignment response */ +int sgsn_ranap_rab_ass_resp(struct sgsn_mm_ctx *ctx, RANAP_RAB_SetupOrModifiedItemIEs_t *setup_ies) +{ + uint8_t rab_id; + bool require_pdp_update = false; + struct sgsn_pdp_ctx *pdp = NULL; + RANAP_RAB_SetupOrModifiedItem_t *item = &setup_ies->raB_SetupOrModifiedItem; + + rab_id = item->rAB_ID.buf[0]; + + pdp = sgsn_pdp_ctx_by_nsapi(ctx, rab_id); + if (!pdp) { + LOGP(DRANAP, LOGL_ERROR, "RAB Assignment Response for unknown RAB/NSAPI=%u\n", rab_id); + return -1; + } + + if (item->transportLayerAddress) { + LOGPC(DRANAP, LOGL_INFO, " Setup: (%u/%s)", rab_id, osmo_hexdump(item->transportLayerAddress->buf, + item->transportLayerAddress->size)); + switch (item->transportLayerAddress->size) { + case 7: + /* It must be IPv4 inside a X213 NSAP */ + memcpy(pdp->lib->gsnlu.v, &item->transportLayerAddress->buf[3], 4); + break; + case 4: + /* It must be a raw IPv4 address */ + memcpy(pdp->lib->gsnlu.v, item->transportLayerAddress->buf, 4); + break; + case 16: + /* TODO: It must be a raw IPv6 address */ + case 19: + /* TODO: It must be IPv6 inside a X213 NSAP */ + default: + LOGP(DRANAP, LOGL_ERROR, "RAB Assignment Resp: Unknown " + "transport layer address size %u\n", + item->transportLayerAddress->size); + return -1; + } + require_pdp_update = true; + } + + /* The TEI on the RNC side might have changed, too */ + if (item->iuTransportAssociation && + item->iuTransportAssociation->present == RANAP_IuTransportAssociation_PR_gTP_TEI && + item->iuTransportAssociation->choice.gTP_TEI.buf && + item->iuTransportAssociation->choice.gTP_TEI.size >= 4) { + uint32_t tei = osmo_load32be(item->iuTransportAssociation->choice.gTP_TEI.buf); + LOGP(DRANAP, LOGL_DEBUG, "Updating TEID on RNC side from 0x%08x to 0x%08x\n", + pdp->lib->teid_own, tei); + pdp->lib->teid_own = tei; + require_pdp_update = true; + } + + if (require_pdp_update) + gtp_update_context(pdp->ggsn->gsn, pdp->lib, pdp, &pdp->lib->hisaddr0); + + if (pdp->state != PDP_STATE_CR_CONF) { + send_act_pdp_cont_acc(pdp); + pdp->state = PDP_STATE_CR_CONF; + } + return 0; + +} +#endif + /* Confirmation of a PDP Context Delete */ static int delete_pdp_conf(struct pdp_t *pdp, void *cbp, int cause) { diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c index 52fc985..18adde5 100644 --- a/openbsc/src/gprs/sgsn_main.c +++ b/openbsc/src/gprs/sgsn_main.c @@ -56,6 +56,8 @@ #include #include #include +#include + #include #include @@ -300,6 +302,9 @@ .num_cat = ARRAY_SIZE(gprs_categories), }; +int asn_debug; + +int sgsn_ranap_iu_event(struct ue_conn_ctx *ctx, enum iu_event_type type, void *data); int main(int argc, char **argv) { @@ -417,6 +422,11 @@ } } + asn_debug = 0; +#ifdef BUILD_IU + iu_init(tall_bsc_ctx, "127.0.0.2", 14001, gsm0408_gprs_rcvmsg_iu, sgsn_ranap_iu_event); +#endif + if (daemonize) { rc = osmo_daemonize(); if (rc < 0) { -- To view, visit https://gerrit.osmocom.org/729 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I469ae6ca9ef254d04ee0d2d79bdd65aebcd027b5 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: daniel Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Mon Aug 22 12:36:06 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 12:36:06 +0000 Subject: [PATCH] openbsc[master]: IuPS: sgsn-test: link Iu related libs Message-ID: Review at https://gerrit.osmocom.org/730 IuPS: sgsn-test: link Iu related libs Add libiu and libasn1c, libosmo-sigtran, libosmo-ranap. So far they are unused, this is preparing for a subsequent commit that introduces calls to iu_tx(). Change-Id: I4c05f15c29797456ddcd7c95bfb7dfd480101577 --- M openbsc/tests/sgsn/Makefile.am 1 file changed, 10 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/30/730/1 diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index b6036c7..025e2c9 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -1,5 +1,8 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) +if BUILD_IU +AM_CFLAGS += $(LIBASN1C_CFLAGS) $(LIBOSMOSIGTRAN_CFLAGS) $(LIBOSMORANAP_CFLAGS) +endif EXTRA_DIST = sgsn_test.ok @@ -38,4 +41,11 @@ $(LIBCARES_LIBS) \ $(LIBCRYPTO_LIBS) \ -lgtp -lrt +if BUILD_IU +sgsn_test_LDADD += \ + $(top_builddir)/src/libiu/libiu.a \ + $(LIBOSMORANAP_LIBS) \ + $(LIBOSMOSIGTRAN_LIBS) \ + $(LIBASN1C_LIBS) +endif -- To view, visit https://gerrit.osmocom.org/730 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I4c05f15c29797456ddcd7c95bfb7dfd480101577 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: daniel Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Mon Aug 22 12:36:06 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 12:36:06 +0000 Subject: [PATCH] openbsc[master]: IuPS: redirect Iu in various places Message-ID: Review at https://gerrit.osmocom.org/731 IuPS: redirect Iu in various places In gsm48_gmm_sendmsg(), redirect to iu_tx() for both cases of MM context present or not. In gsm48_rx_gmm_att_req(), compose an MM context marked as Iu for messages coming in from a ue_conn_ctx (passed in msg->dst). Also make sure cid is initialized to avoid introducing a compiler warning. In gsm48_rx_gmm_ra_upd_req(), look up an Iu MM context based on the presence of the ue_conn_ctx in msg->dst. Change-Id: Ia47ffbfa6fa0f5a0cd76a379c57ef42faa0d80e3 --- M openbsc/src/gprs/gprs_gmm.c 1 file changed, 55 insertions(+), 6 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/31/731/1 diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index e67ee10..0ec5a23 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -183,8 +183,21 @@ static int gsm48_gmm_sendmsg(struct msgb *msg, int command, struct sgsn_mm_ctx *mm, bool encryptable) { - if (mm) + if (mm) { rate_ctr_inc(&mm->ctrg->ctr[GMM_CTR_PKTS_SIG_OUT]); +#ifdef BUILD_IU + if (mm->ran_type == MM_CTX_T_UTRAN_Iu) + return iu_tx(msg, GPRS_SAPI_GMM); +#endif + } + +#ifdef BUILD_IU + /* In Iu mode, msg->dst contains the ue_conn_ctx pointer, in Gb mode + * dst is empty. */ + /* FIXME: have a more explicit indicator for Iu messages */ + if (msg->dst) + return iu_tx(msg, GPRS_SAPI_GMM); +#endif /* caller needs to provide TLLI, BVCI and NSEI */ return gprs_llc_tx_ui(msg, GPRS_SAPI_GMM, command, mm, encryptable); @@ -905,7 +918,7 @@ uint32_t tmsi; char mi_string[GSM48_MI_SIZE]; struct gprs_ra_id ra_id; - uint16_t cid; + uint16_t cid = 0; enum gsm48_gmm_cause reject_cause; int rc; @@ -916,7 +929,13 @@ * with a foreign TLLI (P-TMSI that was allocated to the MS before), * or with random TLLI. */ - cid = bssgp_parse_cell_id(&ra_id, msgb_bcid(msg)); + /* In Iu mode, msg->dst contains the ue_conn_ctx pointer, in Gb mode + * dst is empty. */ + /* FIXME: have a more explicit indicator for Iu messages */ + if (!msg->dst) { + /* Gb mode */ + cid = bssgp_parse_cell_id(&ra_id, msgb_bcid(msg)); + } /* MS network capability 10.5.5.12 */ msnc_len = *cur++; @@ -970,7 +989,10 @@ #if 0 return gsm48_tx_gmm_att_rej(msg, GMM_CAUSE_IMSI_UNKNOWN); #else - ctx = sgsn_mm_ctx_alloc(0, &ra_id); + if (msg->dst) + ctx = sgsn_mm_ctx_alloc_iu(msg->dst); + else + ctx = sgsn_mm_ctx_alloc(0, &ra_id); if (!ctx) { reject_cause = GMM_CAUSE_NET_FAIL; goto rejected; @@ -993,7 +1015,10 @@ if (!ctx) { /* Allocate a context as most of our code expects one. * Context will not have an IMSI ultil ID RESP is received */ - ctx = sgsn_mm_ctx_alloc(msgb_tlli(msg), &ra_id); + if (msg->dst) + ctx = sgsn_mm_ctx_alloc_iu(msg->dst); + else + ctx = sgsn_mm_ctx_alloc(msgb_tlli(msg), &ra_id); ctx->p_tmsi = tmsi; } if (ctx->ran_type == MM_CTX_T_GERAN_Gb) { @@ -1270,7 +1295,31 @@ * is an optimization to avoid the RA reject (impl detached) * below, which will cause a new attach cycle. */ /* Look-up the MM context based on old RA-ID and TLLI */ - mmctx = sgsn_mm_ctx_by_tlli_and_ptmsi(msgb_tlli(msg), &old_ra_id); + /* In Iu mode, msg->dst contains the ue_conn_ctx pointer, in Gb + * mode dst is empty. */ + /* FIXME: have a more explicit indicator for Iu messages */ + if (!msg->dst) { + mmctx = sgsn_mm_ctx_by_tlli_and_ptmsi(msgb_tlli(msg), &old_ra_id); + } else if (TLVP_PRESENT(&tp, GSM48_IE_GMM_ALLOC_PTMSI)) { +#ifdef BUILD_IU + /* In Iu mode search only for ptmsi */ + char mi_string[GSM48_MI_SIZE]; + uint8_t mi_len = TLVP_LEN(&tp, GSM48_IE_GMM_ALLOC_PTMSI); + uint8_t *mi = TLVP_VAL(&tp, GSM48_IE_GMM_ALLOC_PTMSI); + uint8_t mi_type = *mi & GSM_MI_TYPE_MASK; + uint32_t tmsi; + + gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len); + + if (mi_type == GSM_MI_TYPE_TMSI) { + memcpy(&tmsi, mi+1, 4); + tmsi = ntohl(tmsi); + mmctx = sgsn_mm_ctx_by_ptmsi(tmsi); + } +#else + goto rejected; +#endif + } if (mmctx) { LOGMMCTXP(LOGL_INFO, mmctx, "Looked up by matching TLLI and P_TMSI. " -- To view, visit https://gerrit.osmocom.org/731 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ia47ffbfa6fa0f5a0cd76a379c57ef42faa0d80e3 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: daniel Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Mon Aug 22 12:36:07 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 12:36:07 +0000 Subject: [PATCH] openbsc[master]: IuPS: add Iu response to create_pdp_conf() Message-ID: Review at https://gerrit.osmocom.org/732 IuPS: add Iu response to create_pdp_conf() Change-Id: Iad65ca9b77c3166d4df9a58af527e6aef7e589ee --- M openbsc/include/openbsc/gprs_gmm.h M openbsc/src/gprs/gprs_gmm.c M openbsc/src/gprs/sgsn_libgtp.c 3 files changed, 35 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/32/732/1 diff --git a/openbsc/include/openbsc/gprs_gmm.h b/openbsc/include/openbsc/gprs_gmm.h index 28467d7..d210a35 100644 --- a/openbsc/include/openbsc/gprs_gmm.h +++ b/openbsc/include/openbsc/gprs_gmm.h @@ -30,4 +30,6 @@ time_t gprs_max_time_to_idle(void); +int iu_rab_act_ps(uint8_t rab_id, struct sgsn_pdp_ctx *pdp, bool use_x213_nsap); + #endif /* _GPRS_GMM_H */ diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index 0ec5a23..40fa046 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -2417,3 +2417,28 @@ mmctx->mm_state = GMM_REGISTERED_NORMAL; return 0; } + +#ifdef BUILD_IU +int iu_rab_act_ps(uint8_t rab_id, struct sgsn_pdp_ctx *pdp, bool use_x213_nsap) +{ + struct msgb *msg; + struct sgsn_mm_ctx *mm = pdp->mm; + struct ue_conn_ctx *uectx; + uint32_t ggsn_ip; + + uectx = mm->iu.ue_ctx; + + /* Get the IP address for ggsn user plane */ + memcpy(&ggsn_ip, pdp->lib->gsnru.v, pdp->lib->gsnru.l); + ggsn_ip = htonl(ggsn_ip); + + LOGP(DRANAP, LOGL_DEBUG, "Assigning RAB: rab_id=%d, ggsn_ip=%x," + " teid_gn=%x, use_x213_nsap=%d\n", + rab_id, ggsn_ip, pdp->lib->teid_gn, use_x213_nsap); + + msg = ranap_new_msg_rab_assign_data(rab_id, ggsn_ip, + pdp->lib->teid_gn, use_x213_nsap); + msg->l2h = msg->data; + return iu_rab_act(uectx, msg); +} +#endif diff --git a/openbsc/src/gprs/sgsn_libgtp.c b/openbsc/src/gprs/sgsn_libgtp.c index 4a14cf6..45eff63 100644 --- a/openbsc/src/gprs/sgsn_libgtp.c +++ b/openbsc/src/gprs/sgsn_libgtp.c @@ -366,6 +366,14 @@ /* Activate the SNDCP layer */ sndcp_sm_activate_ind(&pctx->mm->gb.llme->lle[pctx->sapi], pctx->nsapi); return send_act_pdp_cont_acc(pctx); + } else if (pctx->mm->ran_type == MM_CTX_T_UTRAN_Iu) { +#ifdef BUILD_IU + /* Activate a radio bearer */ + iu_rab_act_ps(pdp->nsapi, pctx, 1); + return 0; +#else + return -ENOTSUP; +#endif } LOGP(DGPRS, LOGL_ERROR, "Unknown ran_type %d\n", -- To view, visit https://gerrit.osmocom.org/732 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Iad65ca9b77c3166d4df9a58af527e6aef7e589ee Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: daniel From gerrit-no-reply at lists.osmocom.org Mon Aug 22 12:36:07 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 12:36:07 +0000 Subject: [PATCH] openbsc[master]: IuPS: add Iu response to delete_pdp_conf() Message-ID: Review at https://gerrit.osmocom.org/733 IuPS: add Iu response to delete_pdp_conf() Change-Id: I6d601586101c0a004b2243633fab48db82b44b7c --- M openbsc/src/gprs/sgsn_libgtp.c 1 file changed, 7 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/33/733/1 diff --git a/openbsc/src/gprs/sgsn_libgtp.c b/openbsc/src/gprs/sgsn_libgtp.c index 45eff63..35d5dab 100644 --- a/openbsc/src/gprs/sgsn_libgtp.c +++ b/openbsc/src/gprs/sgsn_libgtp.c @@ -485,6 +485,13 @@ if (pctx->mm->ran_type == MM_CTX_T_GERAN_Gb) { /* Deactivate the SNDCP layer */ sndcp_sm_deactivate_ind(&pctx->mm->gb.llme->lle[pctx->sapi], pctx->nsapi); + } else { +#ifdef BUILD_IU + /* Deactivate radio bearer */ + iu_rab_deact(pctx->mm->iu.ue_ctx, 1); +#else + return -ENOTSUP; +#endif } /* Confirm deactivation of PDP context to MS */ -- To view, visit https://gerrit.osmocom.org/733 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I6d601586101c0a004b2243633fab48db82b44b7c Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: daniel From gerrit-no-reply at lists.osmocom.org Mon Aug 22 12:36:07 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 12:36:07 +0000 Subject: [PATCH] openbsc[master]: IuPS: dev hack: init hardcoded Ki on ATT REQ Message-ID: Review at https://gerrit.osmocom.org/734 IuPS: dev hack: init hardcoded Ki on ATT REQ Change-Id: Ieca45960fa941a3a706c6e479b04b9f2ef89d860 --- M openbsc/src/gprs/gprs_gmm.c 1 file changed, 25 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/34/734/1 diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index 40fa046..7b1fd69 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -1037,6 +1038,30 @@ ctx->ra = ra_id; if (ctx->ran_type == MM_CTX_T_GERAN_Gb) ctx->gb.cell_id = cid; + else if (ctx->ran_type == MM_CTX_T_UTRAN_Iu) { + unsigned char tmp_rand[16]; + /* Ki 000102030405060708090a0b0c0d0e0f */ + struct osmo_sub_auth_data auth = { + .type = OSMO_AUTH_TYPE_GSM, + .algo = OSMO_AUTH_ALG_COMP128v1, + .u.gsm.ki = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, + 0x0e, 0x0f + }, + }; + //ctx->iu.sac = sac; + /* XXX: Hack to make 3G auth work with special SIM card */ + ctx->auth_state = SGSN_AUTH_AUTHENTICATE; + + RAND_bytes(tmp_rand, 16); + + memset(&ctx->auth_triplet.vec, 0, sizeof(ctx->auth_triplet.vec)); + osmo_auth_gen_vec(&ctx->auth_triplet.vec, &auth, tmp_rand); + + ctx->auth_triplet.key_seq = 0; + } + /* Update MM Context with other data */ ctx->drx_parms = drx_par; ctx->ms_radio_access_capa.len = ms_ra_acc_cap_len; -- To view, visit https://gerrit.osmocom.org/734 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ieca45960fa941a3a706c6e479b04b9f2ef89d860 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 22 12:36:07 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 12:36:07 +0000 Subject: [PATCH] openbsc[master]: IuPS: send Security Mode Command, track the new_key flag. Message-ID: Review at https://gerrit.osmocom.org/735 IuPS: send Security Mode Command, track the new_key flag. Change-Id: I0b2593c2df13b79eb36975b0d302e31cfdf8bb09 --- M openbsc/src/gprs/gprs_gmm.c M openbsc/src/gprs/gprs_sgsn.c 2 files changed, 14 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/35/735/1 diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index 7b1fd69..1c0418b 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -610,6 +610,9 @@ ctx->is_authenticated = 1; + if (ctx->ran_type == MM_CTX_T_UTRAN_Iu) + ctx->iu.new_key = 1; + /* FIXME: enable LLC cipheirng */ /* Check if we can let the mobile station enter */ @@ -688,6 +691,9 @@ /* Check if we can already authorize a subscriber */ static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx) { +#ifdef BUILD_IU + int rc; +#endif #ifndef PTMSI_ALLOC struct sgsn_signal_data sig_data; #endif @@ -741,6 +747,13 @@ } /* The MS is authorized */ +#ifdef BUILD_IU + if (ctx->ran_type == MM_CTX_T_UTRAN_Iu && !ctx->iu.ue_ctx->integrity_active) { + rc = iu_tx_sec_mode_cmd(ctx->iu.ue_ctx, &ctx->auth_triplet, 0, ctx->iu.new_key); + ctx->iu.new_key = 0; + return rc; + } +#endif switch (ctx->pending_req) { case 0: diff --git a/openbsc/src/gprs/gprs_sgsn.c b/openbsc/src/gprs/gprs_sgsn.c index 4036025..678d8a9 100644 --- a/openbsc/src/gprs/gprs_sgsn.c +++ b/openbsc/src/gprs/gprs_sgsn.c @@ -240,6 +240,7 @@ ctx->ran_type = MM_CTX_T_UTRAN_Iu; ctx->iu.ue_ctx = uectx; + ctx->iu.new_key = 1; ctx->mm_state = GMM_DEREGISTERED; ctx->auth_triplet.key_seq = GSM_KEY_SEQ_INVAL; ctx->ctrg = rate_ctr_group_alloc(ctx, &mmctx_ctrg_desc, 0); -- To view, visit https://gerrit.osmocom.org/735 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I0b2593c2df13b79eb36975b0d302e31cfdf8bb09 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 22 12:36:07 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 12:36:07 +0000 Subject: [PATCH] openbsc[master]: IuPS: GMM Service Request: add local gsm_04_08_gprs.h and .c Message-ID: Review at https://gerrit.osmocom.org/736 IuPS: GMM Service Request: add local gsm_04_08_gprs.h and .c These items will probably move to libosmocore's gsm_04_08_gprs.h and .c, add them here in openbsc until things have settled. Change-Id: Iaf9316f07d21280b6e090d65892c338f9555313a --- M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gsm_04_08_gprs.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/gprs_gmm.c A openbsc/src/gprs/gsm_04_08_gprs.c M openbsc/tests/sgsn/Makefile.am 6 files changed, 62 insertions(+), 3 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/36/736/1 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 2bca6b7..d0f1ca2 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -8,7 +8,7 @@ vty.h socket.h e1_config.h trau_upqueue.h token_auth.h \ handover_decision.h rrlp.h \ crc24.h gprs_llc.h gprs_gmm.h \ - gb_proxy.h gprs_sgsn.h sgsn.h \ + gb_proxy.h gprs_sgsn.h gsm_04_08_gprs.h sgsn.h \ auth.h osmo_msc.h bsc_msc.h bsc_nat.h \ osmo_bsc_rf.h osmo_bsc.h network_listen.h bsc_nat_sccp.h \ osmo_msc_data.h osmo_bsc_grace.h sms_queue.h abis_om2000.h \ diff --git a/openbsc/include/openbsc/gsm_04_08_gprs.h b/openbsc/include/openbsc/gsm_04_08_gprs.h new file mode 100644 index 0000000..42b9a79 --- /dev/null +++ b/openbsc/include/openbsc/gsm_04_08_gprs.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +/* TODO: Move this to osmocom/gsm/protocol/gsm_04_08_gprs.h ? */ + +/* Table 10.4 in 3GPP TS 24.008 (successor to 04.08) */ +#define GSM48_MT_GMM_SERVICE_REQ 0x0c +#define GSM48_MT_GMM_SERVICE_ACK 0x0d +#define GSM48_MT_GMM_SERVICE_REJ 0x0e + +/* 3GPP 24.008 / Chapter 10.5.5.20 / Table 10.5.153a */ +enum gsm48_gmm_service_type { + GPRS_SERVICE_T_SIGNALLING = 0x00, + GPRS_SERVICE_T_DATA = 0x01, + GPRS_SERVICE_T_PAGING_RESP = 0x02, + GPRS_SERVICE_T_MBMS_MC_SERV = 0x03, + GPRS_SERVICE_T_MBMS_BC_SERV = 0x04, +}; + +extern const struct value_string *gprs_service_t_strs; diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index cc135f7..191f115 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -31,7 +31,7 @@ gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c crc24.c \ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ gprs_utils.c gprs_gsup_client.c \ - sgsn_cdr.c sgsn_ares.c \ + gsm_04_08_gprs.c sgsn_cdr.c sgsn_ares.c \ oap.c oap_messages.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index 1c0418b..aac3d86 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -44,7 +44,6 @@ #include #include #include -#include #include @@ -56,6 +55,7 @@ #include #include #include +#include #include #include #include diff --git a/openbsc/src/gprs/gsm_04_08_gprs.c b/openbsc/src/gprs/gsm_04_08_gprs.c new file mode 100644 index 0000000..90657eb --- /dev/null +++ b/openbsc/src/gprs/gsm_04_08_gprs.c @@ -0,0 +1,37 @@ +/* (C) 2009-2010 by Harald Welte + * (C) 2010 by On-Waves + * (C) 2014-2015 by Sysmocom s.f.m.c. GmbH + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +/* TODO: Move this to osmocom/gsm/protocol/gsm_04_08_gprs.h ? */ + +#include + +#include + +const struct value_string gprs_service_t_strs_[] = { + { GPRS_SERVICE_T_SIGNALLING, "signalling" }, + { GPRS_SERVICE_T_DATA, "data" }, + { GPRS_SERVICE_T_PAGING_RESP, "paging response" }, + { GPRS_SERVICE_T_MBMS_MC_SERV, "MBMS multicast service" }, + { GPRS_SERVICE_T_MBMS_BC_SERV, "MBMS broadcast service" }, + { 0, NULL } +}; + +const struct value_string *gprs_service_t_strs = gprs_service_t_strs_; diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 025e2c9..4931b3f 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -30,6 +30,7 @@ $(top_builddir)/src/gprs/gprs_gsup_client.o \ $(top_builddir)/src/gprs/gprs_utils.o \ $(top_builddir)/src/gprs/gprs_subscriber.o \ + $(top_builddir)/src/gprs/gsm_04_08_gprs.o \ $(top_builddir)/src/gprs/gprs_gb_parse.o \ $(top_builddir)/src/gprs/oap.o \ $(top_builddir)/src/gprs/oap_messages.o \ -- To view, visit https://gerrit.osmocom.org/736 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Iaf9316f07d21280b6e090d65892c338f9555313a Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 22 12:36:07 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 12:36:07 +0000 Subject: [PATCH] openbsc[master]: IuPS: add GMM Service Request rx and tx Message-ID: Review at https://gerrit.osmocom.org/737 IuPS: add GMM Service Request rx and tx Change-Id: Ib935de22d23a15f449927840d4d59497ce22abbd --- M openbsc/src/gprs/gprs_gmm.c 1 file changed, 199 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/37/737/1 diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index aac3d86..3812516 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -688,6 +688,75 @@ strncpy(&ctx->hlr[0], called.number, sizeof(ctx->hlr) - 1); } +#ifdef BUILD_IU +/* Chapter 9.4.21: Service accept */ +static int gsm48_tx_gmm_service_ack(struct sgsn_mm_ctx *mm) +{ + struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SERVICE ACK"); + struct gsm48_hdr *gh; + + LOGMMCTXP(LOGL_INFO, mm, "<- GPRS SERVICE ACCEPT (P-TMSI=0x%08x)\n", mm->p_tmsi); + + mmctx2msgid(msg, mm); + + gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); + gh->proto_discr = GSM48_PDISC_MM_GPRS; + gh->msg_type = GSM48_MT_GMM_SERVICE_ACK; + + /* Optional: PDP context status */ + /* Optional: MBMS context status */ + + return gsm48_gmm_sendmsg(msg, 0, mm, false); +} +#endif + +/* Chapter 9.4.22: Service reject */ +static int _tx_gmm_service_rej(struct msgb *msg, uint8_t gmm_cause, + const struct sgsn_mm_ctx *mm) +{ + struct gsm48_hdr *gh; + + LOGMMCTXP(LOGL_NOTICE, mm, "<- GPRS SERVICE REJECT: %s\n", + get_value_string(gsm48_gmm_cause_names, gmm_cause)); + + gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1); + gh->proto_discr = GSM48_PDISC_MM_GPRS; + gh->msg_type = GSM48_MT_GMM_SERVICE_REJ; + gh->data[0] = gmm_cause; + + return gsm48_gmm_sendmsg(msg, 0, NULL, true); +} +static int gsm48_tx_gmm_service_rej_oldmsg(const struct msgb *old_msg, + uint8_t gmm_cause) +{ + struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SERVICE REJ OLD"); + gmm_copy_id(msg, old_msg); + return _tx_gmm_service_rej(msg, gmm_cause, NULL); +} +#if 0 +-- currently unused -- +static int gsm48_tx_gmm_service_rej(struct sgsn_mm_ctx *mm, + uint8_t gmm_cause) +{ + struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SERVICE REJ"); + mmctx2msgid(msg, mm); + return _tx_gmm_service_rej(msg, gmm_cause, mm); +} +#endif + +static int gsm48_tx_gmm_ra_upd_ack(struct sgsn_mm_ctx *mm); + +#ifdef BUILD_IU +void activate_pdp_rabs(struct sgsn_mm_ctx *ctx) +{ + /* Send RAB activation requests for all PDP contexts */ + struct sgsn_pdp_ctx *pdp; + llist_for_each_entry(pdp, &ctx->pdp_list, list) { + iu_rab_act_ps(pdp->nsapi, pdp, 1); + } +} +#endif + /* Check if we can already authorize a subscriber */ static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx) { @@ -776,6 +845,23 @@ #endif return gsm48_tx_gmm_att_ack(ctx); +#ifdef BUILD_IU + case GSM48_MT_GMM_SERVICE_REQ: + /* TODO: PMM State transition */ + ctx->pending_req = 0; + rc = gsm48_tx_gmm_service_ack(ctx); + + if (ctx->iu.service.type == 1) { + activate_pdp_rabs(ctx); + } + + return rc; +#endif + case GSM48_MT_GMM_RA_UPD_REQ: + ctx->pending_req = 0; + /* Send RA UPDATE ACCEPT */ + return gsm48_tx_gmm_ra_upd_ack(ctx); + default: LOGMMCTXP(LOGL_ERROR, ctx, "only Attach Request is supported yet, " @@ -1467,6 +1553,116 @@ return rc; } +/* 3GPP TS 24.008 Section 9.4.20 Service request. + * In Iu, a UE in PMM-IDLE mode can use GSM48_MT_GMM_SERVICE_REQ to switch back + * to PMM-CONNECTED mode. */ +static int gsm48_rx_gmm_service_req(struct sgsn_mm_ctx *ctx, struct msgb *msg) +{ + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); + uint8_t *cur = gh->data, *mi; + uint8_t ciph_seq_nr, service_type, mi_len, mi_type; + uint32_t tmsi; + struct tlv_parsed tp; + char mi_string[GSM48_MI_SIZE]; + enum gsm48_gmm_cause reject_cause; + int rc; + + LOGMMCTXP(LOGL_INFO, ctx, "-> GMM SERVICE REQUEST "); + + /* This message is only valid in Iu mode */ + if (!msg->dst) { + LOGPC(DMM, LOGL_INFO, "Invalid if not in Iu mode\n"); + return -1; + } + + /* Skip Ciphering key sequence number 10.5.1.2 */ + ciph_seq_nr = *cur & 0x07; + + /* Service type 10.5.5.20 */ + service_type = (*cur++ >> 4) & 0x07; + + /* Mobile Identity (P-TMSI or IMSI) 10.5.1.4 */ + mi_len = *cur++; + mi = cur; + if (mi_len > 8) + goto err_inval; + mi_type = *mi & GSM_MI_TYPE_MASK; + cur += mi_len; + + gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len); + + DEBUGPC(DMM, "MI(%s) type=\"%s\" ", mi_string, + get_value_string(gprs_service_t_strs, service_type)); + + LOGPC(DMM, LOGL_INFO, "\n"); + + /* Optional: PDP context status, MBMS context status, Uplink data status, Device properties */ + tlv_parse(&tp, &gsm48_gmm_att_tlvdef, cur, (msg->data + msg->len) - cur, 0, 0); + + switch (mi_type) { + case GSM_MI_TYPE_IMSI: + /* Try to find MM context based on IMSI */ + if (!ctx) + ctx = sgsn_mm_ctx_by_imsi(mi_string); + if (!ctx) { + /* FIXME: We need to have a context for service request? */ + reject_cause = GMM_CAUSE_NET_FAIL; + goto rejected; + } + msgid2mmctx(ctx, msg); + break; + case GSM_MI_TYPE_TMSI: + memcpy(&tmsi, mi+1, 4); + tmsi = ntohl(tmsi); + /* Try to find MM context based on P-TMSI */ + if (!ctx) + ctx = sgsn_mm_ctx_by_ptmsi(tmsi); + if (!ctx) { + /* FIXME: We need to have a context for service request? */ + reject_cause = GMM_CAUSE_NET_FAIL; + goto rejected; + } + msgid2mmctx(ctx, msg); + break; + default: + LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting SERVICE REQUEST with " + "MI type %s\n", gsm48_mi_type_name(mi_type)); + reject_cause = GMM_CAUSE_MS_ID_NOT_DERIVED; + goto rejected; + } + + ctx->mm_state = GMM_COMMON_PROC_INIT; + + ctx->iu.service.type = service_type; + + /* TODO: Handle those only in case of accept? */ + /* Look at PDP Context Status IE and see if MS's view of + * activated/deactivated NSAPIs agrees with our view */ + if (TLVP_PRESENT(&tp, GSM48_IE_GMM_PDP_CTX_STATUS)) { + const uint8_t *pdp_status = TLVP_VAL(&tp, GSM48_IE_GMM_PDP_CTX_STATUS); + process_ms_ctx_status(ctx, pdp_status); + } + + + ctx->pending_req = GSM48_MT_GMM_SERVICE_REQ; + return gsm48_gmm_authorize(ctx); + +err_inval: + LOGPC(DMM, LOGL_INFO, "\n"); + reject_cause = GMM_CAUSE_SEM_INCORR_MSG; + +rejected: + /* Send SERVICE REJECT */ + LOGMMCTXP(LOGL_NOTICE, ctx, + "Rejecting Service Request with cause '%s' (%d)\n", + get_value_string(gsm48_gmm_cause_names, reject_cause), reject_cause); + rc = gsm48_tx_gmm_service_rej_oldmsg(msg, reject_cause); + + return rc; + +} + + static int gsm48_rx_gmm_status(struct sgsn_mm_ctx *mmctx, struct msgb *msg) { struct gsm48_hdr *gh = msgb_l3(msg); @@ -1545,6 +1741,9 @@ case GSM48_MT_GMM_ATTACH_REQ: rc = gsm48_rx_gmm_att_req(mmctx, msg, llme); break; + case GSM48_MT_GMM_SERVICE_REQ: + rc = gsm48_rx_gmm_service_req(mmctx, msg); + break; /* For all the following types mmctx can not be NULL */ case GSM48_MT_GMM_ID_RESP: if (!mmctx) -- To view, visit https://gerrit.osmocom.org/737 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ib935de22d23a15f449927840d4d59497ce22abbd Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 22 12:36:08 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 12:36:08 +0000 Subject: [PATCH] openbsc[master]: IuPS: RA UPD: make sure to authorize, for Iu Integrity Prote... Message-ID: Review at https://gerrit.osmocom.org/738 IuPS: RA UPD: make sure to authorize, for Iu Integrity Protection Change-Id: I2ea2089895f8a8e125ef39d9bef70dafb2b1ce69 --- M openbsc/src/gprs/gprs_gmm.c 1 file changed, 7 insertions(+), 4 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/38/738/1 diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index 3812516..bfd568f 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -49,6 +49,7 @@ #ifdef BUILD_IU #include +#include #endif #include @@ -851,9 +852,8 @@ ctx->pending_req = 0; rc = gsm48_tx_gmm_service_ack(ctx); - if (ctx->iu.service.type == 1) { + if (ctx->iu.service.type != GPRS_SERVICE_T_SIGNALLING) activate_pdp_rabs(ctx); - } return rc; #endif @@ -1534,8 +1534,11 @@ process_ms_ctx_status(mmctx, pdp_status); } - /* Send RA UPDATE ACCEPT */ - return gsm48_tx_gmm_ra_upd_ack(mmctx); + /* Send RA UPDATE ACCEPT. In Iu, the RA upd request can be called from + * a new Iu connection, so we might need to re-authenticate the + * connection as well as turn on integrity protection. */ + mmctx->pending_req = GSM48_MT_GMM_RA_UPD_REQ; + return gsm48_gmm_authorize(mmctx); rejected: /* Send RA UPDATE REJECT */ -- To view, visit https://gerrit.osmocom.org/738 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I2ea2089895f8a8e125ef39d9bef70dafb2b1ce69 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 22 12:36:08 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 12:36:08 +0000 Subject: [PATCH] openbsc[master]: IuPS: sgsn_mm_ctx: add enum gprs_pmm_state field, track PMM ... Message-ID: Review at https://gerrit.osmocom.org/739 IuPS: sgsn_mm_ctx: add enum gprs_pmm_state field, track PMM state Iu needs to page to transfer data in PMM-IDLE state. Change-Id: Id37778cb9a0328a21c8e8246998ecdb43dd687d8 --- M openbsc/include/openbsc/gprs_sgsn.h M openbsc/src/gprs/gprs_gmm.c M openbsc/src/gprs/gprs_sgsn.c 3 files changed, 18 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/39/739/1 diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h index 18cbab8..24e286c 100644 --- a/openbsc/include/openbsc/gprs_sgsn.h +++ b/openbsc/include/openbsc/gprs_sgsn.h @@ -31,6 +31,16 @@ GMM_DEREGISTERED_INIT, /* 4.1.3.3.1.4 */ }; +/* TS 23.060 6.1.1 and 6.1.2 Mobility management states A/Gb and Iu mode */ +enum gprs_pmm_state { + PMM_DETACHED, + PMM_CONNECTED, + PMM_IDLE, + MM_IDLE = PMM_DETACHED, + MM_READY = PMM_CONNECTED, + MM_STANDBY = PMM_IDLE, +}; + enum gprs_mm_ctr { GMM_CTR_PKTS_SIG_IN, GMM_CTR_PKTS_SIG_OUT, @@ -117,6 +127,7 @@ char imsi[GSM23003_IMSI_MAX_DIGITS+1]; enum gprs_gmm_state mm_state; + enum gprs_pmm_state pmm_state; /* Iu: page when in PMM-IDLE mode */ uint32_t p_tmsi; uint32_t p_tmsi_old; /* old P-TMSI before new is confirmed */ uint32_t p_tmsi_sig; diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index bfd568f..e66fec6 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -131,6 +131,8 @@ case IU_EVENT_LINK_INVALIDATED: /* Clean up ue_conn_ctx here */ LOGMMCTXP(LOGL_INFO, mm, "IU release for imsi %s\n", mm->imsi); + if (mm->pmm_state == PMM_CONNECTED) + mm->pmm_state = PMM_IDLE; rc = 0; break; case IU_EVENT_SECURITY_MODE_COMPLETE: @@ -239,6 +241,7 @@ /* Mark MM state as deregistered */ ctx->mm_state = GMM_DEREGISTERED; + ctx->pmm_state = PMM_DETACHED; sgsn_mm_ctx_cleanup_free(ctx); } @@ -850,6 +853,7 @@ case GSM48_MT_GMM_SERVICE_REQ: /* TODO: PMM State transition */ ctx->pending_req = 0; + ctx->pmm_state = PMM_CONNECTED; rc = gsm48_tx_gmm_service_ack(ctx); if (ctx->iu.service.type != GPRS_SERVICE_T_SIGNALLING) @@ -1787,6 +1791,7 @@ mmctx->gb.tlli_new); } mmctx->mm_state = GMM_REGISTERED_NORMAL; + mmctx->pmm_state = PMM_CONNECTED; rc = 0; memset(&sig_data, 0, sizeof(sig_data)); @@ -1809,6 +1814,7 @@ mmctx->gb.tlli_new); } mmctx->mm_state = GMM_REGISTERED_NORMAL; + mmctx->pmm_state = PMM_CONNECTED; rc = 0; memset(&sig_data, 0, sizeof(sig_data)); diff --git a/openbsc/src/gprs/gprs_sgsn.c b/openbsc/src/gprs/gprs_sgsn.c index 678d8a9..73e8793 100644 --- a/openbsc/src/gprs/gprs_sgsn.c +++ b/openbsc/src/gprs/gprs_sgsn.c @@ -242,6 +242,7 @@ ctx->iu.ue_ctx = uectx; ctx->iu.new_key = 1; ctx->mm_state = GMM_DEREGISTERED; + ctx->pmm_state = PMM_DETACHED; ctx->auth_triplet.key_seq = GSM_KEY_SEQ_INVAL; ctx->ctrg = rate_ctr_group_alloc(ctx, &mmctx_ctrg_desc, 0); -- To view, visit https://gerrit.osmocom.org/739 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Id37778cb9a0328a21c8e8246998ecdb43dd687d8 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 22 12:36:08 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 12:36:08 +0000 Subject: [PATCH] openbsc[master]: IuPS: GMM Attach: reset MM ctx pending_req Message-ID: Review at https://gerrit.osmocom.org/740 IuPS: GMM Attach: reset MM ctx pending_req Change-Id: I0df0f3d88085939eb617405e2013ad164eed477b --- M openbsc/src/gprs/gprs_gmm.c 1 file changed, 1 insertion(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/40/740/1 diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index e66fec6..82f7f79 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -834,6 +834,7 @@ "no pending request, authorization completed\n"); break; case GSM48_MT_GMM_ATTACH_REQ: + ctx->pending_req = 0; extract_subscr_msisdn(ctx); extract_subscr_hlr(ctx); -- To view, visit https://gerrit.osmocom.org/740 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I0df0f3d88085939eb617405e2013ad164eed477b Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 22 12:36:08 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 12:36:08 +0000 Subject: [PATCH] openbsc[master]: IuPS: Introduce function to change PMM state Message-ID: Review at https://gerrit.osmocom.org/741 IuPS: Introduce function to change PMM state This is where IuPS will redirect GTP-U endpoints in a subsequent commit. Also add comprehensive logging of pmm_state transitions. Change-Id: I7c2cd1abc1805659b01dffffff31c49fe5161086 --- M openbsc/src/gprs/gprs_gmm.c 1 file changed, 29 insertions(+), 6 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/41/741/1 diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index 82f7f79..d94217b 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -109,6 +109,29 @@ static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx); +void mmctx_set_pmm_state(struct sgsn_mm_ctx *ctx, enum gprs_pmm_state state) +{ + if (ctx->pmm_state == state) + return; + + LOGMMCTXP(LOGL_INFO, ctx, "Changing PMM state from %i to %i\n", ctx->pmm_state, state); + + if (ctx->ran_type == MM_CTX_T_UTRAN_Iu) + { + switch (state) { + case PMM_IDLE: + /* TODO: Change GTP-U endpoints to SGSN, start RA Upd timer */ + break; + case PMM_CONNECTED: + break; + default: + break; + } + } + + ctx->pmm_state = state; +} + #ifdef BUILD_IU int sgsn_ranap_rab_ass_resp(struct sgsn_mm_ctx *ctx, RANAP_RAB_SetupOrModifiedItemIEs_t *setup_ies); int sgsn_ranap_iu_event(struct ue_conn_ctx *ctx, enum iu_event_type type, void *data) @@ -132,7 +155,7 @@ /* Clean up ue_conn_ctx here */ LOGMMCTXP(LOGL_INFO, mm, "IU release for imsi %s\n", mm->imsi); if (mm->pmm_state == PMM_CONNECTED) - mm->pmm_state = PMM_IDLE; + mmctx_set_pmm_state(mm, PMM_IDLE); rc = 0; break; case IU_EVENT_SECURITY_MODE_COMPLETE: @@ -241,7 +264,8 @@ /* Mark MM state as deregistered */ ctx->mm_state = GMM_DEREGISTERED; - ctx->pmm_state = PMM_DETACHED; + + mmctx_set_pmm_state(ctx, PMM_DETACHED); sgsn_mm_ctx_cleanup_free(ctx); } @@ -852,9 +876,8 @@ return gsm48_tx_gmm_att_ack(ctx); #ifdef BUILD_IU case GSM48_MT_GMM_SERVICE_REQ: - /* TODO: PMM State transition */ ctx->pending_req = 0; - ctx->pmm_state = PMM_CONNECTED; + mmctx_set_pmm_state(ctx, PMM_CONNECTED); rc = gsm48_tx_gmm_service_ack(ctx); if (ctx->iu.service.type != GPRS_SERVICE_T_SIGNALLING) @@ -1792,7 +1815,7 @@ mmctx->gb.tlli_new); } mmctx->mm_state = GMM_REGISTERED_NORMAL; - mmctx->pmm_state = PMM_CONNECTED; + mmctx_set_pmm_state(mmctx, PMM_CONNECTED); rc = 0; memset(&sig_data, 0, sizeof(sig_data)); @@ -1815,7 +1838,7 @@ mmctx->gb.tlli_new); } mmctx->mm_state = GMM_REGISTERED_NORMAL; - mmctx->pmm_state = PMM_CONNECTED; + mmctx_set_pmm_state(mmctx, PMM_CONNECTED); rc = 0; memset(&sig_data, 0, sizeof(sig_data)); -- To view, visit https://gerrit.osmocom.org/741 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I7c2cd1abc1805659b01dffffff31c49fe5161086 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: daniel From gerrit-no-reply at lists.osmocom.org Mon Aug 22 12:36:08 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 12:36:08 +0000 Subject: [PATCH] openbsc[master]: IuPS: Change GTP-U endpoint to SGSN in PMM_IDLE and page UE ... Message-ID: Review at https://gerrit.osmocom.org/742 IuPS: Change GTP-U endpoint to SGSN in PMM_IDLE and page UE when data arrives Change-Id: I47b73a40cbdda6b7c31fb2767f74f9f93d84056b --- M openbsc/include/openbsc/sgsn.h M openbsc/src/gprs/gprs_gmm.c M openbsc/src/gprs/sgsn_libgtp.c 3 files changed, 32 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/42/742/1 diff --git a/openbsc/include/openbsc/sgsn.h b/openbsc/include/openbsc/sgsn.h index 59126fe..6b84a0f 100644 --- a/openbsc/include/openbsc/sgsn.h +++ b/openbsc/include/openbsc/sgsn.h @@ -134,6 +134,7 @@ uint16_t nsapi, struct tlv_parsed *tp); int sgsn_delete_pdp_ctx(struct sgsn_pdp_ctx *pctx); +void sgsn_pdp_upd_gtp_u(struct sgsn_pdp_ctx *pdp, void *addr, size_t alen); /* gprs_sndcp.c */ diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index d94217b..8843e6c 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -109,6 +109,16 @@ static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx); +static void mmctx_change_gtpu_endpoints_to_sgsn(struct sgsn_mm_ctx *mm_ctx) +{ + struct sgsn_pdp_ctx *pdp; + llist_for_each_entry(pdp, &mm_ctx->pdp_list, list) { + sgsn_pdp_upd_gtp_u(pdp, + &sgsn->cfg.gtp_listenaddr.sin_addr, + sizeof(sgsn->cfg.gtp_listenaddr.sin_addr)); + } +} + void mmctx_set_pmm_state(struct sgsn_mm_ctx *ctx, enum gprs_pmm_state state) { if (ctx->pmm_state == state) @@ -120,7 +130,8 @@ { switch (state) { case PMM_IDLE: - /* TODO: Change GTP-U endpoints to SGSN, start RA Upd timer */ + /* TODO: start RA Upd timer */ + mmctx_change_gtpu_endpoints_to_sgsn(ctx); break; case PMM_CONNECTED: break; diff --git a/openbsc/src/gprs/sgsn_libgtp.c b/openbsc/src/gprs/sgsn_libgtp.c index 35d5dab..04bd40a 100644 --- a/openbsc/src/gprs/sgsn_libgtp.c +++ b/openbsc/src/gprs/sgsn_libgtp.c @@ -401,6 +401,13 @@ return EOF; } +void sgsn_pdp_upd_gtp_u(struct sgsn_pdp_ctx *pdp, void *addr, size_t alen) +{ + pdp->lib->gsnlu.l = alen; + memcpy(pdp->lib->gsnlu.v, addr, alen); + gtp_update_context(pdp->ggsn->gsn, pdp->lib, pdp, &pdp->lib->hisaddr0); +} + #ifdef BUILD_IU /* Callback for RAB assignment response */ int sgsn_ranap_rab_ass_resp(struct sgsn_mm_ctx *ctx, RANAP_RAB_SetupOrModifiedItemIEs_t *setup_ies) @@ -621,6 +628,18 @@ return -EIO; } + if (mm->ran_type == MM_CTX_T_UTRAN_Iu) { +#ifdef BUILD_IU + /* Ignore the packet for now and page the UE to get the RAB + * reestablished */ + iu_page_ps(mm->imsi, &mm->p_tmsi, mm->ra.lac, mm->ra.rac); + + return 0; +#else + return -ENOTSUP; +#endif + } + msg = msgb_alloc_headroom(len+256, 128, "GTP->SNDCP"); ud = msgb_put(msg, len); memcpy(ud, packet, len); -- To view, visit https://gerrit.osmocom.org/742 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I47b73a40cbdda6b7c31fb2767f74f9f93d84056b Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: daniel From gerrit-no-reply at lists.osmocom.org Mon Aug 22 17:15:58 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 22 Aug 2016 17:15:58 +0000 Subject: osmo-pcu[master]: Remove warning while using 'egprs only' command in VTY In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 I see what you mean. The command says "disable GPRS". I think a warning that no mixed mode operation would be nice at some point in time. -- To view, visit https://gerrit.osmocom.org/704 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I62278f998adc691b9a3563ac2a46d756e7bfb66c Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 22 17:16:00 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Mon, 22 Aug 2016 17:16:00 +0000 Subject: [MERGED] osmo-pcu[master]: Remove warning while using 'egprs only' command in VTY In-Reply-To: References: Message-ID: Holger Freyther has submitted this change and it was merged. Change subject: Remove warning while using 'egprs only' command in VTY ...................................................................... Remove warning while using 'egprs only' command in VTY This warning is not valid since the PCU is not failing when EGPRS is activated. So removing this trace Change-Id: I62278f998adc691b9a3563ac2a46d756e7bfb66c --- M src/pcu_vty.c 1 file changed, 0 insertions(+), 6 deletions(-) Approvals: Jenkins Builder: Verified Holger Freyther: Looks good to me, approved diff --git a/src/pcu_vty.c b/src/pcu_vty.c index 58fea99..ef48027 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -187,12 +187,6 @@ bts->egprs_enabled = 1; - vty_out(vty, "%%Note that EGPRS support is in an experimental state " - "and the PCU will currently fail to use a TBF if the MS is capable " - "to do EGPRS. You may want to disable this feature by entering " - "the \"no egprs\" command. " - "Do not use this in production!%s", VTY_NEWLINE); - return CMD_SUCCESS; } -- To view, visit https://gerrit.osmocom.org/704 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I62278f998adc691b9a3563ac2a46d756e7bfb66c Gerrit-PatchSet: 2 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Mon Aug 22 21:45:14 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 21:45:14 +0000 Subject: [PATCH] osmo-bts[master]: log: l1sap: add 0x to hex output of chan_nr, 5 times Message-ID: Review at https://gerrit.osmocom.org/743 log: l1sap: add 0x to hex output of chan_nr, 5 times Change-Id: I35c8b53146c3451cb6fd3fe7c0d123a4af4a69c1 --- M src/common/l1sap.c 1 file changed, 5 insertions(+), 5 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/43/743/1 diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 6498103..d229728 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -403,7 +403,7 @@ struct bts_ul_meas ulm; struct gsm_lchan *lchan; - DEBUGP(DL1P, "MPH_INFO meas ind chan_nr=%02x\n", + DEBUGP(DL1P, "MPH_INFO meas ind chan_nr=0x%02x\n", info_meas_ind->chan_nr); lchan = get_active_lchan_by_chan_nr(trx, info_meas_ind->chan_nr); @@ -489,7 +489,7 @@ { struct gsm_lchan *lchan; - LOGP(DL1P, LOGL_INFO, "deactivate confirm chan_nr=%02x trx=%d\n", + LOGP(DL1P, LOGL_INFO, "deactivate confirm chan_nr=0x%02x trx=%d\n", info_act_cnf->chan_nr, trx->nr); lchan = get_lchan_by_chan_nr(trx, info_act_cnf->chan_nr); @@ -1145,7 +1145,7 @@ int l1sap_chan_rel(struct gsm_bts_trx *trx, uint8_t chan_nr) { - LOGP(DL1P, LOGL_INFO, "deactivating channel chan_nr=%02x trx=%d\n", + LOGP(DL1P, LOGL_INFO, "deactivating channel chan_nr=0x%02x trx=%d\n", chan_nr, trx->nr); return l1sap_chan_act_dact_modify(trx, chan_nr, PRIM_INFO_DEACTIVATE, @@ -1156,7 +1156,7 @@ { struct gsm_lchan *lchan = get_lchan_by_chan_nr(trx, chan_nr); - LOGP(DL1P, LOGL_INFO, "deactivating sacch chan_nr=%02x trx=%d\n", + LOGP(DL1P, LOGL_INFO, "deactivating sacch chan_nr=0x%02x trx=%d\n", chan_nr, trx->nr); lchan->sacch_deact = 1; @@ -1167,7 +1167,7 @@ int l1sap_chan_modify(struct gsm_bts_trx *trx, uint8_t chan_nr) { - LOGP(DL1P, LOGL_INFO, "modifying channel chan_nr=%02x trx=%d\n", + LOGP(DL1P, LOGL_INFO, "modifying channel chan_nr=0x%02x trx=%d\n", chan_nr, trx->nr); return l1sap_chan_act_dact_modify(trx, chan_nr, PRIM_INFO_MODIFY, 0); -- To view, visit https://gerrit.osmocom.org/743 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I35c8b53146c3451cb6fd3fe7c0d123a4af4a69c1 Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 22 21:45:49 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 21:45:49 +0000 Subject: [PATCH] osmo-bts[master]: log causing rx event for lchan_lookup errors Message-ID: Review at https://gerrit.osmocom.org/744 log causing rx event for lchan_lookup errors Add log_name to lchan_lookup() and pass such from the various RSL rx events that call it to validate the RSL chan_nr. Change-Id: I27ea7c4631b87f1d6ef57895306209bf3ccdc739 --- M src/common/rsl.c 1 file changed, 10 insertions(+), 8 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/44/744/1 diff --git a/src/common/rsl.c b/src/common/rsl.c index 490ae28..622fdae 100644 --- a/src/common/rsl.c +++ b/src/common/rsl.c @@ -144,19 +144,21 @@ return rsl_tx_error_report(trx, RSL_ERR_IE_CONTENT); } -static struct gsm_lchan *lchan_lookup(struct gsm_bts_trx *trx, uint8_t chan_nr) +static struct gsm_lchan *lchan_lookup(struct gsm_bts_trx *trx, uint8_t chan_nr, + const char *log_name) { int rc; struct gsm_lchan *lchan = rsl_lchan_lookup(trx, chan_nr, &rc); if (!lchan) { - LOGP(DRSL, LOGL_ERROR, "unknown chan_nr=0x%02x\n", chan_nr); + LOGP(DRSL, LOGL_ERROR, "%sunknown chan_nr=0x%02x\n", log_name, + chan_nr); return NULL; } if (rc < 0) - LOGP(DRSL, LOGL_ERROR, "%s mismatching chan_nr=0x%02x\n", - gsm_ts_and_pchan_name(lchan->ts), chan_nr); + LOGP(DRSL, LOGL_ERROR, "%s %smismatching chan_nr=0x%02x\n", + gsm_ts_and_pchan_name(lchan->ts), log_name, chan_nr); return lchan; } @@ -2080,7 +2082,7 @@ } msg->l3h = (unsigned char *)rh + sizeof(*rh); - lchan = lchan_lookup(trx, rh->chan_nr); + lchan = lchan_lookup(trx, rh->chan_nr, "RSL rx RLL: "); if (!lchan) { LOGP(DRLL, LOGL_NOTICE, "Rx RLL %s for unknown lchan\n", rsl_msg_name(rh->c.msg_type)); @@ -2224,7 +2226,7 @@ } msg->l3h = (unsigned char *)cch + sizeof(*cch); - msg->lchan = lchan_lookup(trx, cch->chan_nr); + msg->lchan = lchan_lookup(trx, cch->chan_nr, "RSL rx CCHAN: "); if (!msg->lchan) { LOGP(DRSL, LOGL_ERROR, "Rx RSL %s for unknown lchan\n", rsl_msg_name(cch->c.msg_type)); @@ -2278,7 +2280,7 @@ } msg->l3h = (unsigned char *)dch + sizeof(*dch); - msg->lchan = lchan_lookup(trx, dch->chan_nr); + msg->lchan = lchan_lookup(trx, dch->chan_nr, "RSL rx DCHAN: "); if (!msg->lchan) { LOGP(DRSL, LOGL_ERROR, "Rx RSL %s for unknown lchan\n", rsl_or_ipac_msg_name(dch->c.msg_type)); @@ -2377,7 +2379,7 @@ } msg->l3h = (unsigned char *)dch + sizeof(*dch); - msg->lchan = lchan_lookup(trx, dch->chan_nr); + msg->lchan = lchan_lookup(trx, dch->chan_nr, "RSL rx IPACC: "); if (!msg->lchan) { LOGP(DRSL, LOGL_ERROR, "Rx RSL %s for unknow lchan\n", rsl_msg_name(dch->c.msg_type)); -- To view, visit https://gerrit.osmocom.org/744 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I27ea7c4631b87f1d6ef57895306209bf3ccdc739 Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 22 21:51:04 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 21:51:04 +0000 Subject: osmo-bts[master]: dyn TS: sysmo, lc15: ph_data_req: fix PDCH mode detection In-Reply-To: References: Message-ID: Patch Set 3: accidentally updated this patch with another, changing the topic. will fix later. -- To view, visit https://gerrit.osmocom.org/677 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I6136cb42a4d627ebefc963eb5321fadfe63cca4b Gerrit-PatchSet: 3 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 22 21:51:19 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 21:51:19 +0000 Subject: osmo-bts[master]: cosmetic: common ts_is_pdch() In-Reply-To: References: Message-ID: Patch Set 3: accidentally updated this patch with another, changing the topic. will fix later. -- To view, visit https://gerrit.osmocom.org/676 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ib78d663fdbac5a1d7053f1b9d543649b66da00e2 Gerrit-PatchSet: 3 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 22 21:51:29 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 21:51:29 +0000 Subject: osmo-bts[master]: dyn TS: measurement: use correct nr of subslots, rm code dup In-Reply-To: References: Message-ID: Patch Set 3: accidentally updated this patch with another, changing the topic. will fix later. -- To view, visit https://gerrit.osmocom.org/675 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I9d9df470c49487bffd56dde42c7bec0da2f50642 Gerrit-PatchSet: 3 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 22 21:52:20 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 21:52:20 +0000 Subject: [ABANDON] osmo-bts[master]: log: l1sap: add 0x to hex output of chan_nr, 5 times In-Reply-To: References: Message-ID: Neels Hofmeyr has abandoned this change. Change subject: log: l1sap: add 0x to hex output of chan_nr, 5 times ...................................................................... Abandoned on wrong branch -- To view, visit https://gerrit.osmocom.org/743 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: abandon Gerrit-Change-Id: I35c8b53146c3451cb6fd3fe7c0d123a4af4a69c1 Gerrit-PatchSet: 2 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 22 21:52:54 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 21:52:54 +0000 Subject: [ABANDON] osmo-bts[master]: log causing rx event for lchan_lookup errors In-Reply-To: References: Message-ID: Neels Hofmeyr has abandoned this change. Change subject: log causing rx event for lchan_lookup errors ...................................................................... Abandoned on wrong branch (?) -- To view, visit https://gerrit.osmocom.org/744 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: abandon Gerrit-Change-Id: I27ea7c4631b87f1d6ef57895306209bf3ccdc739 Gerrit-PatchSet: 2 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 22 21:53:41 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 21:53:41 +0000 Subject: [PATCH] osmo-bts[master]: log: l1sap: add 0x to hex output of chan_nr, 5 times Message-ID: Review at https://gerrit.osmocom.org/745 log: l1sap: add 0x to hex output of chan_nr, 5 times Change-Id: I187a74fd255dbdfb9bfb1e32786031a66f013efb --- M src/common/l1sap.c 1 file changed, 5 insertions(+), 5 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/45/745/1 diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 6498103..d229728 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -403,7 +403,7 @@ struct bts_ul_meas ulm; struct gsm_lchan *lchan; - DEBUGP(DL1P, "MPH_INFO meas ind chan_nr=%02x\n", + DEBUGP(DL1P, "MPH_INFO meas ind chan_nr=0x%02x\n", info_meas_ind->chan_nr); lchan = get_active_lchan_by_chan_nr(trx, info_meas_ind->chan_nr); @@ -489,7 +489,7 @@ { struct gsm_lchan *lchan; - LOGP(DL1P, LOGL_INFO, "deactivate confirm chan_nr=%02x trx=%d\n", + LOGP(DL1P, LOGL_INFO, "deactivate confirm chan_nr=0x%02x trx=%d\n", info_act_cnf->chan_nr, trx->nr); lchan = get_lchan_by_chan_nr(trx, info_act_cnf->chan_nr); @@ -1145,7 +1145,7 @@ int l1sap_chan_rel(struct gsm_bts_trx *trx, uint8_t chan_nr) { - LOGP(DL1P, LOGL_INFO, "deactivating channel chan_nr=%02x trx=%d\n", + LOGP(DL1P, LOGL_INFO, "deactivating channel chan_nr=0x%02x trx=%d\n", chan_nr, trx->nr); return l1sap_chan_act_dact_modify(trx, chan_nr, PRIM_INFO_DEACTIVATE, @@ -1156,7 +1156,7 @@ { struct gsm_lchan *lchan = get_lchan_by_chan_nr(trx, chan_nr); - LOGP(DL1P, LOGL_INFO, "deactivating sacch chan_nr=%02x trx=%d\n", + LOGP(DL1P, LOGL_INFO, "deactivating sacch chan_nr=0x%02x trx=%d\n", chan_nr, trx->nr); lchan->sacch_deact = 1; @@ -1167,7 +1167,7 @@ int l1sap_chan_modify(struct gsm_bts_trx *trx, uint8_t chan_nr) { - LOGP(DL1P, LOGL_INFO, "modifying channel chan_nr=%02x trx=%d\n", + LOGP(DL1P, LOGL_INFO, "modifying channel chan_nr=0x%02x trx=%d\n", chan_nr, trx->nr); return l1sap_chan_act_dact_modify(trx, chan_nr, PRIM_INFO_MODIFY, 0); -- To view, visit https://gerrit.osmocom.org/745 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I187a74fd255dbdfb9bfb1e32786031a66f013efb Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 22 21:55:25 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 21:55:25 +0000 Subject: [PATCH] osmo-bts[master]: log causing rx event for lchan_lookup errors Message-ID: Review at https://gerrit.osmocom.org/746 log causing rx event for lchan_lookup errors Add log_name to lchan_lookup() and pass such from the various RSL rx events that call it to validate the RSL chan_nr. Change-Id: I0d9923f47ac655b204169eec302d607412d5754d --- M src/common/rsl.c 1 file changed, 10 insertions(+), 8 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/46/746/1 diff --git a/src/common/rsl.c b/src/common/rsl.c index 490ae28..622fdae 100644 --- a/src/common/rsl.c +++ b/src/common/rsl.c @@ -144,19 +144,21 @@ return rsl_tx_error_report(trx, RSL_ERR_IE_CONTENT); } -static struct gsm_lchan *lchan_lookup(struct gsm_bts_trx *trx, uint8_t chan_nr) +static struct gsm_lchan *lchan_lookup(struct gsm_bts_trx *trx, uint8_t chan_nr, + const char *log_name) { int rc; struct gsm_lchan *lchan = rsl_lchan_lookup(trx, chan_nr, &rc); if (!lchan) { - LOGP(DRSL, LOGL_ERROR, "unknown chan_nr=0x%02x\n", chan_nr); + LOGP(DRSL, LOGL_ERROR, "%sunknown chan_nr=0x%02x\n", log_name, + chan_nr); return NULL; } if (rc < 0) - LOGP(DRSL, LOGL_ERROR, "%s mismatching chan_nr=0x%02x\n", - gsm_ts_and_pchan_name(lchan->ts), chan_nr); + LOGP(DRSL, LOGL_ERROR, "%s %smismatching chan_nr=0x%02x\n", + gsm_ts_and_pchan_name(lchan->ts), log_name, chan_nr); return lchan; } @@ -2080,7 +2082,7 @@ } msg->l3h = (unsigned char *)rh + sizeof(*rh); - lchan = lchan_lookup(trx, rh->chan_nr); + lchan = lchan_lookup(trx, rh->chan_nr, "RSL rx RLL: "); if (!lchan) { LOGP(DRLL, LOGL_NOTICE, "Rx RLL %s for unknown lchan\n", rsl_msg_name(rh->c.msg_type)); @@ -2224,7 +2226,7 @@ } msg->l3h = (unsigned char *)cch + sizeof(*cch); - msg->lchan = lchan_lookup(trx, cch->chan_nr); + msg->lchan = lchan_lookup(trx, cch->chan_nr, "RSL rx CCHAN: "); if (!msg->lchan) { LOGP(DRSL, LOGL_ERROR, "Rx RSL %s for unknown lchan\n", rsl_msg_name(cch->c.msg_type)); @@ -2278,7 +2280,7 @@ } msg->l3h = (unsigned char *)dch + sizeof(*dch); - msg->lchan = lchan_lookup(trx, dch->chan_nr); + msg->lchan = lchan_lookup(trx, dch->chan_nr, "RSL rx DCHAN: "); if (!msg->lchan) { LOGP(DRSL, LOGL_ERROR, "Rx RSL %s for unknown lchan\n", rsl_or_ipac_msg_name(dch->c.msg_type)); @@ -2377,7 +2379,7 @@ } msg->l3h = (unsigned char *)dch + sizeof(*dch); - msg->lchan = lchan_lookup(trx, dch->chan_nr); + msg->lchan = lchan_lookup(trx, dch->chan_nr, "RSL rx IPACC: "); if (!msg->lchan) { LOGP(DRSL, LOGL_ERROR, "Rx RSL %s for unknow lchan\n", rsl_msg_name(dch->c.msg_type)); -- To view, visit https://gerrit.osmocom.org/746 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I0d9923f47ac655b204169eec302d607412d5754d Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 22 22:00:17 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 22:00:17 +0000 Subject: [PATCH] osmo-bts[master]: common/rsl: move decision whether to chan act ack/nack to co... Message-ID: Review at https://gerrit.osmocom.org/747 common/rsl: move decision whether to chan act ack/nack to common function Prepare for a dyn TS patch that needs to call rsl_tx_chan_act_ack() directly without the rel_act_kind decision. Add function rsl_tx_chan_act_acknack() to wrap rsl_tx_chan_act_ack() and rsl_tx_chan_act_nack(). Move the decision whether to drop the ack/nack, based on lchan->rel_act_kind, to the new function, losing some code dup. Change all callers to use the new function; drop the two older ones from rsl.h and make them static. Note: for nack, the exception for dyn TS in PDCH mode was missing (rsl_tx_chan_act_nack() had only the rel_act_kind != LCHAN_REL_ACT_RSL condition, but should also have had the dyn TS exception as in rsl_tx_chan_act_ack()). I already know that this exception will again be removed in an upcoming commit, but for patch readability it logically makes sense to add it here. To easily include the nack case, drop the check for which pchan the dyn TS is operating as, because a rel_act_kind == LCHAN_REL_ACT_PCU implies that it is either already in or trying to become PDCH mode. Change-Id: I57ba60c670730c6d7877a6a9b96ece0a7679a0bb --- M include/osmo-bts/rsl.h M src/common/l1sap.c M src/common/rsl.c 3 files changed, 32 insertions(+), 34 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/47/747/1 diff --git a/include/osmo-bts/rsl.h b/include/osmo-bts/rsl.h index 72ed2fc..093e9cb 100644 --- a/include/osmo-bts/rsl.h +++ b/include/osmo-bts/rsl.h @@ -19,8 +19,7 @@ uint8_t ra, uint8_t acc_delay); int rsl_tx_est_ind(struct gsm_lchan *lchan, uint8_t link_id, uint8_t *data, int len); -int rsl_tx_chan_act_ack(struct gsm_lchan *lchan); -int rsl_tx_chan_act_nack(struct gsm_lchan *lchan, uint8_t cause); +int rsl_tx_chan_act_acknack(struct gsm_lchan *lchan, uint8_t cause); int rsl_tx_conn_fail(struct gsm_lchan *lchan, uint8_t cause); int rsl_tx_rf_rel_ack(struct gsm_lchan *lchan); int rsl_tx_hando_det(struct gsm_lchan *lchan, uint8_t *ho_delay); diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 6498103..3802e25 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -466,10 +466,7 @@ lchan = get_lchan_by_chan_nr(trx, info_act_cnf->chan_nr); - if (info_act_cnf->cause) - rsl_tx_chan_act_nack(lchan, info_act_cnf->cause); - else - rsl_tx_chan_act_ack(lchan); + rsl_tx_chan_act_acknack(lchan, info_act_cnf->cause); /* During PDCH ACT, this is where we know that the PCU is done * activating a PDCH, and PDCH switchover is complete. See diff --git a/src/common/rsl.c b/src/common/rsl.c index 490ae28..37c142c 100644 --- a/src/common/rsl.c +++ b/src/common/rsl.c @@ -535,26 +535,12 @@ } /* 8.4.2 sending CHANnel ACTIVation ACKnowledge */ -int rsl_tx_chan_act_ack(struct gsm_lchan *lchan) +static int rsl_tx_chan_act_ack(struct gsm_lchan *lchan) { struct gsm_time *gtime = get_time(lchan->ts->trx->bts); struct msgb *msg; uint8_t chan_nr = gsm_lchan2chan_nr(lchan); uint8_t ie[2]; - - /* - * Normally, PDCH activation via PCU does not ack back to the BSC. - * But for GSM_PCHAN_TCH_F_TCH_H_PDCH, send a non-standard act ack for - * LCHAN_REL_ACT_PCU, since the act req came from RSL initially. - */ - if (lchan->rel_act_kind != LCHAN_REL_ACT_RSL - && !(lchan->ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH - && lchan->ts->dyn.pchan_is == GSM_PCHAN_PDCH - && lchan->rel_act_kind == LCHAN_REL_ACT_PCU)) { - LOGP(DRSL, LOGL_NOTICE, "%s not sending CHAN ACT ACK\n", - gsm_lchan_name(lchan)); - return 0; - } LOGP(DRSL, LOGL_NOTICE, "%s Tx CHAN ACT ACK\n", gsm_lchan_name(lchan)); @@ -596,16 +582,10 @@ } /* 8.4.3 sending CHANnel ACTIVation Negative ACK */ -int rsl_tx_chan_act_nack(struct gsm_lchan *lchan, uint8_t cause) +static int rsl_tx_chan_act_nack(struct gsm_lchan *lchan, uint8_t cause) { struct msgb *msg; uint8_t chan_nr = gsm_lchan2chan_nr(lchan); - - if (lchan->rel_act_kind != LCHAN_REL_ACT_RSL) { - LOGP(DRSL, LOGL_DEBUG, "%s not sending CHAN ACT NACK.\n", - gsm_lchan_name(lchan)); - return 0; - } LOGP(DRSL, LOGL_NOTICE, "%s Sending Channel Activated NACK: cause = 0x%02x\n", @@ -621,6 +601,27 @@ msg->trx = lchan->ts->trx; return abis_bts_rsl_sendmsg(msg); +} + +/* Send an RSL Channel Activation Ack if cause is zero, a Nack otherwise. */ +int rsl_tx_chan_act_acknack(struct gsm_lchan *lchan, uint8_t cause) +{ + /* + * Normally, PDCH activation via PCU does not ack back to the BSC. + * But for GSM_PCHAN_TCH_F_TCH_H_PDCH, send a non-standard act ack for + * LCHAN_REL_ACT_PCU, since the act req came from RSL initially. + */ + if (lchan->rel_act_kind != LCHAN_REL_ACT_RSL + && !(lchan->ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH + && lchan->rel_act_kind == LCHAN_REL_ACT_PCU)) { + LOGP(DRSL, LOGL_NOTICE, "%s not sending CHAN ACT %s\n", + gsm_lchan_name(lchan), rc ? "NACK" : "ACK"); + return 0; + } + + if (rc) + return rsl_tx_chan_act_nack(lchan); + return rsl_tx_chan_act_ack(lchan); } /* 8.4.4 sending CONNection FAILure */ @@ -782,7 +783,7 @@ LOGP(DRSL, LOGL_ERROR, "%s: error: lchan is not available, but in state: %s.\n", gsm_lchan_name(lchan), gsm_lchans_name(lchan->state)); - return rsl_tx_chan_act_nack(lchan, RSL_ERR_EQUIPMENT_FAIL); + return rsl_tx_chan_act_acknack(lchan, RSL_ERR_EQUIPMENT_FAIL); } if (ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) { @@ -797,8 +798,8 @@ */ rc = dyn_ts_l1_reconnect(ts, msg); if (rc) - return rsl_tx_chan_act_nack(lchan, - RSL_ERR_NORMAL_UNSPEC); + return rsl_tx_chan_act_acknack(lchan, + RSL_ERR_NORMAL_UNSPEC); /* indicate that the msgb should not be freed. */ return 1; } @@ -814,7 +815,7 @@ /* 9.3.3 Activation Type */ if (!TLVP_PRESENT(&tp, RSL_IE_ACT_TYPE)) { LOGP(DRSL, LOGL_NOTICE, "missing Activation Type\n"); - return rsl_tx_chan_act_nack(lchan, RSL_ERR_MAND_IE_ERROR); + return rsl_tx_chan_act_acknack(lchan, RSL_ERR_MAND_IE_ERROR); } type = *TLVP_VAL(&tp, RSL_IE_ACT_TYPE); @@ -822,7 +823,8 @@ if (type != RSL_ACT_OSMO_PDCH) { if (!TLVP_PRESENT(&tp, RSL_IE_CHAN_MODE)) { LOGP(DRSL, LOGL_NOTICE, "missing Channel Mode\n"); - return rsl_tx_chan_act_nack(lchan, RSL_ERR_MAND_IE_ERROR); + return rsl_tx_chan_act_acknack(lchan, + RSL_ERR_MAND_IE_ERROR); } cm = (struct rsl_ie_chan_mode *) TLVP_VAL(&tp, RSL_IE_CHAN_MODE); lchan_tchmode_from_cmode(lchan, cm); @@ -954,7 +956,7 @@ /* actually activate the channel in the BTS */ rc = l1sap_chan_act(lchan->ts->trx, dch->chan_nr, &tp); if (rc < 0) - return rsl_tx_chan_act_nack(lchan, -rc); + return rsl_tx_chan_act_acknack(lchan, -rc); return 0; } -- To view, visit https://gerrit.osmocom.org/747 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I57ba60c670730c6d7877a6a9b96ece0a7679a0bb Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 22 22:00:17 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 22:00:17 +0000 Subject: [PATCH] osmo-bts[master]: dyn TS: if PCU is not connected, allow operation as TCH Message-ID: Review at https://gerrit.osmocom.org/748 dyn TS: if PCU is not connected, allow operation as TCH Before this patch, Osmocom style TCH/F_TCH/H_PDCH dyn TS were paralyzed if no PCU was running. The state of the dyn TS would lock up in the PDCH activation phase since the PCU never completed the process. Make more robust, i.e. don't concern the BSC with PDCH activation failures. This matches the way plain PDCH TS work: besides declaring the TS as PDCH, the BSC is not involved and is not told about errors. During PDCH deactivation, still wait for the PCU to tear down the PDTCH SAPIs, but in case no PCU is connected, send a rel ack right away. Thus, the BSC will happily switch Osmocom style dynamic timeslots to and from PDCH mode, using the dyn TS as voice channels as needed, and not caring about possible PDCH failures. GPRS starts working right away as soon as a PCU connects, regardless of dyn TS having been used for voice any number of times, and without another switchover needed. In detail: In rsl_rx_chan_activ(), upon receiving a PDCH activation, send an RSL chan act ack right away, unconditionally (with an explaining comment). Do not concern the Abis link with PDCH activation failures. Since we're acking right away now, drop the chan act ack that would follow after the PCU activation: as before dyn TS, only send acks and nacks for rel_act_kind == LCHAN_REL_ACT_RSL (PDCH runs as LCHAN_REL_ACT_PCU). In dyn_ts_pdch_release, indicate that the PCU is not connected by means of returning 1. In rsl_rx_rf_chan_rel(), use this indicator to send a rel ack right away if the PCU is not connected. Change-Id: I2a0b9730197786b99ff3bc1f08c75f7d279cb1f7 --- M src/common/rsl.c 1 file changed, 29 insertions(+), 11 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/48/748/1 diff --git a/src/common/rsl.c b/src/common/rsl.c index 37c142c..f96f0e5 100644 --- a/src/common/rsl.c +++ b/src/common/rsl.c @@ -606,14 +606,7 @@ /* Send an RSL Channel Activation Ack if cause is zero, a Nack otherwise. */ int rsl_tx_chan_act_acknack(struct gsm_lchan *lchan, uint8_t cause) { - /* - * Normally, PDCH activation via PCU does not ack back to the BSC. - * But for GSM_PCHAN_TCH_F_TCH_H_PDCH, send a non-standard act ack for - * LCHAN_REL_ACT_PCU, since the act req came from RSL initially. - */ - if (lchan->rel_act_kind != LCHAN_REL_ACT_RSL - && !(lchan->ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH - && lchan->rel_act_kind == LCHAN_REL_ACT_PCU)) { + if (lchan->rel_act_kind != LCHAN_REL_ACT_RSL) { LOGP(DRSL, LOGL_NOTICE, "%s not sending CHAN ACT %s\n", gsm_lchan_name(lchan), rc ? "NACK" : "ACK"); return 0; @@ -931,6 +924,24 @@ if (ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH && ts->dyn.pchan_want == GSM_PCHAN_PDCH) { /* + * We ack the activation to the BSC right away, regardless of + * the PCU succeeding or not; if a dynamic timeslot fails to go + * to PDCH mode for any reason, the BSC should still be able to + * switch it back to TCH modes. So for the BSC, it is not + * helpful in any way to know that a PDCH channel fails to + * work, e.g. if the PCU is not running. If the BSC tells us to + * do PDCH, we do our best, and keep the details on the BTS and + * PCU level. This is kind of analogous to how plain PDCH TS + * operate. Directly call rsl_tx_chan_act_ack() instead of + * rsl_tx_chan_act_acknack() because we don't want/need to + * decide whether to drop due to lchan->rel_act_kind. + */ + rc = rsl_tx_chan_act_ack(lchan); + if (rc < 0) + LOGP(DRSL, LOGL_ERROR, "%s Cannot send act ack: %d\n", + gsm_ts_and_pchan_name(ts), rc); + + /* * pcu_tx_info_ind() will pick up the ts->dyn.pchan_want. If * the PCU is not connected yet, ignore for now; the PCU will * catch up (and send the RSL ack) once it connects. @@ -981,7 +992,7 @@ /* PCU not connected yet. Just record the new type and done, * the PCU will pick it up once connected. */ ts->dyn.pchan_is = GSM_PCHAN_NONE; - return 0; + return 1; } return pcu_tx_info_ind(); @@ -990,6 +1001,8 @@ /* 8.4.14 RF CHANnel RELease is received */ static int rsl_rx_rf_chan_rel(struct gsm_lchan *lchan, uint8_t chan_nr) { + int rc; + if (lchan->abis_ip.rtp_socket) { rsl_tx_ipac_dlcx_ind(lchan, RSL_ERR_NORMAL_UNSPEC); osmo_rtp_socket_free(lchan->abis_ip.rtp_socket); @@ -1004,8 +1017,13 @@ /* Dynamic channel in PDCH mode is released via PCU */ if (lchan->ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH - && lchan->ts->dyn.pchan_is == GSM_PCHAN_PDCH) - return dyn_ts_pdch_release(lchan); + && lchan->ts->dyn.pchan_is == GSM_PCHAN_PDCH) { + rc = dyn_ts_pdch_release(lchan); + if (rc != 1) + return rc; + /* If the PCU is not connected, continue right away. */ + return rsl_tx_rf_rel_ack(lchan); + } l1sap_chan_rel(lchan->ts->trx, chan_nr); -- To view, visit https://gerrit.osmocom.org/748 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I2a0b9730197786b99ff3bc1f08c75f7d279cb1f7 Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 22 22:13:54 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 22:13:54 +0000 Subject: [PATCH] osmo-bts[master]: common/rsl: move decision whether to chan act ack/nack to co... In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/747 to look at the new patch set (#2). common/rsl: move decision whether to chan act ack/nack to common function Prepare for a dyn TS patch that needs to call rsl_tx_chan_act_ack() directly without the rel_act_kind decision. Add function rsl_tx_chan_act_acknack() to wrap rsl_tx_chan_act_ack() and rsl_tx_chan_act_nack(). Move the decision whether to drop the ack/nack, based on lchan->rel_act_kind, to the new function, losing some code dup. Change all callers to use the new function; drop the two older ones from rsl.h and make them static. Note: for nack, the exception for dyn TS in PDCH mode was missing (rsl_tx_chan_act_nack() had only the rel_act_kind != LCHAN_REL_ACT_RSL condition, but should also have had the dyn TS exception as in rsl_tx_chan_act_ack()). I already know that this exception will again be removed in an upcoming commit, but for patch readability it logically makes sense to add it here. To easily include the nack case, drop the check for which pchan the dyn TS is operating as, because a rel_act_kind == LCHAN_REL_ACT_PCU implies that it is either already in or trying to become PDCH mode. Change-Id: I57ba60c670730c6d7877a6a9b96ece0a7679a0bb --- M include/osmo-bts/rsl.h M src/common/l1sap.c M src/common/rsl.c 3 files changed, 32 insertions(+), 34 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/47/747/2 diff --git a/include/osmo-bts/rsl.h b/include/osmo-bts/rsl.h index 72ed2fc..093e9cb 100644 --- a/include/osmo-bts/rsl.h +++ b/include/osmo-bts/rsl.h @@ -19,8 +19,7 @@ uint8_t ra, uint8_t acc_delay); int rsl_tx_est_ind(struct gsm_lchan *lchan, uint8_t link_id, uint8_t *data, int len); -int rsl_tx_chan_act_ack(struct gsm_lchan *lchan); -int rsl_tx_chan_act_nack(struct gsm_lchan *lchan, uint8_t cause); +int rsl_tx_chan_act_acknack(struct gsm_lchan *lchan, uint8_t cause); int rsl_tx_conn_fail(struct gsm_lchan *lchan, uint8_t cause); int rsl_tx_rf_rel_ack(struct gsm_lchan *lchan); int rsl_tx_hando_det(struct gsm_lchan *lchan, uint8_t *ho_delay); diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 6498103..3802e25 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -466,10 +466,7 @@ lchan = get_lchan_by_chan_nr(trx, info_act_cnf->chan_nr); - if (info_act_cnf->cause) - rsl_tx_chan_act_nack(lchan, info_act_cnf->cause); - else - rsl_tx_chan_act_ack(lchan); + rsl_tx_chan_act_acknack(lchan, info_act_cnf->cause); /* During PDCH ACT, this is where we know that the PCU is done * activating a PDCH, and PDCH switchover is complete. See diff --git a/src/common/rsl.c b/src/common/rsl.c index 490ae28..8905028 100644 --- a/src/common/rsl.c +++ b/src/common/rsl.c @@ -535,26 +535,12 @@ } /* 8.4.2 sending CHANnel ACTIVation ACKnowledge */ -int rsl_tx_chan_act_ack(struct gsm_lchan *lchan) +static int rsl_tx_chan_act_ack(struct gsm_lchan *lchan) { struct gsm_time *gtime = get_time(lchan->ts->trx->bts); struct msgb *msg; uint8_t chan_nr = gsm_lchan2chan_nr(lchan); uint8_t ie[2]; - - /* - * Normally, PDCH activation via PCU does not ack back to the BSC. - * But for GSM_PCHAN_TCH_F_TCH_H_PDCH, send a non-standard act ack for - * LCHAN_REL_ACT_PCU, since the act req came from RSL initially. - */ - if (lchan->rel_act_kind != LCHAN_REL_ACT_RSL - && !(lchan->ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH - && lchan->ts->dyn.pchan_is == GSM_PCHAN_PDCH - && lchan->rel_act_kind == LCHAN_REL_ACT_PCU)) { - LOGP(DRSL, LOGL_NOTICE, "%s not sending CHAN ACT ACK\n", - gsm_lchan_name(lchan)); - return 0; - } LOGP(DRSL, LOGL_NOTICE, "%s Tx CHAN ACT ACK\n", gsm_lchan_name(lchan)); @@ -596,16 +582,10 @@ } /* 8.4.3 sending CHANnel ACTIVation Negative ACK */ -int rsl_tx_chan_act_nack(struct gsm_lchan *lchan, uint8_t cause) +static int rsl_tx_chan_act_nack(struct gsm_lchan *lchan, uint8_t cause) { struct msgb *msg; uint8_t chan_nr = gsm_lchan2chan_nr(lchan); - - if (lchan->rel_act_kind != LCHAN_REL_ACT_RSL) { - LOGP(DRSL, LOGL_DEBUG, "%s not sending CHAN ACT NACK.\n", - gsm_lchan_name(lchan)); - return 0; - } LOGP(DRSL, LOGL_NOTICE, "%s Sending Channel Activated NACK: cause = 0x%02x\n", @@ -621,6 +601,27 @@ msg->trx = lchan->ts->trx; return abis_bts_rsl_sendmsg(msg); +} + +/* Send an RSL Channel Activation Ack if cause is zero, a Nack otherwise. */ +int rsl_tx_chan_act_acknack(struct gsm_lchan *lchan, uint8_t cause) +{ + /* + * Normally, PDCH activation via PCU does not ack back to the BSC. + * But for GSM_PCHAN_TCH_F_TCH_H_PDCH, send a non-standard act ack for + * LCHAN_REL_ACT_PCU, since the act req came from RSL initially. + */ + if (lchan->rel_act_kind != LCHAN_REL_ACT_RSL + && !(lchan->ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH + && lchan->rel_act_kind == LCHAN_REL_ACT_PCU)) { + LOGP(DRSL, LOGL_NOTICE, "%s not sending CHAN ACT %s\n", + gsm_lchan_name(lchan), cause ? "NACK" : "ACK"); + return 0; + } + + if (cause) + return rsl_tx_chan_act_nack(lchan, cause); + return rsl_tx_chan_act_ack(lchan); } /* 8.4.4 sending CONNection FAILure */ @@ -782,7 +783,7 @@ LOGP(DRSL, LOGL_ERROR, "%s: error: lchan is not available, but in state: %s.\n", gsm_lchan_name(lchan), gsm_lchans_name(lchan->state)); - return rsl_tx_chan_act_nack(lchan, RSL_ERR_EQUIPMENT_FAIL); + return rsl_tx_chan_act_acknack(lchan, RSL_ERR_EQUIPMENT_FAIL); } if (ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) { @@ -797,8 +798,8 @@ */ rc = dyn_ts_l1_reconnect(ts, msg); if (rc) - return rsl_tx_chan_act_nack(lchan, - RSL_ERR_NORMAL_UNSPEC); + return rsl_tx_chan_act_acknack(lchan, + RSL_ERR_NORMAL_UNSPEC); /* indicate that the msgb should not be freed. */ return 1; } @@ -814,7 +815,7 @@ /* 9.3.3 Activation Type */ if (!TLVP_PRESENT(&tp, RSL_IE_ACT_TYPE)) { LOGP(DRSL, LOGL_NOTICE, "missing Activation Type\n"); - return rsl_tx_chan_act_nack(lchan, RSL_ERR_MAND_IE_ERROR); + return rsl_tx_chan_act_acknack(lchan, RSL_ERR_MAND_IE_ERROR); } type = *TLVP_VAL(&tp, RSL_IE_ACT_TYPE); @@ -822,7 +823,8 @@ if (type != RSL_ACT_OSMO_PDCH) { if (!TLVP_PRESENT(&tp, RSL_IE_CHAN_MODE)) { LOGP(DRSL, LOGL_NOTICE, "missing Channel Mode\n"); - return rsl_tx_chan_act_nack(lchan, RSL_ERR_MAND_IE_ERROR); + return rsl_tx_chan_act_acknack(lchan, + RSL_ERR_MAND_IE_ERROR); } cm = (struct rsl_ie_chan_mode *) TLVP_VAL(&tp, RSL_IE_CHAN_MODE); lchan_tchmode_from_cmode(lchan, cm); @@ -954,7 +956,7 @@ /* actually activate the channel in the BTS */ rc = l1sap_chan_act(lchan->ts->trx, dch->chan_nr, &tp); if (rc < 0) - return rsl_tx_chan_act_nack(lchan, -rc); + return rsl_tx_chan_act_acknack(lchan, -rc); return 0; } -- To view, visit https://gerrit.osmocom.org/747 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I57ba60c670730c6d7877a6a9b96ece0a7679a0bb Gerrit-PatchSet: 2 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 22 22:15:54 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 22:15:54 +0000 Subject: osmo-bts[master]: common/rsl: move decision whether to chan act ack/nack to co... In-Reply-To: References: Message-ID: Patch Set 1: (1 comment) https://gerrit.osmocom.org/#/c/747/1/src/common/rsl.c File src/common/rsl.c: Line 622: if (rc) had accidentally pushed the wrong branch for review :P -- To view, visit https://gerrit.osmocom.org/747 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I57ba60c670730c6d7877a6a9b96ece0a7679a0bb Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Mon Aug 22 22:17:47 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 22:17:47 +0000 Subject: osmo-bts[master]: dyn TS: measurement: use correct nr of subslots, rm code dup In-Reply-To: References: Message-ID: Patch Set 3: ...and this is still waiting for 669 (and its two parent revisions) to be able to build -- To view, visit https://gerrit.osmocom.org/675 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I9d9df470c49487bffd56dde42c7bec0da2f50642 Gerrit-PatchSet: 3 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 22 22:18:03 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 22:18:03 +0000 Subject: osmo-bts[master]: cosmetic: common ts_is_pdch() In-Reply-To: References: Message-ID: Patch Set 3: ...and this is still waiting for 669 (and its two parent revisions) to be able to build -- To view, visit https://gerrit.osmocom.org/676 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ib78d663fdbac5a1d7053f1b9d543649b66da00e2 Gerrit-PatchSet: 3 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 22 22:18:19 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 22:18:19 +0000 Subject: osmo-bts[master]: dyn TS: sysmo, lc15: ph_data_req: fix PDCH mode detection In-Reply-To: References: Message-ID: Patch Set 3: ...and this is still waiting for 669 (and its two parent revisions) to be able to build -- To view, visit https://gerrit.osmocom.org/677 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I6136cb42a4d627ebefc963eb5321fadfe63cca4b Gerrit-PatchSet: 3 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 22 22:19:11 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 22:19:11 +0000 Subject: openbsc[master]: comment: gsm48_gmm_sendmsg(): add spec reference on encryptable In-Reply-To: References: Message-ID: Patch Set 2: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/689 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I54a3bc518bc38e38b78f6e9ea3705e4fbd5ffb98 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 22 22:19:13 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 22:19:13 +0000 Subject: [MERGED] openbsc[master]: comment: gsm48_gmm_sendmsg(): add spec reference on encryptable In-Reply-To: References: Message-ID: Neels Hofmeyr has submitted this change and it was merged. Change subject: comment: gsm48_gmm_sendmsg(): add spec reference on encryptable ...................................................................... comment: gsm48_gmm_sendmsg(): add spec reference on encryptable Change-Id: I54a3bc518bc38e38b78f6e9ea3705e4fbd5ffb98 --- M openbsc/src/gprs/gprs_gmm.c 1 file changed, 3 insertions(+), 1 deletion(-) Approvals: Neels Hofmeyr: Looks good to me, approved Jenkins Builder: Verified diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index aa49919..036164f 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -130,7 +130,9 @@ return sgsn->cfg.timers.T3314 + (sgsn->cfg.timers.T3312 + 4 * 60); } -/* Send a message through the underlying layer */ +/* Send a message through the underlying layer. + * For param encryptable, see 3GPP TS 24.008 ? 4.7.1.2 and + * gsm48_hdr_gmm_cipherable(). Pass false for not cipherable messages. */ static int gsm48_gmm_sendmsg(struct msgb *msg, int command, struct sgsn_mm_ctx *mm, bool encryptable) { -- To view, visit https://gerrit.osmocom.org/689 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I54a3bc518bc38e38b78f6e9ea3705e4fbd5ffb98 Gerrit-PatchSet: 3 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 22 22:28:48 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 22:28:48 +0000 Subject: openbsc[master]: IuPS: sgsn-test: link Iu related libs In-Reply-To: References: Message-ID: Patch Set 1: > http://jenkins.osmocom.org/jenkins/job/OpenBSC-gerrit/754/ : > FAILURE The build failure: The "undefined references" talloc_asn1_ctx asn1_xer_print are present in iu.c in libiu, which is being linked. The very next commit in this branch, 731, no longer shows this build failure. It seems libiu is not being linked at all until it is used the first time by 731... -- To view, visit https://gerrit.osmocom.org/730 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I4c05f15c29797456ddcd7c95bfb7dfd480101577 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: daniel Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 22 22:32:16 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 22:32:16 +0000 Subject: openbsc[master]: IuPS: dev hack: init hardcoded Ki on ATT REQ In-Reply-To: References: Message-ID: Patch Set 1: > http://jenkins.osmocom.org/jenkins/job/OpenBSC-gerrit/745/ : > FAILURE interesting build failure: time="2016-08-22T16:09:58+02:00" level=fatal msg="Error response from daemon: Cannot destroy container 5d0bc920059450e376bc2fabb86900a68140de40e441c8470e75d4e44ee886a9: Driver aufs failed to remove root filesystem 5d0bc920059450e376bc2fabb86900a68140de40e441c8470e75d4e44ee886a9: rename /var/lib/docker/aufs/diff/5d0bc920059450e376bc2fabb86900a68140de40e441c8470e75d4e44ee886a9 /var/lib/docker/aufs/diff/5d0bc920059450e376bc2fabb86900a68140de40e441c8470e75d4e44ee886a9-removing: device or resource busy" -- To view, visit https://gerrit.osmocom.org/734 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieca45960fa941a3a706c6e479b04b9f2ef89d860 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 22 22:37:58 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 22:37:58 +0000 Subject: openbsc[master]: IuPS: sgsn-test: link Iu related libs In-Reply-To: References: Message-ID: Patch Set 1: > http://jenkins.osmocom.org/jenkins/job/OpenBSC-gerrit/742/ : > FAILURE BTW, one of the first builds failed due to a timeout, first time I'm seeing this after we reduced the nr of concurrent build jobs: http://jenkins.osmocom.org/jenkins/job/OpenBSC-gerrit/IU=--disable-iu,MGCP=--disable-mgcp-transcoding,SMPP=--enable-smpp,label=linux_amd64_debian8/742/console ERROR: testBSCreload (__main__.TestVTYNAT) ---------------------------------------------------------------------- Traceback (most recent call last): File "./vty_test_runner.py", line 782, in testBSCreload msc = nat_msc_test(self, ip, port) File "./vty_test_runner.py", line 1237, in nat_msc_test conn, addr = msc.accept() File "/usr/lib/python2.7/socket.py", line 202, in accept sock, addr = self._sock.accept() timeout: timed out -- To view, visit https://gerrit.osmocom.org/730 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I4c05f15c29797456ddcd7c95bfb7dfd480101577 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: daniel Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 22 22:43:23 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 22:43:23 +0000 Subject: openbsc[master]: IuPS: sgsn-test: link Iu related libs In-Reply-To: References: Message-ID: Patch Set 1: > It seems libiu is not being linked at all until it is used the > first time by 731... Then again, 729 already uses libiu elements like iu_init() etc., also some in gprs_gmm.c. Am slightly puzzled. Should I squash 730 and 731 together? -- To view, visit https://gerrit.osmocom.org/730 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I4c05f15c29797456ddcd7c95bfb7dfd480101577 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: daniel Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 22 22:53:45 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 22:53:45 +0000 Subject: osmo-pcu[master]: tbf: add llc_queue_size() to check llc_queue is valid before... In-Reply-To: References: Message-ID: Patch Set 1: (2 comments) https://gerrit.osmocom.org/#/c/724/1//COMMIT_MSG Commit Message: Line 9: gcc6 is optimizing if (!this) {CODE} as this is assumed to never be which "if (!this)" are you referring to? would be good to clarify in this commit log. Currently I fail to see the connection. https://gerrit.osmocom.org/#/c/724/1/src/tbf.cpp File src/tbf.cpp: Line 194: return m_ms ? m_ms->llc_queue()->size() : 0; nitpick... from a code maintenance point of view, I guess it would be better to call this->llc_queue() here. Then there is only "one" pivotal place that decides on where llc_queue is coming from. ("one" in quotes because of the const dup) -- To view, visit https://gerrit.osmocom.org/724 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I88cc3180f8f86785e3f07981895dabddf50b60a2 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Mon Aug 22 22:59:08 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 22:59:08 +0000 Subject: openbsc[master]: libmsc/bsc: split rate counters into bsc and msc group In-Reply-To: References: Message-ID: Patch Set 3: Code-Review-1 (2 comments) excellent! I have the MSC/BSC split in the 3G queue, this will be very welcome there. Let's just drop that unrelated change... https://gerrit.osmocom.org/#/c/646/3/openbsc/include/openbsc/transaction.h File openbsc/include/openbsc/transaction.h: Line 17: /* Back pointer to the network struct */ unrelated cosmetic change, Should not be part of this commit. Line 25: while at it you could also fix this whitespace :P (in the separate cosmetic commit) -- To view, visit https://gerrit.osmocom.org/646 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I7361033cd1eb919ec3c2ea2652f40ab8c75b2f99 Gerrit-PatchSet: 3 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Mon Aug 22 23:06:22 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 23:06:22 +0000 Subject: osmo-pcu[master]: llc: fix NULL-pointer check gprs_llc_queue::size() gprs_llc_... In-Reply-To: References: Message-ID: Patch Set 3: > @Holger: it's now ready. your new patch sets didn't change a thing -- but the callers are checked in 724, right? It would be good to refer from one commit log to the other. Something like "All callers now check the NULL pointer by adding llc_queue_size() in a previous commit ..." -- To view, visit https://gerrit.osmocom.org/213 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I918a094e0dc59098a9eb00d152c9ae42d36b3a99 Gerrit-PatchSet: 3 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: lynxis lazus Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 22 23:15:58 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 23:15:58 +0000 Subject: osmo-bts[master]: dyn TS: if PCU is not connected, allow operation as TCH In-Reply-To: References: Message-ID: Patch Set 2: A corresponding Abis doc change is waiting in branch neels/dyn_ts_no_pcu in osmo-gsm-manuals.git. -- To view, visit https://gerrit.osmocom.org/748 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I2a0b9730197786b99ff3bc1f08c75f7d279cb1f7 Gerrit-PatchSet: 2 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 22 23:24:40 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 23:24:40 +0000 Subject: [PATCH] openbsc[master]: log: abis_rsl: don't log 'error' when there is no error Message-ID: Review at https://gerrit.osmocom.org/749 log: abis_rsl: don't log 'error' when there is no error The message 'RF Channel Release due error 0' keeps catching my eye because it says 'error' even though the error code is zero, i.e. no error. This shall end now. Change-Id: Ie0b9d62e8ce85a096c963931e0ae5527b8dc490a --- M openbsc/src/libbsc/abis_rsl.c 1 file changed, 5 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/49/749/1 diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index b84a0b5..096ea29 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -769,7 +769,11 @@ msg->lchan = lchan; msg->dst = lchan->ts->trx->rsl_link; - DEBUGP(DRSL, "%s RF Channel Release CMD due error %d\n", gsm_lchan_name(lchan), error); + if (error) + DEBUGP(DRSL, "%s RF Channel Release due to error: %d\n", + gsm_lchan_name(lchan), error); + else + DEBUGP(DRSL, "%s RF Channel Release\n", gsm_lchan_name(lchan)); if (error) { /* -- To view, visit https://gerrit.osmocom.org/749 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ie0b9d62e8ce85a096c963931e0ae5527b8dc490a Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 22 23:24:40 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 22 Aug 2016 23:24:40 +0000 Subject: [PATCH] openbsc[master]: log causing rx event for lchan_lookup errors Message-ID: Review at https://gerrit.osmocom.org/750 log causing rx event for lchan_lookup errors Add log_name to lchan_lookup() and pass such from the various RSL rx events that call it to validate the RSL chan_nr. Change-Id: Id81e7b8b9c27831923f050a78dfc7d650e687033 --- M openbsc/src/libbsc/abis_rsl.c 1 file changed, 14 insertions(+), 8 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/50/750/1 diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index 096ea29..b4eb350 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -110,19 +110,21 @@ } /* call rsl_lchan_lookup and set the log context */ -static struct gsm_lchan *lchan_lookup(struct gsm_bts_trx *trx, uint8_t chan_nr) +static struct gsm_lchan *lchan_lookup(struct gsm_bts_trx *trx, uint8_t chan_nr, + const char *log_name) { int rc; struct gsm_lchan *lchan = rsl_lchan_lookup(trx, chan_nr, &rc); if (!lchan) { - LOGP(DRSL, LOGL_ERROR, "unknown chan_nr=0x%02x\n", chan_nr); + LOGP(DRSL, LOGL_ERROR, "%sunknown chan_nr=0x%02x\n", + log_name, chan_nr); return NULL; } if (rc < 0) - LOGP(DRSL, LOGL_ERROR, "%s mismatching chan_nr=0x%02x\n", - gsm_ts_and_pchan_name(lchan->ts), chan_nr); + LOGP(DRSL, LOGL_ERROR, "%s %smismatching chan_nr=0x%02x\n", + gsm_ts_and_pchan_name(lchan->ts), log_name, chan_nr); log_set_context(BSC_CTX_LCHAN, lchan); if (lchan->conn) @@ -1430,7 +1432,8 @@ char *ts_name; struct e1inp_sign_link *sign_link = msg->dst; - msg->lchan = lchan_lookup(sign_link->trx, rslh->chan_nr); + msg->lchan = lchan_lookup(sign_link->trx, rslh->chan_nr, + "Abis RSL rx DCHAN: "); ts_name = gsm_lchan_name(msg->lchan); switch (rslh->c.msg_type) { @@ -1791,7 +1794,8 @@ struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg); int rc = 0; - msg->lchan = lchan_lookup(sign_link->trx, rslh->chan_nr); + msg->lchan = lchan_lookup(sign_link->trx, rslh->chan_nr, + "Abis RSL rx CCHAN: "); switch (rslh->c.msg_type) { case RSL_MT_CHAN_RQD: @@ -1892,7 +1896,8 @@ char *ts_name; uint8_t sapi = rllh->link_id & 7; - msg->lchan = lchan_lookup(sign_link->trx, rllh->chan_nr); + msg->lchan = lchan_lookup(sign_link->trx, rllh->chan_nr, + "Abis RSL rx RLL: "); ts_name = gsm_lchan_name(msg->lchan); DEBUGP(DRLL, "%s SAPI=%u ", ts_name, sapi); @@ -2286,7 +2291,8 @@ char *ts_name; int rc = 0; - msg->lchan = lchan_lookup(sign_link->trx, rllh->chan_nr); + msg->lchan = lchan_lookup(sign_link->trx, rllh->chan_nr, + "Abis RSL rx IPACC: "); ts_name = gsm_lchan_name(msg->lchan); switch (rllh->c.msg_type) { -- To view, visit https://gerrit.osmocom.org/750 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Id81e7b8b9c27831923f050a78dfc7d650e687033 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Tue Aug 23 01:13:28 2016 From: gerrit-no-reply at lists.osmocom.org (lynxis lazus) Date: Tue, 23 Aug 2016 01:13:28 +0000 Subject: osmo-pcu[master]: tbf: add llc_queue_size() to check llc_queue is valid before... In-Reply-To: References: Message-ID: Patch Set 1: (2 comments) https://gerrit.osmocom.org/#/c/724/1//COMMIT_MSG Commit Message: Line 9: gcc6 is optimizing if (!this) {CODE} as this is assumed to never be > which "if (!this)" are you referring to? would be good will fix that in another commit. https://gerrit.osmocom.org/#/c/724/1/src/tbf.cpp File src/tbf.cpp: Line 194: return m_ms ? m_ms->llc_queue()->size() : 0; > nitpick... IMHO: I like it this way, because it's easier to read. You're right, it would be easier to change if it's using llc_queue(), because it's only a simple check on `m_ms` and it would save one in-direction through a function call. I would prefer it how it is now. -- To view, visit https://gerrit.osmocom.org/724 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I88cc3180f8f86785e3f07981895dabddf50b60a2 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: lynxis lazus Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 23 05:50:24 2016 From: gerrit-no-reply at lists.osmocom.org (pravin) Date: Tue, 23 Aug 2016 05:50:24 +0000 Subject: [PATCH] osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Hello Max, Neels Hofmeyr, Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/416 to look at the new patch set (#20). Add decoding of compressed bitmap in EPDAN Implemented tree based algorithm to decode compressed bitmap in EPDAN as described in section 9.1.10 of 3GPP 44.060. This algorithm intends to improve the performance over existing method. New Regression test is added under bitcomp directory. Test case is added to validate decompressed result of the bitmap Present in EPDAN. Test is done for multiple bitmaps of varying length. Invalid inputs are also part of the test vector. Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce --- M src/Makefile.am M src/decoding.cpp A src/egprs_rlc_compression.cpp A src/egprs_rlc_compression.h M tests/Makefile.am A tests/bitcomp/BitcompTest A tests/bitcomp/BitcompTest.cpp A tests/bitcomp/BitcompTest.err A tests/bitcomp/BitcompTest.ok M tests/testsuite.at 10 files changed, 761 insertions(+), 18 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/16/416/20 diff --git a/src/Makefile.am b/src/Makefile.am index 9bdec2f..9b047e7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -62,7 +62,8 @@ rlc.cpp \ osmobts_sock.cpp \ gprs_codel.c \ - gprs_coding_scheme.cpp + gprs_coding_scheme.cpp \ + egprs_rlc_compression.cpp bin_PROGRAMS = \ osmo-pcu @@ -94,7 +95,8 @@ pcu_utils.h \ cxx_linuxlist.h \ gprs_codel.h \ - gprs_coding_scheme.h + gprs_coding_scheme.h \ + egprs_rlc_compression.h osmo_pcu_SOURCES = pcu_main.cpp diff --git a/src/decoding.cpp b/src/decoding.cpp index 7c00ff7..2b00a07 100644 --- a/src/decoding.cpp +++ b/src/decoding.cpp @@ -20,6 +20,7 @@ #include #include #include +#include extern "C" { #include @@ -652,10 +653,10 @@ int num_blocks = 0; struct bitvec urbb; int i; + int rc; bool have_bitmap; int implicitly_acked_blocks; int ssn = desc->STARTING_SEQUENCE_NUMBER; - int rc; if (desc->FINAL_ACK_INDICATION) return handle_final_ack(bits, bsn_begin, bsn_end, window); @@ -695,24 +696,20 @@ if (crbb_len > 0) { int old_len = bits->cur_bit; - struct bitvec crbb; - crbb.data = (uint8_t *)desc->CRBB; - crbb.data_len = sizeof(desc->CRBB); - crbb.cur_bit = desc->CRBB_LENGTH; - - rc = osmo_t4_decode(&crbb, desc->CRBB_STARTING_COLOR_CODE, - bits); - + LOGP(DRLCMACDL, LOGL_DEBUG, "Compress bitmap exist," + "CRBB LEN =%d and Starting color code =%d", + desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE); + rc = decompress_crbb(desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE, + desc->CRBB, bits); if (rc < 0) { LOGP(DRLCMACUL, LOGL_NOTICE, - "Failed to decode CRBB: " - "length %d, data '%s'\n", - desc->CRBB_LENGTH, - osmo_hexdump(crbb.data, crbb.data_len)); + "Failed to decode CRBB: length %d, data '%s'\n", + desc->CRBB_LENGTH, osmo_hexdump( + desc->CRBB, (desc->CRBB_LENGTH + 7)/8)); /* We don't know the SSN offset for the URBB, - * return what we have so far and assume the - * bitmap has stopped here */ + * return what we have so far and assume the + * bitmap has stopped here */ goto aborted; } diff --git a/src/egprs_rlc_compression.cpp b/src/egprs_rlc_compression.cpp new file mode 100644 index 0000000..217f5d5 --- /dev/null +++ b/src/egprs_rlc_compression.cpp @@ -0,0 +1,334 @@ +/* egprs_rlc_compression.h +* Routines for EGPRS RLC bitmap compression handling +*/ +#include +#include +#include + +extern "C" { +#include +#include +#include +} + +extern void *tall_pcu_ctx; + +egprs_compress *egprs_compress::s_instance = 0; + +/* Function to create tree node */ +Node *egprs_compress::create_tree_node(void *parent) +{ + Node *new_node; + + new_node = talloc_zero(parent, Node); + new_node->left = NULL; + new_node->right = NULL; + new_node->run_length = -1; + return new_node; +} + +/* Function to build the codeword tree + * \param iter[in] Iterate the node on the tree + * \param len[in] Length of the code word + * \param i[in] Iterator + * \param idx[in] Iterate index of the code word table + */ +void egprs_compress::build_codeword(Node *root, const char *cdwd[]) +{ + Node *iter; + int len; + int i; + int idx; + + for (idx = 0; idx < MAX_CDWDTBL_LEN; idx++) { + len = strlen((const char *)cdwd[idx]); + iter = root; + for (i = 0; i < len; i++) { + if (cdwd[idx][i] == '0') { + if (!iter->left) + iter->left = create_tree_node(root); + iter = iter->left; + } else if (cdwd[idx][i] == '1') { + if (!iter->right) + iter->right = create_tree_node(root); + iter = iter->right; + } + } + if (iter) { + if (idx < 64) + (iter->run_length) = idx; + else + (iter->run_length) = (idx - 63) * 64; + } + } +} + +const char *one_run_len_code_list[MAX_CDWDTBL_LEN] = { + "00110101", + "000111", + "0111", + "1000", + "1011", + "1100", + "1110", + "1111", + "10011", + "10100", + "00111", + "01000", + "001000", + "000011", + "110100", + "110101", + "101010", + "101011", + "0100111", + "0001100", + "0001000", + "0010111", + "0000011", + "0000100", + "0101000", + "0101011", + "0010011", + "0100100", + "0011000", + "00000010", + "00000011", + "00011010", + "00011011", + "00010010", + "00010011", + "00010100", + "00010101", + "00010110", + "00010111", + "00101000", + "00101001", + "00101010", + "00101011", + "00101100", + "00101101", + "00000100", + "00000101", + "00001010", + "00001011", + "01010010", + "01010011", + "01010100", + "01010101", + "00100100", + "00100101", + "01011000", + "01011001", + "01011010", + "01011011", + "01001010", + "01001011", + "00110010", + "00110011", + "00110100", + "11011", + "10010", + "010111", + "0110111", + "00110110", + "00110111", + "01100100", + "01100101", + "01101000", + "01100111", + "011001100", + "011001101", + "011010010", + "011010011", + "011010100" +}; + +const char *zero_run_len_code_list[MAX_CDWDTBL_LEN] = { + "0000110111", + "10", + "11", + "010", + "011", + "0011", + "0010", + "00011", + "000101", + "000100", + "0000100", + "0000101", + "0000111", + "00000100", + "00000111", + "000011000", + "0000010111", + "0000011000", + "0000001000", + "00001100111", + "00001101000", + "00001101100", + "00000110111", + "00000101000", + "00000010111", + "00000011000", + "000011001010", + "000011001011", + "000011001100", + "000011001101", + "000001101000", + "000001101001", + "000001101010", + "000001101011", + "000011010010", + "000011010011", + "000011010100", + "000011010101", + "000011010110", + "000011010111", + "000001101100", + "000001101101", + "000011011010", + "000011011011", + "000001010100", + "000001010101", + "000001010110", + "000001010111", + "000001100100", + "000001100101", + "000001010010", + "000001010011", + "000000100100", + "000000110111", + "000000111000", + "000000100111", + "000000101000", + "000001011000", + "000001011001", + "000000101011", + "000000101100", + "000001011010", + "000001100110", + "000001100111", + "0000001111", + "000011001000", + "000011001001", + "000001011011", + "000000110011", + "000000110100", + "000000110101", + "0000001101100", + "0000001101101", + "0000001001010", + "0000001001011", + "0000001001100", + "0000001001101", + "0000001110010", + "0000001110011" +}; + +/* search_runlen function will return the runlength for the codeword + * \param root[in] Root of Ones or Zeros tree + * \param bmbuf[in] Recevied compressed bitmap buf + * \param bit_pos[in] The start bit pos to read codeword + * \param len_codewd[in] Length of code word + * \param rlen[out] Run length value + */ +static int search_runlen( + Node *root, + const uint8_t *bmbuf, + uint8_t bit_pos, + uint8_t *len_codewd, + uint16_t *rlen) +{ + Node *iter; + uint8_t dir; + + iter = root; + *len_codewd = 0; + + while (iter->run_length == -1) { + if ((!iter->left) && (!iter->right)) + return -1; + /* get the bit value at the bitpos and put it in right most of dir */ + dir = ((bmbuf[BITS_TO_BYTES(bit_pos)-1] + >>(7-(MOD8(bit_pos)))) & 0x01); + (bit_pos)++; + (*len_codewd)++; + if (((dir&0x01) == 0) && (iter->left != NULL)) + iter = iter->left; + else if (((dir&0x01) == 1) && (iter->right != NULL)) + iter = iter->right; + else + return -1; + } + (*rlen) = (iter->run_length); + return 1; +} + +/* Function to decompress crbb + * \param[in] Compressed bitmap length + * \clr_code_bit[in] Color code 1 for Ones runlength 0 for Zero runlength + * \orig_crbb_buf[in] Received block crbb bitmap + * \dest[out] Uncompressed bitvector + */ +int decompress_crbb( + int8_t compress_bmap_len, + uint8_t clr_code_bit, + const uint8_t *orig_crbb_buf, + bitvec *dest) +{ + + uint8_t bit_pos = 0; + uint8_t data = 0x0; + node *list = NULL; + uint8_t nbits = 0; /* number of bits of codeword */ + uint16_t run_length = 0; + uint16_t cbmaplen = 0; /* compressed bitmap part after decompression */ + unsigned wp = dest->cur_bit; + int rc = 0; + egprs_compress *compress = egprs_compress::instance(); + + while (compress_bmap_len > 0) { + if (clr_code_bit == 1) { + data = 0xff; + list = compress->ones_list; + } else { + data = 0x00; + list = compress->zeros_list; + } + rc = search_runlen(list, orig_crbb_buf, + bit_pos, &nbits, &run_length); + if (rc == -1) + return -1; + /* If run length > 64, need makeup and terminating code */ + if (run_length < 64) + clr_code_bit ? clr_code_bit = 0 : clr_code_bit = 1; + cbmaplen = cbmaplen + run_length; + /* put run length of Ones in uncompressed bitmap */ + while (run_length != 0) { + if (run_length > 8) { + bitvec_write_field(dest, wp, data, 8); + run_length = run_length - 8; + } else { + bitvec_write_field(dest, wp, data, run_length); + run_length = 0; + } + } + bit_pos = bit_pos + nbits; + compress_bmap_len = compress_bmap_len - nbits; + } + return 0; +} + +/* init function to build codeword */ +int egprs_compress::decode_tree_init() +{ + ones_list = create_tree_node(tall_pcu_ctx); + zeros_list = create_tree_node(tall_pcu_ctx); + build_codeword( + ones_list, one_run_len_code_list); + build_codeword( + zeros_list, zero_run_len_code_list); + return 0; +} diff --git a/src/egprs_rlc_compression.h b/src/egprs_rlc_compression.h new file mode 100644 index 0000000..a596a6f --- /dev/null +++ b/src/egprs_rlc_compression.h @@ -0,0 +1,63 @@ +/* egprs_rlc_compression.h + * Routines for EGPRS RLC bitmap compression handling + */ + +#pragma once + +#include +#include + +extern "C" { +#include +} + +#include +#include +#include + +#define MAX_CDWDTBL_LEN 79 /* total number of codewords */ +#define BITS_TO_BYTES(X) ((X ? (X/8):0)+1) +#define MOD8(X) (((X)+8) & (0x07)) + +typedef struct node { + struct node *left; + struct node *right; + int run_length; +} Node; + +extern const char *one_run_len_code_list[MAX_CDWDTBL_LEN]; +extern const char *zero_run_len_code_list[MAX_CDWDTBL_LEN]; + +int decompress_crbb(int8_t compress_bmap_len, uint8_t clr_code_bit, + const uint8_t *orig_buf, bitvec *dest); + +/* Creating singleton class + */ +class egprs_compress +{ + static egprs_compress *s_instance; + + egprs_compress() + { + if (decode_tree_init() < 0) { + fprintf(stderr, "Error initializing tree\n"); + exit(1); + } + } + Node *create_tree_node(void *); + void build_codeword(Node *root, const char *cdwd[]); + ~egprs_compress(); +public: + Node *ones_list; + Node *zeros_list; + + int decode_tree_init(void); + + static egprs_compress *instance() + { + if (!s_instance) + s_instance = new egprs_compress; + + return s_instance; + } +}; diff --git a/tests/Makefile.am b/tests/Makefile.am index 2a3415e..1d9e7b9 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,7 +1,7 @@ AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGB_CFLAGS) $(LIBOSMOGSM_CFLAGS) -I$(top_srcdir)/src/ AM_LDFLAGS = -lrt -check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest llc/LlcTest codel/codel_test edge/EdgeTest +check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest llc/LlcTest codel/codel_test edge/EdgeTest bitcomp/BitcompTest noinst_PROGRAMS = emu/pcu_emu rlcmac_RLCMACTest_SOURCES = rlcmac/RLCMACTest.cpp @@ -25,6 +25,14 @@ $(LIBOSMOGSM_LIBS) \ $(LIBOSMOCORE_LIBS) \ $(COMMON_LA) + +bitcomp_BitcompTest_SOURCES = bitcomp/BitcompTest.cpp ../src/egprs_rlc_compression.cpp +bitcomp_BitcompTest_LDADD = \ + $(LIBOSMOCORE_LIBS) \ + $(COMMON_LA) + +bitcomp_BitcompTest_LDFLAGS = \ + -Wl,-u,bssgp_prim_cb edge_EdgeTest_SOURCES = edge/EdgeTest.cpp edge_EdgeTest_LDADD = \ @@ -108,6 +116,7 @@ rlcmac/RLCMACTest.ok rlcmac/RLCMACTest.err \ alloc/AllocTest.ok alloc/AllocTest.err \ tbf/TbfTest.ok tbf/TbfTest.err \ + bitcomp/BitcompTest.ok bitcomp/BitcompTest.err \ types/TypesTest.ok types/TypesTest.err \ ms/MsTest.ok ms/MsTest.err \ llc/LlcTest.ok llc/LlcTest.err \ diff --git a/tests/bitcomp/BitcompTest b/tests/bitcomp/BitcompTest new file mode 100755 index 0000000..764bd83 --- /dev/null +++ b/tests/bitcomp/BitcompTest Binary files differ diff --git a/tests/bitcomp/BitcompTest.cpp b/tests/bitcomp/BitcompTest.cpp new file mode 100644 index 0000000..915e7ff --- /dev/null +++ b/tests/bitcomp/BitcompTest.cpp @@ -0,0 +1,236 @@ +#include +#include + +#include "rlc.h" +#include "gprs_debug.h" +#include "egprs_rlc_compression.h" + +extern "C" { +#include +#include +#include +#include +} + +#define NEW 1 +#define MASK(n) (0xFF << (8-n)) +#define MAX_CRBB_LEN 23 +#define MAX_URBB_LEN 40 + +void *tall_pcu_ctx; +int16_t spoof_mnc = 0, spoof_mcc = 0; + +struct test_data { + int8_t crbb_len; + uint8_t cc; + uint8_t crbb_data[MAX_CRBB_LEN]; /* compressed data */ + uint8_t ucmp_data[MAX_URBB_LEN]; /* uncompressed data */ + int ucmp_len; + int verify; +} test[] = { + { .crbb_len = 67, .cc = 1, + .crbb_data = { + 0x02, 0x0c, 0xa0, 0x30, 0xcb, 0x1a, 0x0c, 0xe3, 0x6c + }, + .ucmp_data = { + 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x01, 0xff, 0xff, + 0xff, 0xf8, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, + 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xdb + }, + .ucmp_len = 194, .verify = 1 + }, + { .crbb_len = 40, .cc = 1, + .crbb_data = { + 0x53, 0x06, 0xc5, 0x40, 0x6d + }, + .ucmp_data = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x03 + }, + .ucmp_len = 182, .verify = 1 + }, + { .crbb_len = 8, .cc = 1, + .crbb_data = {0x02}, + .ucmp_data = {0xff, 0xff, 0xff, 0xf8}, + .ucmp_len = 29, .verify = 1 + }, + { .crbb_len = 103, .cc = 1, + .crbb_data = { + 0x02, 0x0c, 0xe0, 0x41, 0xa0, 0x0c, 0x36, 0x0d, 0x03, + 0x71, 0xb0, 0x6e, 0x24 + }, + .ucmp_data = { + 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xf8, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, + 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff + }, + .ucmp_len = 288, .verify = 1 + }, + /* Test vector from libosmocore test */ + { .crbb_len = 35, .cc = 0, + .crbb_data = {0xde, 0x88, 0x75, 0x65, 0x80}, + .ucmp_data = {0x37, 0x47, 0x81, 0xf0}, + .ucmp_len = 28, .verify = 1 + }, + { .crbb_len = 18, .cc = 1, + .crbb_data = {0xdd, 0x41, 0x00}, + .ucmp_data = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00 + }, + .ucmp_len = 90, .verify = 1 + }, + /*Invalid inputs*/ + { .crbb_len = 18, .cc = 1, + .crbb_data = {0x1E, 0x70, 0xc0}, + .ucmp_data = {0x0}, + .ucmp_len = 0, .verify = 0 + }, + { .crbb_len = 14, .cc = 1, + .crbb_data = {0x00, 0x1E, 0x7c}, + .ucmp_data = {0x0}, + .ucmp_len = 0, .verify = 0 + }, + { .crbb_len = 24, .cc = 0, + .crbb_data = {0x00, 0x00, 0x00}, + .ucmp_data = {0x0}, + .ucmp_len = 0, .verify = 0 + } + }; + +static const struct log_info_cat default_categories[] = { + {"DCSN1", "\033[1;31m", "Concrete Syntax Notation One (CSN1)", LOGL_INFO, 0}, + {"DL1IF", "\033[1;32m", "GPRS PCU L1 interface (L1IF)", LOGL_DEBUG, 1}, + {"DRLCMAC", "\033[0;33m", "GPRS RLC/MAC layer (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACDATA", "\033[0;33m", "GPRS RLC/MAC layer Data (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACDL", "\033[1;33m", "GPRS RLC/MAC layer Downlink (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACUL", "\033[1;36m", "GPRS RLC/MAC layer Uplink (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACSCHED", "\033[0;36m", "GPRS RLC/MAC layer Scheduling (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACMEAS", "\033[1;31m", "GPRS RLC/MAC layer Measurements (RLCMAC)", LOGL_INFO, 1}, + {"DNS", "\033[1;34m", "GPRS Network Service Protocol (NS)", LOGL_INFO, 1}, + {"DBSSGP", "\033[1;34m", "GPRS BSS Gateway Protocol (BSSGP)", LOGL_INFO, 1}, + {"DPCU", "\033[1;35m", "GPRS Packet Control Unit (PCU)", LOGL_NOTICE, 1}, +}; + +static int filter_fn(const struct log_context *ctx, + struct log_target *tar) +{ + return 1; +} + +/* To verify the result with expected result */ +int check_result(bitvec bits, uint8_t *exp_data, int exp_len) +{ + if (bits.cur_bit != exp_len) + return 0; + size_t n = (exp_len / 8); + int rem = (exp_len % 8); + + if (memcmp(exp_data, bits.data, n) == 0) { + if (rem == 0) + return 1; + if ((bits.data[n] & MASK(rem)) == ((*(exp_data + n)) & MASK(rem))) + return 1; + else + return 0; + } else + return 0; +} + +/* To test decoding of compressed bitmap by Tree based method + * and to verify the result with expected result + * for invalid input verfication is suppressed + */ +static void test_EPDAN_decode_tree(void) +{ + bitvec dest; + int init_flag = 1; + int itr; + int rc; + uint8_t bits_data[RLC_EGPRS_MAX_WS/8]; + + printf("=== start %s ===\n", __func__); + + for (itr = 0 ; itr < (sizeof(test) / sizeof(test_data)) ; itr++) { + dest.data = bits_data; + dest.data_len = sizeof(bits_data); + dest.cur_bit = 0; + memset(dest.data, 0, sizeof(bits_data)); + LOGP(DRLCMACDL, LOGL_DEBUG, "\nTest:%d\nTree based decoding:" + "\nuncompressed data = %s\nlen = %d\n", itr + 1, + osmo_hexdump(test[itr].crbb_data, + (test[itr].crbb_len + 7)/8), test[itr].crbb_len + ); + rc = decompress_crbb(test[itr].crbb_len, test[itr].cc, + test[itr].crbb_data, &dest + ); + if (rc < 0) { + LOGP(DRLCMACUL, LOGL_NOTICE, + "\nFailed to decode CRBB: length %d, data %s", + test[itr].crbb_len, osmo_hexdump( + test[itr].crbb_data, (test[itr].crbb_len + 7)/8)); + } + if (init_flag) + init_flag = 0; + if (test[itr].verify) { + if (check_result(dest, test[itr].ucmp_data, + test[itr].ucmp_len) == 0) { + LOGP(DRLCMACDL, LOGL_DEBUG, "\nTree based decoding" + ":Error\nexpected data = %s\nexpected" + " len = %d\ndecoded data = %s\n" + "decoded len = %d\n", + osmo_hexdump(test[itr].ucmp_data, + (test[itr].ucmp_len + 7)/8), + test[itr].ucmp_len, osmo_hexdump(dest.data, + (dest.cur_bit + 7)/8), dest.cur_bit + ); + OSMO_ASSERT(0); + } + } + LOGP(DRLCMACDL, LOGL_DEBUG, "\nexpected data = %s\nexpected len = %d" + "\ndecoded data = %s\ndecoded len = %d\n", + osmo_hexdump(test[itr].ucmp_data, + (test[itr].ucmp_len + 7)/8), + test[itr].ucmp_len, osmo_hexdump(dest.data, + (dest.cur_bit + 7)/8), dest.cur_bit + ); + } + + printf("=== end %s ===\n", __func__); +} + +const struct log_info debug_log_info = { + filter_fn, + (struct log_info_cat *)default_categories, + ARRAY_SIZE(default_categories), +}; + +int main(int argc, char **argv) +{ + osmo_init_logging(&debug_log_info); + log_set_use_color(osmo_stderr_target, 0); + log_set_print_filename(osmo_stderr_target, 0); + + tall_pcu_ctx = talloc_named_const(NULL, 1, "moiji-mobile TbfTest context"); + if (!tall_pcu_ctx) + abort(); + + test_EPDAN_decode_tree(); + + if (getenv("TALLOC_REPORT_FULL")) + talloc_report_full(tall_pcu_ctx, stderr); + talloc_free(tall_pcu_ctx); + return EXIT_SUCCESS; +} +/* + * stubs that should not be reached + */ +extern "C" { +void l1if_pdch_req() { abort(); } +void l1if_connect_pdch() { abort(); } +void l1if_close_pdch() { abort(); } +void l1if_open_pdch() { abort(); } +} + diff --git a/tests/bitcomp/BitcompTest.err b/tests/bitcomp/BitcompTest.err new file mode 100644 index 0000000..a9078d0 --- /dev/null +++ b/tests/bitcomp/BitcompTest.err @@ -0,0 +1,92 @@ + +Test:1 +Tree based decoding: +uncompressed data = 02 0c a0 30 cb 1a 0c e3 6c +len = 67 + +expected data = ff ff ff f8 00 00 01 ff ff ff f8 00 00 00 ff ff ff fe 00 00 3f ff ff ff db +expected len = 194 +decoded data = ff ff ff f8 00 00 01 ff ff ff f8 00 00 00 ff ff ff fe 00 00 3f ff ff ff db +decoded len = 194 + +Test:2 +Tree based decoding: +uncompressed data = 53 06 c5 40 6d +len = 40 + +expected data = ff ff ff ff ff ff c0 00 00 00 00 3f ff ff ff ff ff f8 00 00 00 00 03 +expected len = 182 +decoded data = ff ff ff ff ff ff c0 00 00 00 00 3f ff ff ff ff ff f8 00 00 00 00 03 +decoded len = 182 + +Test:3 +Tree based decoding: +uncompressed data = 02 +len = 8 + +expected data = ff ff ff f8 +expected len = 29 +decoded data = ff ff ff f8 +decoded len = 29 + +Test:4 +Tree based decoding: +uncompressed data = 02 0c e0 41 a0 0c 36 0d 03 71 b0 6e 24 +len = 103 + +expected data = ff ff ff f8 00 00 ff ff ff f8 00 00 7f ff ff fe 00 00 0f ff ff ff e0 00 00 7f ff ff ff 80 00 01 ff ff ff ff +expected len = 288 +decoded data = ff ff ff f8 00 00 ff ff ff f8 00 00 7f ff ff fe 00 00 0f ff ff ff e0 00 00 7f ff ff ff 80 00 01 ff ff ff ff +decoded len = 288 + +Test:5 +Tree based decoding: +uncompressed data = de 88 75 65 80 +len = 35 + +expected data = 37 47 81 f0 +expected len = 28 +decoded data = 37 47 81 f0 +decoded len = 28 + +Test:6 +Tree based decoding: +uncompressed data = dd 41 00 +len = 18 + +expected data = ff ff ff ff ff ff ff ff ff ff 00 00 +expected len = 90 +decoded data = ff ff ff ff ff ff ff ff ff ff 00 00 +decoded len = 90 + +Test:7 +Tree based decoding: +uncompressed data = 1e 70 c0 +len = 18 + +expected data = +expected len = 0 +decoded data = +decoded len = 19 + +Test:8 +Tree based decoding: +uncompressed data = 00 1e +len = 14 + +Failed to decode CRBB: length 14, data 00 1e +expected data = +expected len = 0 +decoded data = +decoded len = 0 + +Test:9 +Tree based decoding: +uncompressed data = 00 00 00 +len = 24 + +Failed to decode CRBB: length 24, data 00 00 00 +expected data = +expected len = 0 +decoded data = +decoded len = 0 diff --git a/tests/bitcomp/BitcompTest.ok b/tests/bitcomp/BitcompTest.ok new file mode 100644 index 0000000..f7720fc --- /dev/null +++ b/tests/bitcomp/BitcompTest.ok @@ -0,0 +1,2 @@ +=== start test_EPDAN_decode_tree === +=== end test_EPDAN_decode_tree === diff --git a/tests/testsuite.at b/tests/testsuite.at index 1049b31..3ab39cc 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -23,6 +23,14 @@ AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/tbf/TbfTest], [0], [expout], [experr]) AT_CLEANUP + +AT_SETUP([bitcomp]) +AT_KEYWORDS([bitcomp]) +cat $abs_srcdir/bitcomp/BitcompTest.ok > expout +cat $abs_srcdir/bitcomp/BitcompTest.err > experr +AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/bitcomp/BitcompTest], [0], [expout], [experr]) +AT_CLEANUP + AT_SETUP([edge]) AT_KEYWORDS([edge]) cat $abs_srcdir/edge/EdgeTest.ok > expout -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 20 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: pravin From gerrit-no-reply at lists.osmocom.org Tue Aug 23 09:35:01 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Tue, 23 Aug 2016 09:35:01 +0000 Subject: [PATCH] openbsc[master]: Adding compression control and final fixups In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/642 to look at the new patch set (#23). Adding compression control and final fixups - Add module to handle compression entities - Add module to control header compression - Introduce VTY commands for heade compression configuration - Add changes in sndcp and llc to integrate header compression Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 --- M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/gprs_llc.h M openbsc/include/openbsc/gprs_sndcp.h A openbsc/include/openbsc/gprs_sndcp_comp.h A openbsc/include/openbsc/gprs_sndcp_pcomp.h M openbsc/include/openbsc/sgsn.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/gprs_llc.c M openbsc/src/gprs/gprs_sndcp.c A openbsc/src/gprs/gprs_sndcp_comp.c A openbsc/src/gprs/gprs_sndcp_pcomp.c M openbsc/src/gprs/sgsn_libgtp.c M openbsc/src/gprs/sgsn_vty.c M openbsc/tests/sgsn/Makefile.am 14 files changed, 1,413 insertions(+), 34 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/42/642/23 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index f402fea..88a7e2c 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,7 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ - slhc.h + slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h index c3b82b1..4cd6c2e 100644 --- a/openbsc/include/openbsc/gprs_llc.h +++ b/openbsc/include/openbsc/gprs_llc.h @@ -174,6 +174,15 @@ * able to create the compression entity. */ struct llist_head *xid; + /* Compression entities */ + struct { + /* In this two list_heads we will store the + * data and protocol compression entities, + * together with their compression states */ + struct llist_head *proto; + struct llist_head *data; + } comp; + /* Internal management */ uint32_t age_timestamp; }; diff --git a/openbsc/include/openbsc/gprs_sndcp.h b/openbsc/include/openbsc/gprs_sndcp.h index fef871a..cd6ee4e 100644 --- a/openbsc/include/openbsc/gprs_sndcp.h +++ b/openbsc/include/openbsc/gprs_sndcp.h @@ -21,6 +21,16 @@ struct llist_head frag_list; struct osmo_timer_list timer; + + /* Holds state to know which compression mode is used + * when the packet is re-assembled */ + uint8_t pcomp; + uint8_t dcomp; + + /* Holds the pointers to the compression entity list + * that is used when the re-assembled packet is decompressed */ + struct llist_head *proto; + struct llist_head *data; }; /* See 6.7.1.2 Reassembly */ @@ -50,4 +60,20 @@ extern struct llist_head gprs_sndcp_entities; +/* Set of SNDCP-XID negotiation (See also: TS 144 065, + * Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_req(struct gprs_llc_lle *lle, uint8_t nsapi); + +/* Process SNDCP-XID indication (See also: TS 144 065, + * Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_ind(struct gprs_llc_xid_field *xid_field_indication, + struct gprs_llc_xid_field *xid_field_response, + struct gprs_llc_lle *lle); + +/* Process SNDCP-XID indication + * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_conf(struct gprs_llc_xid_field *xid_field_confirmation, + struct gprs_llc_xid_field *xid_field_request, + struct gprs_llc_lle *lle); + #endif /* INT_SNDCP_H */ diff --git a/openbsc/include/openbsc/gprs_sndcp_comp.h b/openbsc/include/openbsc/gprs_sndcp_comp.h new file mode 100644 index 0000000..69441fb --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_comp.h @@ -0,0 +1,84 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +/* Header / Data compression entity */ +struct gprs_sndcp_comp { + struct llist_head list; + + /* Serves as an ID in case we want to delete this entity later */ + unsigned int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + + /* Specifies to which NSAPIs the compression entity is assigned */ + uint8_t nsapi_len; /* Number of applicable NSAPIs (default 0) */ + uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */ + + /* Assigned pcomp values */ + uint8_t comp_len; /* Number of contained PCOMP / DCOMP values */ + uint8_t comp[MAX_COMP]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */ + + /* Algorithm parameters */ + int algo; /* Algorithm type (see gprs_sndcp_xid.h) */ + int compclass; /* See gprs_sndcp_xid.h/c */ + void *state; /* Algorithm status and parameters */ +}; + +#define MAX_COMP 16 /* Maximum number of possible pcomp/dcomp values */ +#define MAX_NSAPI 11 /* Maximum number usable NSAPIs */ + +/* Allocate a compression enitiy list */ +struct llist_head *gprs_sndcp_comp_alloc(const void *ctx); + +/* Free a compression entitiy list */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities); + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, unsigned int entity); + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_entities_add(const void *ctx, struct + llist_head *comp_entities, + const struct + gprs_sndcp_comp_field + *comp_field); + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head + *comp_entities, uint8_t comp); + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head + *comp_entities, uint8_t nsapi); + +/* Find a comp_index for a given pcomp/dcomp value */ +int gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp *comp_entity, + int comp); + +/* Find a pcomp/dcomp value for a given comp_index */ +int gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp *comp_entity, + int comp_index); + diff --git a/openbsc/include/openbsc/gprs_sndcp_pcomp.h b/openbsc/include/openbsc/gprs_sndcp_pcomp.h new file mode 100644 index 0000000..2528a86 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_pcomp.h @@ -0,0 +1,44 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field); + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity); + +/* Expand packet header */ +int gprs_sndcp_pcomp_expand(uint8_t *data_o, uint8_t *data_i, unsigned int len, + uint8_t pcomp, + const struct llist_head *comp_entities); + +/* Compress packet header */ +int gprs_sndcp_pcomp_compress(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t *pcomp, + const struct llist_head *comp_entities, + int nsapi); diff --git a/openbsc/include/openbsc/sgsn.h b/openbsc/include/openbsc/sgsn.h index 59126fe..acd3e4b 100644 --- a/openbsc/include/openbsc/sgsn.h +++ b/openbsc/include/openbsc/sgsn.h @@ -89,6 +89,12 @@ int dynamic_lookup; struct oap_config oap; + + /* RFC1144 TCP/IP Header compression */ + struct { + int enabled; + int s01; + } pcomp_rfc1144; }; struct sgsn_instance { diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 245636b..2910c02 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -27,7 +27,7 @@ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ - slhc.c + slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c index 79795d6..34b7afe 100644 --- a/openbsc/src/gprs/gprs_llc.c +++ b/openbsc/src/gprs/gprs_llc.c @@ -39,6 +39,7 @@ #include #include #include +#include #include static struct gprs_llc_llme *llme_alloc(uint32_t tlli); @@ -88,7 +89,9 @@ llist_add(&l3_xid_field->list, &xid_fields); } - llme->xid = gprs_llc_copy_xid(llme->xid, &xid_fields); + /* Store generated XID for later reference */ + talloc_free(llme->xid); + llme->xid = gprs_llc_copy_xid(llme, &xid_fields); return gprs_llc_compile_xid(bytes, bytes_len, &xid_fields); } @@ -120,7 +123,9 @@ llist_add(&xid_iovui.list, &xid_fields); llist_add(&xid_reset.list, &xid_fields); - llme->xid = gprs_llc_copy_xid(llme->xid, &xid_fields); + /* Store generated XID for later reference */ + talloc_free(llme->xid); + llme->xid = gprs_llc_copy_xid(llme, &xid_fields); return gprs_llc_compile_xid(bytes, bytes_len, &xid_fields); } @@ -135,6 +140,16 @@ struct llist_head *xid_fields; struct gprs_llc_xid_field *xid_field; + struct gprs_llc_xid_field *xid_field_request; + struct gprs_llc_xid_field *xid_field_request_l3 = NULL; + + /* Pick layer3 XID from the XID request we have sent last */ + if (lle->llme->xid) { + llist_for_each_entry(xid_field_request, lle->llme->xid, list) { + if (xid_field_request->type == GPRS_LLC_XID_T_L3_PAR) + xid_field_request_l3 = xid_field_request; + } + } /* Parse and analyze XID-Response */ xid_fields = gprs_llc_parse_xid(NULL, bytes, bytes_len); @@ -145,11 +160,10 @@ llist_for_each_entry(xid_field, xid_fields, list) { /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ - if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { - LOGP(DLLC, LOGL_NOTICE, - "Ignoring SNDCP-XID-Field: XID: type=%i, data_len=%i, data=%s\n", - xid_field->type, xid_field->data_len, - xid_field->data); + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR && + xid_field_request_l3) { + sndcp_sn_xid_conf(xid_field, + xid_field_request_l3, lle); } /* Process LLC-XID fields: */ @@ -163,9 +177,10 @@ * inquiry. There is a remainig risk of * malfunction! */ LOGP(DLLC, LOGL_NOTICE, - "Ignoring XID-Field: XID: type=%i, data_len=%i, data=%s\n", + "Ignoring XID-Field: XID: type=%d, data_len=%d, data=%s\n", xid_field->type, xid_field->data_len, - xid_field->data); + osmo_hexdump_nospc(xid_field->data, + xid_field->data_len)); } } talloc_free(xid_fields); @@ -197,10 +212,6 @@ struct gprs_llc_xid_field *xid_field; struct gprs_llc_xid_field *xid_field_response; - /* Flush eventually pending XID fields */ - talloc_free(lle->llme->xid); - lle->llme->xid = NULL; - /* Parse and analyze XID-Request */ xid_fields = gprs_llc_parse_xid(lle->llme, bytes_request, bytes_request_len); @@ -220,7 +231,7 @@ * when a phone submits values which defer from * the default! */ LOGP(DLLC, LOGL_NOTICE, - "Echoing XID-Field: XID: type=%i, data_len=%i, data=%s\n", + "Echoing XID-Field: XID: type=%d, data_len=%d, data=%s\n", xid_field->type, xid_field->data_len, osmo_hexdump_nospc(xid_field->data, xid_field->data_len)); @@ -229,6 +240,23 @@ (lle->llme, xid_field); llist_add(&xid_field_response->list, xid_fields_response); + } + } + + /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ + llist_for_each_entry(xid_field, xid_fields, list) { + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { + + xid_field_response = + talloc_zero(lle->llme, + struct gprs_llc_xid_field); + rc = sndcp_sn_xid_ind(xid_field, + xid_field_response, lle); + if (rc == 0) + llist_add(&xid_field_response->list, + xid_fields_response); + else + talloc_free(xid_field_response); } } @@ -518,11 +546,16 @@ llist_add(&llme->list, &gprs_llc_llmes); + llme->comp.proto = gprs_sndcp_comp_alloc(llme); + llme->comp.data = gprs_sndcp_comp_alloc(llme); + return llme; } static void llme_free(struct gprs_llc_llme *llme) { + gprs_sndcp_comp_free(llme->comp.proto); + gprs_sndcp_comp_free(llme->comp.data); talloc_free(llme->xid); llist_del(&llme->list); talloc_free(llme); diff --git a/openbsc/src/gprs/gprs_sndcp.c b/openbsc/src/gprs/gprs_sndcp.c index 4f71121..0d076e3 100644 --- a/openbsc/src/gprs/gprs_sndcp.c +++ b/openbsc/src/gprs/gprs_sndcp.c @@ -35,6 +35,131 @@ #include #include #include +#include +#include +#include +#include + +#define DEBUG_IP_PACKETS 1 /* 0=Disabled, 1=Enabled */ + +#if DEBUG_IP_PACKETS == 1 +/* Calculate TCP/IP checksum */ +static uint16_t calc_ip_csum(uint8_t *data, int len) +{ + int i; + uint32_t accumulator = 0; + uint16_t *pointer = (uint16_t *) data; + + for (i = len; i > 1; i -= 2) { + accumulator += *pointer; + pointer++; + } + + if (len % 2) + accumulator += *pointer; + + accumulator = (accumulator & 0xffff) + ((accumulator >> 16) & 0xffff); + accumulator += (accumulator >> 16) & 0xffff; + return (~accumulator); +} + +/* Calculate TCP/IP checksum */ +static uint16_t calc_tcpip_csum(const void *ctx, uint8_t *packet, int len) +{ + uint8_t *buf; + uint16_t csum; + + buf = talloc_zero_size(ctx, len); + memset(buf, 0, len); + memcpy(buf, packet + 12, 8); + buf[9] = packet[9]; + buf[11] = (len - 20) & 0xFF; + buf[10] = (len - 20) >> 8 & 0xFF; + memcpy(buf + 12, packet + 20, len - 20); + csum = calc_ip_csum(buf, len - 20 + 12); + talloc_free(buf); + return csum; +} + +/* Show some ip packet details */ +static void debug_ip_packet(uint8_t *data, int len, int dir, char *info) +{ + uint8_t tcp_flags; + char flags_debugmsg[256]; + int len_short; + static unsigned int packet_count = 0; + static unsigned int tcp_csum_err_count = 0; + static unsigned int ip_csum_err_count = 0; + + packet_count++; + + if (len > 80) + len_short = 80; + else + len_short = len; + + if (dir) + DEBUGP(DSNDCP, "%s: PHONE => NETWORK: %s\n", info, + osmo_hexdump_nospc(data, len_short)); + else + DEBUGP(DSNDCP, "%s: PHONE <= NETWORK: %s\n", info, + osmo_hexdump_nospc(data, len_short)); + + DEBUGP(DSNDCP, "%s: Length.: %d\n", info, len); + DEBUGP(DSNDCP, "%s: NO.: %d\n", info, packet_count); + + if (len < 20) { + DEBUGP(DSNDCP, "%s: Error: Short IP packet!\n", info); + return; + } + + if (calc_ip_csum(data, 20) != 0) { + DEBUGP(DSNDCP, "%s: Bad IP-Header checksum!\n", info); + ip_csum_err_count++; + } else + DEBUGP(DSNDCP, "%s: IP-Header checksum ok.\n", info); + + if (data[9] == 0x06) { + if (len < 40) { + DEBUGP(DSNDCP, "%s: Error: Short TCP packet!\n", info); + return; + } + + DEBUGP(DSNDCP, "%s: Protocol type: TCP\n", info); + tcp_flags = data[33]; + + if (calc_tcpip_csum(NULL, data, len) != 0) { + DEBUGP(DSNDCP, "%s: Bad TCP checksum!\n", info); + tcp_csum_err_count++; + } else + DEBUGP(DSNDCP, "%s: TCP checksum ok.\n", info); + + memset(flags_debugmsg, 0, sizeof(flags_debugmsg)); + if (tcp_flags & 1) + strcat(flags_debugmsg, "FIN "); + if (tcp_flags & 2) + strcat(flags_debugmsg, "SYN "); + if (tcp_flags & 4) + strcat(flags_debugmsg, "RST "); + if (tcp_flags & 8) + strcat(flags_debugmsg, "PSH "); + if (tcp_flags & 16) + strcat(flags_debugmsg, "ACK "); + if (tcp_flags & 32) + strcat(flags_debugmsg, "URG "); + DEBUGP(DSNDCP, "%s: FLAGS: %s\n", info, flags_debugmsg); + } else if (data[9] == 0x11) { + DEBUGP(DSNDCP, "%s: Protocol type: UDP\n", info); + } else { + DEBUGP(DSNDCP, "%s: Protocol type: (%02x)\n", info, data[9]); + } + + DEBUGP(DSNDCP, "%s: IP-Header checksum errors: %d\n", info, + ip_csum_err_count); + DEBUGP(DSNDCP, "%s: TCP-Checksum errors: %d\n", info, + tcp_csum_err_count); +} +#endif /* Chapter 7.2: SN-PDU Formats */ struct sndcp_common_hdr { @@ -143,6 +268,9 @@ struct msgb *msg; unsigned int seg_nr; uint8_t *npdu; + int npdu_len; + int rc; + uint8_t *expnd; LOGP(DSNDCP, LOGL_DEBUG, "TLLI=0x%08x NSAPI=%u: Defragment output PDU %u " "num_seg=%u tot_len=%u\n", sne->lle->llme->tlli, sne->nsapi, @@ -173,16 +301,46 @@ talloc_free(dqe); } + npdu_len = sne->defrag.tot_len; + /* FIXME: cancel timer */ /* actually send the N-PDU to the SGSN core code, which then * hands it off to the correct GTP tunnel + GGSN via gtp_data_req() */ - return sgsn_rx_sndcp_ud_ind(&sne->ra_id, sne->lle->llme->tlli, - sne->nsapi, msg, sne->defrag.tot_len, npdu); + + /* Decompress packet */ +#if DEBUG_IP_PACKETS == 1 + DEBUGP(DSNDCP, " \n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, "===================================================\n"); +#endif + expnd = talloc_zero_size(msg, msg->len + 64); + rc = gprs_sndcp_pcomp_expand(expnd, npdu, npdu_len, + sne->defrag.pcomp, sne->defrag.proto); + if (rc < 0) { + LOGP(DSNDCP, LOGL_ERROR, + "TCP/IP Header decompression failed!\n"); + talloc_free(expnd); + return -EIO; + } else + npdu_len = rc; +#if DEBUG_IP_PACKETS == 1 + debug_ip_packet(expnd, npdu_len, 1, "defrag_segments()"); + DEBUGP(DSNDCP, "===================================================\n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, " \n"); +#endif + + /* Hand off packet to gtp */ + rc = sgsn_rx_sndcp_ud_ind(&sne->ra_id, sne->lle->llme->tlli, + sne->nsapi, msg, npdu_len, expnd); + + talloc_free(expnd); + return rc; } -static int defrag_input(struct gprs_sndcp_entity *sne, struct msgb *msg, uint8_t *hdr, - unsigned int len) +static int defrag_input(struct gprs_sndcp_entity *sne, struct msgb *msg, + uint8_t *hdr, unsigned int len) { struct sndcp_common_hdr *sch; struct sndcp_udata_hdr *suh; @@ -343,7 +501,8 @@ }; /* returns '1' if there are more fragments to send, '0' if none */ -static int sndcp_send_ud_frag(struct sndcp_frag_state *fs) +static int sndcp_send_ud_frag(struct sndcp_frag_state *fs, + uint8_t pcomp, uint8_t dcomp) { struct gprs_sndcp_entity *sne = fs->sne; struct gprs_llc_lle *lle = sne->lle; @@ -380,8 +539,8 @@ if (sch->first) { scomph = (struct sndcp_comp_hdr *) msgb_put(fmsg, sizeof(*scomph)); - scomph->pcomp = 0; - scomph->dcomp = 0; + scomph->pcomp = pcomp; + scomph->dcomp = dcomp; } /* append the user-data header */ @@ -446,8 +605,37 @@ struct sndcp_comp_hdr *scomph; struct sndcp_udata_hdr *suh; struct sndcp_frag_state fs; + uint8_t pcomp = 0; + uint8_t dcomp = 0; + int rc; + uint8_t *compr; /* Identifiers from UP: (TLLI, SAPI) + (BVCI, NSEI) */ + + /* Compress packet */ +#if DEBUG_IP_PACKETS == 1 + DEBUGP(DSNDCP, " \n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, "===================================================\n"); + debug_ip_packet(msg->data, msg->len, 0, "sndcp_initdata_req()"); +#endif + compr = talloc_zero_size(msg, msg->len); + rc = gprs_sndcp_pcomp_compress(compr, msg->data, msg->len, &pcomp, + lle->llme->comp.proto, nsapi); + if (rc < 0) { + LOGP(DSNDCP, LOGL_ERROR, "TCP/IP Header compression failed!\n"); + talloc_free(compr); + return -EIO; + } else { + msg->len = rc; + memcpy(msg->data, compr, rc); + } + talloc_free(compr); +#if DEBUG_IP_PACKETS == 1 + DEBUGP(DSNDCP, "===================================================\n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, " \n"); +#endif sne = gprs_sndcp_entity_by_lle(lle, nsapi); if (!sne) { @@ -469,7 +657,7 @@ /* call function to generate and send fragments until all * of the N-PDU has been sent */ while (1) { - int rc = sndcp_send_ud_frag(&fs); + int rc = sndcp_send_ud_frag(&fs,pcomp,dcomp); if (rc == 0) return 0; if (rc < 0) @@ -489,8 +677,8 @@ sne->tx_npdu_nr = (sne->tx_npdu_nr + 1) % 0xfff; scomph = (struct sndcp_comp_hdr *) msgb_push(msg, sizeof(*scomph)); - scomph->pcomp = 0; - scomph->dcomp = 0; + scomph->pcomp = pcomp; + scomph->dcomp = dcomp; /* prepend common SNDCP header */ sch = (struct sndcp_common_hdr *) msgb_push(msg, sizeof(*sch)); @@ -512,6 +700,8 @@ uint8_t *npdu; uint16_t npdu_num __attribute__((unused)); int npdu_len; + int rc; + uint8_t *expnd; sch = (struct sndcp_common_hdr *) hdr; if (sch->first) { @@ -540,26 +730,58 @@ /* FIXME: move this RA_ID up to the LLME or even higher */ bssgp_parse_cell_id(&sne->ra_id, msgb_bcid(msg)); + if(scomph) { + sne->defrag.pcomp = scomph->pcomp; + sne->defrag.dcomp = scomph->dcomp; + sne->defrag.proto = lle->llme->comp.proto; + sne->defrag.data = lle->llme->comp.data; + } + /* any non-first segment is by definition something to defragment * as is any segment that tells us there are more segments */ if (!sch->first || sch->more) return defrag_input(sne, msg, hdr, len); - if (scomph && (scomph->pcomp || scomph->dcomp)) { - LOGP(DSNDCP, LOGL_ERROR, "We don't support compression yet\n"); - return -EIO; - } - npdu_num = (suh->npdu_high << 8) | suh->npdu_low; npdu = (uint8_t *)suh + sizeof(*suh); - npdu_len = (msg->data + msg->len) - npdu; + npdu_len = (msg->data + msg->len) - npdu - 3; /* -3 'removes' the FCS */ + if (npdu_len <= 0) { LOGP(DSNDCP, LOGL_ERROR, "Short SNDCP N-PDU: %d\n", npdu_len); return -EIO; } /* actually send the N-PDU to the SGSN core code, which then * hands it off to the correct GTP tunnel + GGSN via gtp_data_req() */ - return sgsn_rx_sndcp_ud_ind(&sne->ra_id, lle->llme->tlli, sne->nsapi, msg, npdu_len, npdu); + + /* Decompress packet */ +#if DEBUG_IP_PACKETS == 1 + DEBUGP(DSNDCP, " \n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, "===================================================\n"); +#endif + expnd = talloc_zero_size(msg, npdu_len + 64); + rc = gprs_sndcp_pcomp_expand(expnd, npdu, npdu_len, + sne->defrag.pcomp, sne->defrag.proto); + if (rc < 0) { + LOGP(DSNDCP, LOGL_ERROR, + "TCP/IP Header decompression failed!\n"); + talloc_free(expnd); + return -EIO; + } else + npdu_len = rc; +#if DEBUG_IP_PACKETS == 1 + debug_ip_packet(expnd, npdu_len, 1, "sndcp_llunitdata_ind()"); + DEBUGP(DSNDCP, "===================================================\n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, " \n"); +#endif + + /* Hand off packet to gtp */ + rc = sgsn_rx_sndcp_ud_ind(&sne->ra_id, lle->llme->tlli, + sne->nsapi, msg, npdu_len, expnd); + + talloc_free(expnd); + return rc; } #if 0 @@ -619,3 +841,328 @@ case LL_STATUS_IND: } #endif + +/* Generate SNDCP-XID message */ +static int gprs_llc_generate_sndcp_xid(uint8_t *bytes, int bytes_len, + uint8_t nsapi) +{ + LLIST_HEAD(comp_fields); + struct gprs_sndcp_pcomp_rfc1144_params rfc1144_params; + struct gprs_sndcp_comp_field rfc1144_comp_field; + + memset(&rfc1144_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + + /* Setup which NSAPIs shall make use of rfc1144 */ + rfc1144_params.nsapi[0] = nsapi; + rfc1144_params.nsapi_len = 1; + + /* Setup rfc1144 operating parameters */ + rfc1144_params.s01 = sgsn->cfg.pcomp_rfc1144.s01; + + /* Setup rfc1144 compression field */ + rfc1144_comp_field.p = 1; + rfc1144_comp_field.entity = 0; + rfc1144_comp_field.algo = RFC_1144; + rfc1144_comp_field.comp[RFC1144_PCOMP1] = 1; + rfc1144_comp_field.comp[RFC1144_PCOMP2] = 2; + rfc1144_comp_field.comp_len = RFC1144_PCOMP_NUM; + rfc1144_comp_field.rfc1144_params = &rfc1144_params; + + /* Add compression field(s) to list */ + if (sgsn->cfg.pcomp_rfc1144.enabled) + llist_add(&rfc1144_comp_field.list, &comp_fields); + + /* Comile bytestream */ + return gprs_sndcp_compile_xid(bytes, bytes_len, &comp_fields); +} + +/* Set of SNDCP-XID bnegotiation (See also: TS 144 065, + * Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_req(struct gprs_llc_lle *lle, uint8_t nsapi) +{ + /* Note: The specification requires the SNDCP-User to set of an + * SNDCP xid request. See also 3GPP TS 44.065, 6.8 XID parameter + * negotiation, Figure 11: SNDCP XID negotiation procedure. In + * our case the SNDCP-User is sgsn_libgtp.c, which calls + * sndcp_sn_xid_req directly. */ + + uint8_t l3params_bytes[1024]; + int sndcp_xid_bytes_len; + struct gprs_llc_xid_field xid_field_request; + + /* Generate compression parameter bytestream */ + sndcp_xid_bytes_len = gprs_llc_generate_sndcp_xid(l3params_bytes, + sizeof + (l3params_bytes), + nsapi); + + /* Send XID with the SNDCP-XID bytetsream included */ + if (sndcp_xid_bytes_len > 0) { + xid_field_request.type = GPRS_LLC_XID_T_L3_PAR; + xid_field_request.data = l3params_bytes; + xid_field_request.data_len = sndcp_xid_bytes_len; + return gprs_ll_xid_req(lle, &xid_field_request); + } + + /* When bytestream can not be generated, proceed without SNDCP-XID */ + else { + return gprs_ll_xid_req(lle, NULL); + } +} + +/* Hanle header compression entites */ +static int handle_pcomp_entities(struct gprs_sndcp_comp_field *comp_field, + struct gprs_llc_lle *lle) +{ + /* Note: This functions also transforms the comp_field into its + * echo form (strips comp values, resets propose bit etc...) + * the processed comp_fields can then be sent back as XID- + * Response without further modification. */ + + /* Delete propose bit */ + comp_field->p = 0; + + /* Process proposed parameters */ + switch (comp_field->algo) { + case RFC_1144: + if (sgsn->cfg.pcomp_rfc1144.enabled && + comp_field->rfc1144_params->nsapi_len > 0) { + LOGP(DSNDCP, LOGL_DEBUG, + "Accepting RFC1144 header conpression...\n"); + gprs_sndcp_comp_entities_add(lle->llme, + lle->llme->comp.proto, + comp_field); + } else { + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting RFC1144 header conpression...\n"); + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + comp_field->rfc1144_params->nsapi_len = 0; + } + break; + case RFC_2507: + /* RFC 2507 is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting RFC2507 header conpression...\n"); + comp_field->rfc2507_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + break; + case ROHC: + /* ROHC is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting ROHC header conpression...\n"); + comp_field->rohc_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + break; + } + + return 0; +} + +/* Hanle data compression entites */ +static int handle_dcomp_entities(struct gprs_sndcp_comp_field *comp_field, + struct gprs_llc_lle *lle) +{ + /* Note: This functions also transforms the comp_field into its + * echo form (strips comp values, resets propose bit etc...) + * the processed comp_fields can then be sent back as XID- + * Response without further modification. */ + + /* Delete propose bit */ + comp_field->p = 0; + + /* Process proposed parameters */ + switch (comp_field->algo) { + case V42BIS: + /* V42BIS is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting V42BIS data conpression...\n"); + comp_field->rfc2507_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + break; + case V44: + /* V44 is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, "Rejecting V44 data conpression...\n"); + comp_field->rohc_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + break; + } + + return 0; + +} + +/* Process SNDCP-XID indication + * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_ind(struct gprs_llc_xid_field *xid_field_indication, + struct gprs_llc_xid_field *xid_field_response, + struct gprs_llc_lle *lle) +{ + /* Note: This function computes the SNDCP-XID response that is sent + * back to the phone when a phone originated XID is received. The + * Input XID fields are directly processed and the result is directly + * handed back. */ + + int rc; + int compclass; + + struct llist_head *comp_fields; + struct gprs_sndcp_comp_field *comp_field; + + OSMO_ASSERT(xid_field_indication); + OSMO_ASSERT(xid_field_response); + OSMO_ASSERT(lle); + + /* Parse SNDCP-CID XID-Field */ + comp_fields = + gprs_sndcp_parse_xid(lle->llme, xid_field_indication->data, + xid_field_indication->data_len, NULL); + if (!comp_fields) + return -EINVAL; + + /* Don't bother with empty indications */ + if (llist_empty(comp_fields)) { + xid_field_response->data = NULL; + xid_field_response->data_len = 0; + DEBUGP(DSNDCP, + "SNDCP-XID indication did not contain any parameters!\n"); + return 0; + } + + /* Handle compression entites */ + DEBUGP(DSNDCP, "Unmodified SNDCP-XID received from the phone:\n"); + gprs_sndcp_dump_comp_fields(comp_fields, LOGL_DEBUG); + + llist_for_each_entry(comp_field, comp_fields, list) { + compclass = gprs_sndcp_get_compression_class(comp_field); + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + rc = handle_pcomp_entities(comp_field, lle); + else if (compclass == SNDCP_XID_DATA_COMPRESSION) + rc = handle_dcomp_entities(comp_field, lle); + else { + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + rc = 0; + } + + if (rc < 0) { + talloc_free(comp_fields); + return -EINVAL; + } + } + + DEBUGP(DSNDCP, + "Modified version of received SNDCP-XID to be sent back from the ggsn:\n"); + gprs_sndcp_dump_comp_fields(comp_fields, LOGL_DEBUG); + + /* Reserve some memory to store the modified SNDCP-XID bytes */ + xid_field_response->data = + talloc_zero_size(lle->llme, xid_field_indication->data_len); + + /* Set Type flag for response */ + xid_field_response->type = GPRS_LLC_XID_T_L3_PAR; + + /* Compile modified SNDCP-XID bytes */ + rc = gprs_sndcp_compile_xid(xid_field_response->data, + xid_field_indication->data_len, + comp_fields); + + if (rc > 0) + xid_field_response->data_len = rc; + else { + talloc_free(xid_field_response->data); + xid_field_response->data = NULL; + xid_field_response->data_len = 0; + return -EINVAL; + } + + talloc_free(comp_fields); + + return 0; +} + +/* Process SNDCP-XID indication + * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_conf(struct gprs_llc_xid_field *xid_field_confirmation, + struct gprs_llc_xid_field *xid_field_request, + struct gprs_llc_lle *lle) +{ + /* Note: This function handles an incomming SNDCP-XID confirmiation. + * Since the confirmation fields may lack important parameters we + * will reconstruct these missing fields using the original request + * we have sent. After that we will create (or delete) the + * compression entites */ + + struct llist_head *comp_fields_req; + struct llist_head *comp_fields_conf; + struct gprs_sndcp_comp_field *comp_field; + int rc; + int compclass; + + /* We need both, the confirmation that is sent back by the phone, + * and the original request we have sent. If one of this is missing + * we can not process the confirmation, the caller must check if + * request and confirmation fields are available. */ + OSMO_ASSERT(xid_field_confirmation); + OSMO_ASSERT(xid_field_request); + + /* Parse SNDCP-CID XID-Field */ + comp_fields_req = gprs_sndcp_parse_xid(lle->llme, + xid_field_request->data, + xid_field_request->data_len, + NULL); + if (!comp_fields_req) + return -EINVAL; + + DEBUGP(DSNDCP, "Unmodified SNDCP-XID sent from the ggsn:\n"); + gprs_sndcp_dump_comp_fields(comp_fields_req, LOGL_DEBUG); + + /* Parse SNDCP-CID XID-Field */ + comp_fields_conf = gprs_sndcp_parse_xid(lle->llme, + xid_field_confirmation->data, + xid_field_confirmation-> + data_len, comp_fields_req); + if (!comp_fields_conf) + return -EINVAL; + + DEBUGP(DSNDCP, + "Modified version of received SNDCP-XID received from the phone:\n"); + gprs_sndcp_dump_comp_fields(comp_fields_conf, LOGL_DEBUG); + + /* Handle compression entites */ + llist_for_each_entry(comp_field, comp_fields_conf, list) { + compclass = gprs_sndcp_get_compression_class(comp_field); + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + rc = handle_pcomp_entities(comp_field, lle); + else if (compclass == SNDCP_XID_DATA_COMPRESSION) + rc = handle_dcomp_entities(comp_field, lle); + else { + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + rc = 0; + } + + if (rc < 0) { + talloc_free(comp_fields_req); + talloc_free(comp_fields_conf); + return -EINVAL; + } + } + + talloc_free(comp_fields_req); + talloc_free(comp_fields_conf); + + return 0; +} diff --git a/openbsc/src/gprs/gprs_sndcp_comp.c b/openbsc/src/gprs/gprs_sndcp_comp.c new file mode 100644 index 0000000..19cd7b1 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_comp.c @@ -0,0 +1,319 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +/* Create a new compression entity from a XID-Field */ +static struct gprs_sndcp_comp *gprs_sndcp_comp_create(const void *ctx, + const struct + gprs_sndcp_comp_field + *comp_field) +{ + OSMO_ASSERT(comp_field); + + struct gprs_sndcp_comp *comp_entity; + comp_entity = talloc_zero(ctx, struct gprs_sndcp_comp); + + /* Copy relevant information from the SNDCP-XID field */ + comp_entity->entity = comp_field->entity; + comp_entity->comp_len = comp_field->comp_len; + memcpy(comp_entity->comp, comp_field->comp, sizeof(comp_entity->comp)); + + if (comp_field->rfc1144_params) { + comp_entity->nsapi_len = comp_field->rfc1144_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc1144_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->rfc2507_params) { + comp_entity->nsapi_len = comp_field->rfc2507_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc2507_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->rohc_params) { + comp_entity->nsapi_len = comp_field->rohc_params->nsapi_len; + memcpy(comp_entity->nsapi, comp_field->rohc_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->v42bis_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->v44_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + sizeof(comp_entity->nsapi)); + } else { + /* The caller is expected to check carefully if the all + * data fields required for compression entity creation + * are present. Otherwise we blow an assertion here */ + OSMO_ASSERT(false); + } + comp_entity->algo = comp_field->algo; + + /* Check if an NSAPI is selected, if not, it does not make sense + * to create the compression entity, since the caller should + * have checked the presence of the NSAPI, we blow an assertion + * in case of missing NSAPIs */ + OSMO_ASSERT(comp_entity->nsapi_len > 0) + + /* Determine of which class our compression entity will be + * (Protocol or Data compresson ?) */ + comp_entity->compclass = + gprs_sndcp_get_compression_class(comp_field); + OSMO_ASSERT(comp_entity->compclass != -1); + + /* Create an algorithm specific compression context */ + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + if (gprs_sndcp_pcomp_init(ctx, comp_entity, comp_field) != 0) { + talloc_free(comp_entity); + comp_entity = NULL; + } + } else { + LOGP(DSNDCP, LOGL_ERROR, + "We don't support data compression yet!\n"); + talloc_free(comp_entity); + return NULL; + } + + /* Display info message */ + if (comp_entity == NULL) { + LOGP(DSNDCP, LOGL_ERROR, + "Header compression entity (%d) creation failed!\n", + comp_entity->entity); + return NULL; + } + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "New header compression entity (%d) created.\n", + comp_entity->entity); + } else { + LOGP(DSNDCP, LOGL_INFO, + "New data compression entity (%d) created.\n", + comp_entity->entity); + } + + return comp_entity; +} + +/* Allocate a compression enitiy list */ +struct llist_head *gprs_sndcp_comp_alloc(const void *ctx) +{ + struct llist_head *lh; + + lh = talloc_zero(ctx, struct llist_head); + INIT_LLIST_HEAD(lh); + + return lh; +} + +/* Free a compression entitiy list */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities) +{ + struct gprs_sndcp_comp *comp_entity; + + /* We expect the caller to take care of allocating a + * compression entity list properly. Attempting to + * free a non existing list clearly points out + * a malfunction. */ + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + /* Free compression entity */ + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %d ...\n", + comp_entity->entity); + gprs_sndcp_pcomp_term(comp_entity); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %d ...\n", + comp_entity->entity); + } + } + + talloc_free(comp_entities); +} + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, + unsigned int entity) +{ + struct gprs_sndcp_comp *comp_entity; + struct gprs_sndcp_comp *comp_entity_to_delete = NULL; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) + comp_entity_to_delete = comp_entity; + } + + if (!comp_entity_to_delete) + return; + + if (comp_entity_to_delete->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %d ...\n", + comp_entity_to_delete->entity); + gprs_sndcp_pcomp_term(comp_entity_to_delete); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %d ...\n", + comp_entity_to_delete->entity); + } + + /* Delete compression entity */ + llist_del(&comp_entity_to_delete->list); + talloc_free(comp_entity_to_delete); +} + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_entities_add(const void *ctx, + struct llist_head + *comp_entities, + const struct + gprs_sndcp_comp_field + *comp_field) +{ + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(comp_entities); + OSMO_ASSERT(comp_field); + + /* Just to be sure, if the entity is already in + * the list it will be deleted now */ + gprs_sndcp_comp_delete(comp_entities, comp_field->entity); + + /* Create and add a new entity to the list */ + comp_entity = gprs_sndcp_comp_create(ctx, comp_field); + + if (!comp_entity) + return NULL; + + llist_add(&comp_entity->list, comp_entities); + return comp_entity; +} + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head + *comp_entities, uint8_t comp) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return comp_entity; + } + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given pcomp/dcomp value %d.\n", + comp); + return NULL; +} + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head + *comp_entities, uint8_t nsapi) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->nsapi_len; i++) { + if (comp_entity->nsapi[i] == nsapi) + return comp_entity; + } + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given nsapi value %d\n", + nsapi); + return NULL; +} + +/* Find a comp_index for a given pcomp/dcomp value */ +int gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp *comp_entity, int comp) +{ + int i; + + OSMO_ASSERT(comp_entity); + + /* A pcomp/dcomp field set to zero always disables + * all sort of compression and is assigned fix. So we + * just return zero in this case */ + if (comp == 0) + return 0; + + /* Look in the pcomp/dcomp list for the index */ + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return i + 1; + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching comp_index for given pcomp/dcomp value %d\n", + comp); + return 0; +} + +/* Find a pcomp/dcomp value for a given comp_index */ +int gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp *comp_entity, + int comp_index) +{ + OSMO_ASSERT(comp_entity); + + /* A comp_index of zero translates to zero right away. */ + if (comp_index == 0) + return 0; + + if (comp_index > comp_entity->comp_len) { + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching pcomp/dcomp value for given comp_index value %d.\n", + comp_index); + return 0; + } + + /* Look in the pcomp/dcomp list for the comp_index */ + return comp_entity->comp[comp_index - 1]; +} diff --git a/openbsc/src/gprs/gprs_sndcp_pcomp.c b/openbsc/src/gprs/gprs_sndcp_pcomp.c new file mode 100644 index 0000000..0fb72b6 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_pcomp.c @@ -0,0 +1,264 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a new header compression + * entity is created by gprs_sndcp.c */ + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + comp_entity->state = + slhc_init(ctx, comp_field->rfc1144_params->s01 + 1, + comp_field->rfc1144_params->s01 + 1); + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression initalized.\n"); + return 0; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a header compression + * entity is deleted by gprs_sndcp.c */ + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + if (comp_entity->state) { + slhc_free((struct slcompress *)comp_entity->state); + comp_entity->state = NULL; + } + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression terminated.\n"); + return; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Compress a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_compress(uint8_t *pcomp_index, + uint8_t *data_o, uint8_t *data_i, + unsigned int len, + struct slcompress *comp) +{ + uint8_t *comp_ptr; /* Required by slhc_compress() */ + int compr_len; + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Run compressor */ + compr_len = slhc_compress(comp, data_i, len, data_o, &comp_ptr, 0); + + /* Generate pcomp_index */ + if (data_o[0] & SL_TYPE_COMPRESSED_TCP) { + *pcomp_index = 2; + data_o[0] &= ~SL_TYPE_COMPRESSED_TCP; + } else if ((data_o[0] & SL_TYPE_UNCOMPRESSED_TCP) == + SL_TYPE_UNCOMPRESSED_TCP) { + *pcomp_index = 1; + data_o[0] &= 0x4F; + } else + *pcomp_index = 0; + + return compr_len; +} + +/* Expand a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_expand(uint8_t *data_o, uint8_t *data_i, + unsigned int len, + uint8_t pcomp_index, + struct slcompress *comp) +{ + int data_decompressed_len; + int type = -1; + + /* Note: this function should never be called with pcomp_index=0, + * since this condition is already filtered + * out by gprs_sndcp_pcomp_expand() */ + + /* Determine the data type by the PCOMP index */ + switch (pcomp_index) { + case 1: + type = SL_TYPE_UNCOMPRESSED_TCP; + break; + case 2: + type = SL_TYPE_COMPRESSED_TCP; + break; + } + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Restore the original version nibble on + * marked uncompressed packets */ + if (type == SL_TYPE_UNCOMPRESSED_TCP) { + /* Just in case the phone tags uncompressed tcp-datas + * (normally this is handled by pcomp so there is + * no need for tagging the datas) */ + data_o[0] &= 0x4F; + data_decompressed_len = slhc_remember(comp, data_o, len); + return data_decompressed_len; + } + + /* Uncompress compressed packets */ + else if (type == SL_TYPE_COMPRESSED_TCP) { + data_decompressed_len = slhc_uncompress(comp, data_o, len); + return data_decompressed_len; + } + + /* Regular or unknown packets will not be touched */ + return len; +} + +/* Expand packet header */ +int gprs_sndcp_pcomp_expand(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t pcomp, + const struct llist_head *comp_entities) +{ + int rc; + uint8_t pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data_o); + OSMO_ASSERT(data_i); + OSMO_ASSERT(comp_entities); + + /* Skip on pcomp=0 */ + if (pcomp == 0) { + memcpy(data_o, data_i, len); + return len; + } + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_comp(comp_entities, pcomp); + + /* Skip compression if no suitable compression entity can be found */ + if (comp_entity == NULL) { + memcpy(data_o, data_i, len); + return len; + } + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION); + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144); + + /* Find pcomp_index */ + pcomp_index = gprs_sndcp_comp_get_idx(comp_entity, pcomp); + + /* Run decompression algo */ + rc = gprs_sndcp_pcomp_rfc1144_expand(data_o, data_i, len, pcomp_index, + comp_entity->state); + slhc_i_status(comp_entity->state); + slhc_o_status(comp_entity->state); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header expansion done, old length=%d, new length=%d\n", len, rc); + + return rc; +} + +/* Compress packet header */ +int gprs_sndcp_pcomp_compress(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t *pcomp, + const struct llist_head *comp_entities, int nsapi) +{ + int rc; + uint8_t pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data_o); + OSMO_ASSERT(data_i); + OSMO_ASSERT(pcomp); + OSMO_ASSERT(comp_entities); + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_nsapi(comp_entities, nsapi); + + /* Skip compression if no suitable compression entity can be found */ + if (!comp_entity) { + *pcomp = 0; + memcpy(data_o, data_i, len); + return len; + } + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION); + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144); + + /* Run compression algo */ + rc = gprs_sndcp_pcomp_rfc1144_compress(&pcomp_index, data_o, data_i, + len, comp_entity->state); + slhc_i_status(comp_entity->state); + slhc_o_status(comp_entity->state); + + /* Find pcomp value */ + *pcomp = gprs_sndcp_comp_get_comp(comp_entity, pcomp_index); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header compression done, old length=%d, new length=%d\n", + len, rc); + return rc; +} diff --git a/openbsc/src/gprs/sgsn_libgtp.c b/openbsc/src/gprs/sgsn_libgtp.c index be7637a..f548dd6 100644 --- a/openbsc/src/gprs/sgsn_libgtp.c +++ b/openbsc/src/gprs/sgsn_libgtp.c @@ -307,6 +307,9 @@ static int send_act_pdp_cont_acc(struct sgsn_pdp_ctx *pctx) { struct sgsn_signal_data sig_data; + int rc_pdp; + int rc_xid; + struct gprs_llc_lle *lle; /* Inform others about it */ memset(&sig_data, 0, sizeof(sig_data)); @@ -314,7 +317,17 @@ osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_ACT, &sig_data); /* Send PDP CTX ACT to MS */ - return gsm48_tx_gsm_act_pdp_acc(pctx); + rc_pdp = gsm48_tx_gsm_act_pdp_acc(pctx); + if(rc_pdp < 0) + return rc_pdp; + + /* Send SNDCP XID to MS */ + lle = &pctx->mm->gb.llme->lle[pctx->sapi]; + rc_xid = sndcp_sn_xid_req(lle,pctx->nsapi); + if(rc_xid < 0) + return rc_xid; + + return rc_pdp; } /* The GGSN has confirmed the creation of a PDP Context */ diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c index e6dc68d..c7cc268 100644 --- a/openbsc/src/gprs/sgsn_vty.c +++ b/openbsc/src/gprs/sgsn_vty.c @@ -269,6 +269,13 @@ vty_out(vty, " timer t3395 %d%s", g_cfg->timers.T3395, VTY_NEWLINE); vty_out(vty, " timer t3397 %d%s", g_cfg->timers.T3397, VTY_NEWLINE); + if (g_cfg->pcomp_rfc1144.enabled) { + vty_out(vty, " compression rfc1144 slots %d%s", + g_cfg->pcomp_rfc1144.s01+1, VTY_NEWLINE); + } else { + vty_out(vty, " no compression rfc1144%s", VTY_NEWLINE); + } + return CMD_SUCCESS; } @@ -1074,6 +1081,28 @@ return CMD_SUCCESS; } +#define COMPRESSION_STR "Configure compression\n" +DEFUN(cfg_no_comp_rfc1144, cfg_no_comp_rfc1144_cmd, + "no compression rfc1144", + NO_STR COMPRESSION_STR + "disable rfc1144 TCP/IP header compression\n") +{ + g_cfg->pcomp_rfc1144.enabled = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_comp_rfc1144, cfg_comp_rfc1144_cmd, + "compression rfc1144 slots <1-256>", + COMPRESSION_STR + "RFC1144 Header compresion scheme\n" + "Number of compression state slots\n" + "Number of compression state slots\n") +{ + g_cfg->pcomp_rfc1144.enabled = 1; + g_cfg->pcomp_rfc1144.s01 = atoi(argv[0]) - 1; + return CMD_SUCCESS; +} + int sgsn_vty_init(void) { install_element_ve(&show_sgsn_cmd); @@ -1128,6 +1157,9 @@ install_element(SGSN_NODE, &cfg_sgsn_T3395_cmd); install_element(SGSN_NODE, &cfg_sgsn_T3397_cmd); + install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd); + install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd); + return 0; } diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 3e66978..1804280 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -33,6 +33,8 @@ $(top_builddir)/src/gprs/gprs_llc_xid.o \ $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ $(top_builddir)/src/gprs/slhc.o \ + $(top_builddir)/src/gprs/gprs_sndcp_comp.o \ + $(top_builddir)/src/gprs/gprs_sndcp_pcomp.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ -- To view, visit https://gerrit.osmocom.org/642 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 Gerrit-PatchSet: 23 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Tue Aug 23 09:50:56 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 23 Aug 2016 09:50:56 +0000 Subject: osmo-pcu[master]: tbf: add llc_queue_size() to check llc_queue is valid before... In-Reply-To: References: Message-ID: Patch Set 1: (1 comment) https://gerrit.osmocom.org/#/c/724/1/src/tbf.cpp File src/tbf.cpp: Line 194: return m_ms ? m_ms->llc_queue()->size() : 0; > IMHO: I like it this way, because it's easier to read. ok, keep it then :) -- To view, visit https://gerrit.osmocom.org/724 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I88cc3180f8f86785e3f07981895dabddf50b60a2 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: lynxis lazus Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 23 10:06:13 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 23 Aug 2016 10:06:13 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 21: (4 comments) https://gerrit.osmocom.org/#/c/655/21//COMMIT_MSG Commit Message: Line 10: Retx. This patch will also Upgrade the test suite with test cases hm, was about to +2, but I don't see the test cases this commit log is talking about? Drop the "Upgrade" sentence? https://gerrit.osmocom.org/#/c/655/21/src/pcu_vty.c File src/pcu_vty.c: Line 133: vty_out(vty, " egprs dl arq-type %s%s", "arq2", hehe interesting -- at first I thought you had forgot to check for spb, but since spb is the default you only need to print something if arq2 is enabled. It doesn't really make sense to do "foo %s", "bar" i.e. rather have "... arq-type arq2%s", VTY_NEWLINE but whatever. Line 487: #define DL_STR "DL specific configuration\n" I'd prefer "DL" written out in the doc, noob users will have an easier time understanding what it means then. leaving it up to you. What does it mean, "downlink"? Line 494: "enable ARQ2 support") nice. -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 21 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 23 10:16:29 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 23 Aug 2016 10:16:29 +0000 Subject: [PATCH] osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/655 to look at the new patch set (#22). Modify EGPRS DL TBF flow to support SPB Modify the EGPRS DL TBF flow to support Split block during Retx. This patch will also Upgrade the test suite with test cases to validate the EGPRS Downlink SPB for Retransmission Scenarios like MCS6->MCS3, MCS4->MCS1, MCS5->MCS2, MCS9->MCS3 MCS7->MCS2, MCS8->MCS3 have been simulated and Integration tested in NuRAN 1.0 hardware thoroughly. Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 --- M src/gprs_coding_scheme.h M src/pcu_main.cpp M src/pcu_vty.c M src/rlc.cpp M src/rlc.h M src/tbf.h M src/tbf_dl.cpp M tests/edge/EdgeTest.cpp M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 11 files changed, 958 insertions(+), 80 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/55/655/22 diff --git a/src/gprs_coding_scheme.h b/src/gprs_coding_scheme.h index 60a8e79..3b15372 100644 --- a/src/gprs_coding_scheme.h +++ b/src/gprs_coding_scheme.h @@ -113,7 +113,8 @@ static const char *modeName(Mode mode); static Scheme get_retx_mcs(const GprsCodingScheme mcs, - const GprsCodingScheme retx_mcs); + const GprsCodingScheme retx_mcs, + const unsigned arq_type); static enum Scheme egprs_mcs_retx_tbl[MAX_NUM_ARQ] [MAX_NUM_MCS][MAX_NUM_MCS]; @@ -232,8 +233,9 @@ } inline GprsCodingScheme::Scheme GprsCodingScheme::get_retx_mcs( const GprsCodingScheme mcs, - const GprsCodingScheme demanded_mcs) + const GprsCodingScheme demanded_mcs, + const unsigned arq_type) { - return egprs_mcs_retx_tbl[EGPRS_ARQ2][mcs.to_num() - 1] + return egprs_mcs_retx_tbl[arq_type][mcs.to_num() - 1] [demanded_mcs.to_num() - 1]; } diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2d86cda..e34d534 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -210,6 +210,12 @@ bts->dl_tbf_idle_msec = 2000; bts->llc_idle_ack_csec = 10; + /* + * By default resegmentation is supported in DL + * can also be configured through VTY + */ + bts->dl_arq_type = EGPRS_ARQ1; + msgb_set_talloc_ctx(tall_pcu_ctx); osmo_init_logging(&gprs_log_info); diff --git a/src/pcu_vty.c b/src/pcu_vty.c index 58fea99..ea01135 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -129,6 +129,10 @@ vty_out(vty, " window-size %d %d%s", bts->ws_base, bts->ws_pdch, VTY_NEWLINE); + if (bts->dl_arq_type) + vty_out(vty, " egprs dl arq-type arq2%s", + VTY_NEWLINE); + if (bts->force_llc_lifetime == 0xffff) vty_out(vty, " queue lifetime infinite%s", VTY_NEWLINE); else if (bts->force_llc_lifetime) @@ -476,6 +480,25 @@ bts->max_mcs_dl = 0; bts->max_mcs_ul = 0; + + return CMD_SUCCESS; +} + +#define DL_STR "downlink specific configuration\n" + +DEFUN(cfg_pcu_dl_arq_type, + cfg_pcu_dl_arq_cmd, + "egprs dl arq-type (spb|arq2)", + EGPRS_STR DL_STR "ARQ options\n" + "enable SPB(ARQ1) support\n" + "enable ARQ2 support") +{ + struct gprs_rlcmac_bts *bts = bts_main_data(); + + if (!strcmp(argv[0], "arq2")) + bts->dl_arq_type = 1; + else + bts->dl_arq_type = 0; return CMD_SUCCESS; } @@ -954,6 +977,7 @@ install_element(PCU_NODE, &cfg_pcu_no_cs_downgrade_thrsh_cmd); install_element(PCU_NODE, &cfg_pcu_cs_lqual_ranges_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_cmd); + install_element(PCU_NODE, &cfg_pcu_dl_arq_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_max_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_max_cmd); diff --git a/src/rlc.cpp b/src/rlc.cpp index 6770043..e69d1fc 100644 --- a/src/rlc.cpp +++ b/src/rlc.cpp @@ -285,7 +285,8 @@ } static void gprs_rlc_data_header_init(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding, unsigned int header_bits) + GprsCodingScheme cs, bool with_padding, unsigned int header_bits, + const unsigned int spb) { unsigned int i; unsigned int padding_bits = with_padding ? cs.optionalPaddingBits() : 0; @@ -300,7 +301,7 @@ for (i = 0; i < rlc->num_data_blocks; i++) { gprs_rlc_data_block_info_init(&rlc->block_info[i], cs, - with_padding); + with_padding, spb); rlc->data_offs_bits[i] = header_bits + padding_bits + @@ -310,21 +311,25 @@ } void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsDL()); + cs.numDataHeaderBitsDL(), spb); } void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding) { + /* + * last parameter is sent as 0 since common function used + * for both DL and UL + */ return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsUL()); + cs.numDataHeaderBitsUL(), 0); } void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { unsigned int data_len = cs.maxDataBlockBytes(); if (with_padding) @@ -336,7 +341,7 @@ rdbi->e = 1; rdbi->cv = 15; rdbi->pi = 0; - rdbi->spb = 0; + rdbi->spb = spb; } unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, @@ -411,8 +416,18 @@ enum egprs_puncturing_values gprs_get_punct_scheme( enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current) + const GprsCodingScheme &cs_current, + const enum egprs_rlcmac_dl_spb spb) { + + /* + * 10.4.8b of TS 44.060 + * If it is second segment of the block + * dont change the puncturing scheme + */ + if (spb == EGPRS_RLCMAC_DL_SEC_SEG) + return punct; + /* TS 44.060 9.3.2.1.1 */ if ((GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS9) && (GprsCodingScheme::Scheme(cs_current) == GprsCodingScheme::MCS6)) { diff --git a/src/rlc.h b/src/rlc.h index b1a1fba..b693418 100644 --- a/src/rlc.h +++ b/src/rlc.h @@ -213,18 +213,19 @@ }; void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding); void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, enum egprs_puncturing_values punct, enum egprs_puncturing_values punct2, int with_padding); void gprs_rlc_mcs_cps_decode(unsigned int cps, GprsCodingScheme cs, int *punct, int *punct2, int *with_padding); enum egprs_puncturing_values gprs_get_punct_scheme(enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current_trans); + const GprsCodingScheme &cs_current_trans, + const enum egprs_rlcmac_dl_spb spb); void gprs_update_punct_scheme(enum egprs_puncturing_values *punct, const GprsCodingScheme &cs); /* diff --git a/src/tbf.h b/src/tbf.h index 1bd7878..2a1bfe8 100644 --- a/src/tbf.h +++ b/src/tbf.h @@ -421,6 +421,11 @@ int analyse_errors(char *show_rbb, uint8_t ssn, ana_result *res); void schedule_next_frame(); + enum egprs_rlc_dl_reseg_bsn_state egprs_dl_get_data + (int bsn, uint8_t **block_data); + unsigned int get_egprs_dl_spb_status(int bsn); + enum egprs_rlcmac_dl_spb get_egprs_dl_spb(int bsn); + struct osmo_timer_list m_llc_timer; }; diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp index 07a747a..a24cc21 100644 --- a/src/tbf_dl.cpp +++ b/src/tbf_dl.cpp @@ -375,21 +375,28 @@ return -1; if (is_egprs_enabled()) { + /* Table 8.1.1.2 and Table 8.1.1.1 of 44.060 */ m_rlc.block(bsn)->cs_current_trans = - GprsCodingScheme::get_retx_mcs( - m_rlc.block(bsn)->cs_last, ms()->current_cs_dl()); + GprsCodingScheme::get_retx_mcs( + m_rlc.block(bsn)->cs_init, + ms()->current_cs_dl(), + bts->bts_data()->dl_arq_type); LOGP(DRLCMACDL, LOGL_DEBUG, - "- current_cs_dl(%d) demanded_mcs(%d) cs_trans(%d)\n", - m_rlc.block(bsn)->cs_last.to_num(), - ms()->current_cs_dl().to_num(), - m_rlc.block(bsn)->cs_current_trans.to_num()); + "- initial_cs_dl(%d) last_mcs(%d)" + " demanded_mcs(%d) cs_trans(%d)" + " arq_type(%d) bsn(%d)\n", + m_rlc.block(bsn)->cs_init.to_num(), + m_rlc.block(bsn)->cs_last.to_num(), + ms()->current_cs_dl().to_num(), + m_rlc.block(bsn)->cs_current_trans.to_num(), + bts->bts_data()->dl_arq_type, bsn); /* TODO: Need to remove this check when MCS-8 -> MCS-6 * transistion is handled. * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 */ - if (m_rlc.block(bsn)->cs_last == GprsCodingScheme::MCS8) + if (m_rlc.block(bsn)->cs_init == GprsCodingScheme::MCS8) m_rlc.block(bsn)->cs_current_trans = GprsCodingScheme::MCS8; } else @@ -523,6 +530,11 @@ data = rlc_data->prepare(block_data_len); rlc_data->cs_last = cs; rlc_data->cs_current_trans = cs; + + /* Initialise the variable related to DL SPB */ + rlc_data->spb_status.block_status_dl = EGPRS_RESEG_DL_DEFAULT; + rlc_data->cs_init = cs; + rlc_data->len = block_data_len; rdbi = &(rlc_data->block_info); @@ -616,7 +628,8 @@ unsigned num_bsns; enum egprs_puncturing_values punct[ARRAY_SIZE(rlc.block_info)]; bool need_padding = false; - + enum egprs_rlcmac_dl_spb spb = EGPRS_RLCMAC_DL_NO_RETX; + unsigned int spb_status = get_egprs_dl_spb_status(index); /* * TODO: This is an experimental work-around to put 2 BSN into * MSC-7 to MCS-9 encoded messages. It just sends the same BSN @@ -626,6 +639,7 @@ * the current limit. */ cs = m_rlc.block(index)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(index)->cs_init; bsns[0] = index; num_bsns = 1; @@ -634,7 +648,17 @@ num_bsns += 1; } - if (num_bsns == 1) { + /* + * if the intial mcs is 8 and retransmission mcs is either 6 or 3 + * we have to include the padding of 6 octets in first segment + */ + if ((GprsCodingScheme::Scheme(cs_init) == GprsCodingScheme::MCS8) && + (GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS6 || + GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS3)) { + if (spb_status == EGPRS_RESEG_DL_DEFAULT || + spb_status == EGPRS_RESEG_SECOND_SEG_SENT) + need_padding = true; + } else if (num_bsns == 1) { /* TODO: remove the conditional when MCS-6 padding isn't * failing to be decoded by MEs anymore */ /* TODO: support of MCS-8 -> MCS-6 transition should be @@ -646,7 +670,14 @@ cs.decToSingleBlock(&need_padding); } - gprs_rlc_data_info_init_dl(&rlc, cs, need_padding); + spb = get_egprs_dl_spb(index); + + LOGP(DRLCMACDL, LOGL_DEBUG, "- need_padding %d spb_status %d spb %d" + "(BSN1 %d BSN2 %d)\n", + need_padding, + spb_status, spb, index, index2); + + gprs_rlc_data_info_init_dl(&rlc, cs, need_padding, spb); rlc.usf = 7; /* will be set at scheduler */ rlc.pr = 0; /* FIXME: power reduction */ @@ -665,10 +696,9 @@ data_block_idx++) { int bsn; - GprsCodingScheme cs_enc; uint8_t *block_data; gprs_rlc_data_block_info *rdbi, *block_info; - enum egprs_puncturing_values punct_scheme; + enum egprs_rlc_dl_reseg_bsn_state reseg_status; /* Check if there are more blocks than BSNs */ if (data_block_idx < num_bsns) @@ -676,38 +706,43 @@ else bsn = bsns[0]; - cs_enc = m_rlc.block(bsn)->cs_current_trans; - /* get data and header from current block */ - block_data = m_rlc.block(bsn)->block; - /* Get current puncturing scheme from block */ - punct_scheme = gprs_get_punct_scheme( + + m_rlc.block(bsn)->next_ps = gprs_get_punct_scheme( m_rlc.block(bsn)->next_ps, - m_rlc.block(bsn)->cs_last, cs); + m_rlc.block(bsn)->cs_last, cs, spb); if (cs.isEgprs()) { - OSMO_ASSERT(punct_scheme >= EGPRS_PS_1); - OSMO_ASSERT(punct_scheme <= EGPRS_PS_3); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps >= EGPRS_PS_1); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps <= EGPRS_PS_3); } - punct[data_block_idx] = punct_scheme; + punct[data_block_idx] = m_rlc.block(bsn)->next_ps; rdbi = &rlc.block_info[data_block_idx]; block_info = &m_rlc.block(bsn)->block_info; - if(rdbi->data_len != m_rlc.block(bsn)->len) { - LOGP(DRLCMACDL, LOGL_ERROR, - "ERROR: Expected len = %d for %s instead of " - "%d in data unit %d (BSN %d, %s)\n", - rdbi->data_len, cs.name(), m_rlc.block(bsn)->len, - data_block_idx, bsn, cs_enc.name()); - OSMO_ASSERT(rdbi->data_len == m_rlc.block(bsn)->len); - } - - /* TODO: Need to handle 2 same bsns - * in header type 1 + /* + * get data and header from current block + * function returns the reseg status */ - gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, - cs); + reseg_status = egprs_dl_get_data(bsn, &block_data); + m_rlc.block(bsn)->spb_status.block_status_dl = reseg_status; + + /* + * If it is first segment of the split block set the state of + * bsn to nacked. If it is the first segment dont update the + * next ps value of bsn. since next segment also needs same cps + */ + if (spb == EGPRS_RLCMAC_DL_FIRST_SEG) + m_window.m_v_b.mark_nacked(bsn); + else { + /* + * TODO: Need to handle 2 same bsns + * in header type 1 + */ + gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, + cs); + } m_rlc.block(bsn)->cs_last = cs; rdbi->e = block_info->e; @@ -1169,3 +1204,118 @@ keep_time_frames = msecs_to_frames(bts_data()->dl_tbf_idle_msec); return frames_since_last_drain(fn) <= keep_time_frames; } + +/* + * This function returns the pointer to data which needs + * to be copied. Also updates the status of the block related to + * Split block handling in the RLC/MAC block. + */ +enum egprs_rlc_dl_reseg_bsn_state + gprs_rlcmac_dl_tbf::egprs_dl_get_data(int bsn, uint8_t **block_data) +{ + gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state *block_status_dl = + &rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + *block_data = &rlc_data->block[0]; + + /* + * Table 10.3a.0.1 of 44.060 + * MCS6,9: second segment starts at 74/2 = 37 + * MCS5,7: second segment starts at 56/2 = 28 + * MCS8: second segment starts at 31 + * MCS4: second segment starts at 44/2 = 22 + */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + if (*block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + switch (GprsCodingScheme::Scheme(cs_init)) { + case GprsCodingScheme::MCS6 : + case GprsCodingScheme::MCS9 : + *block_data = &rlc_data->block[37]; + break; + case GprsCodingScheme::MCS7 : + case GprsCodingScheme::MCS5 : + *block_data = &rlc_data->block[28]; + break; + case GprsCodingScheme::MCS8 : + *block_data = &rlc_data->block[31]; + break; + case GprsCodingScheme::MCS4 : + *block_data = &rlc_data->block[22]; + break; + default: + LOGP(DRLCMACDL, LOGL_ERROR, "Software error: " + "--%s hit invalid condition. headerType(%d) " + " blockstatus(%d) cs(%s) PLEASE FIX!\n", name(), + cs_current_trans.headerTypeData(), + *block_status_dl, cs_init.name()); + break; + + } + return EGPRS_RESEG_SECOND_SEG_SENT; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } + } + return EGPRS_RESEG_DL_DEFAULT; +} + +/* + * This function returns the status of split block + * for RLC/MAC block. + */ +unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_status(const int bsn) +{ + const gprs_rlc_data *rlc_data = m_rlc.block(bsn); + + return rlc_data->spb_status.block_status_dl; +} + +/* + * This function returns the spb value to be sent OTA + * for RLC/MAC block. + */ +enum egprs_rlcmac_dl_spb gprs_rlcmac_dl_tbf::get_egprs_dl_spb(const int bsn) +{ + struct gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state block_status_dl = + rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + + /* Table 10.4.8b.1 of 44.060 */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + /* + * if we are sending the second segment the spb should be 3 + * other wise it should be 2 + */ + if (block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + return EGPRS_RLCMAC_DL_SEC_SEG; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RLCMAC_DL_FIRST_SEG; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RLCMAC_DL_FIRST_SEG; + } + } + /* Non SPB cases 0 is reurned */ + return EGPRS_RLCMAC_DL_NO_RETX; +} diff --git a/tests/edge/EdgeTest.cpp b/tests/edge/EdgeTest.cpp index 807102c..9081d4d 100644 --- a/tests/edge/EdgeTest.cpp +++ b/tests/edge/EdgeTest.cpp @@ -517,7 +517,7 @@ /* TS 44.060, B.1 */ cs = GprsCodingScheme::CS4; - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -570,7 +570,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -592,7 +592,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -630,7 +630,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -669,7 +669,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -694,7 +694,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -719,7 +719,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -740,7 +740,7 @@ OSMO_ASSERT(data[0] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -777,7 +777,7 @@ cs = GprsCodingScheme::MCS4; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -835,7 +835,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -872,7 +872,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -923,7 +923,7 @@ OSMO_ASSERT(data[3] == 0); /* Block 3 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -967,7 +967,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -993,7 +993,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1020,7 +1020,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1074,7 +1074,7 @@ block_idx++) { struct gprs_rlc_data_info rlc; - gprs_rlc_data_info_init_dl(&rlc, cs, false); + gprs_rlc_data_info_init_dl(&rlc, cs, false, 0); memset(bits, pattern, sizeof(bits)); Decoding::rlc_copy_to_aligned_buffer( @@ -1118,12 +1118,14 @@ struct gprs_rlc_data_info rlc; printf("=== start %s ===\n", __func__); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::CS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::CS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 24); OSMO_ASSERT(rlc.block_info[0].data_len == 20); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::MCS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::MCS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 33); OSMO_ASSERT(rlc.block_info[0].data_len == 22); diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..5e45506 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -1814,6 +1814,203 @@ } +static void egprs_spb_to_normal_validation(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + uint16_t bsn1, bsn2, bsn3; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + struct gprs_rlc_dl_header_egprs_2 *egprs2; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + if (!(mcs == 6 && demanded_mcs == 3)) + return; + + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + bsn1 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) + || (egprs2->bsn1_lo); + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(bsn1 == 0); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + bsn2 = (egprs3->bsn1_hi << 9) || (egprs3->bsn1_mid << 1) || + (egprs3->bsn1_lo); + OSMO_ASSERT(bsn2 == bsn1); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Handle (MCS3, MCS3) -> MCS6 case */ + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + mcs)); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs2->cps == 0); + bsn3 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) || + (egprs2->bsn1_lo); + OSMO_ASSERT(bsn3 == bsn2); + + tbf_cleanup(dl_tbf); +} +static void establish_and_use_egprs_dl_tbf_for_spb(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + /* TODO: Need to support of MCS8 -> MCS6 ->MCS3 transistion + * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 + * dated 2016-02-07 23:45:40 (UTC) + */ + if (!(((mcs == 5) && (demanded_mcs == 2)) || + ((mcs == 6) && (demanded_mcs == 3)) || + ((mcs == 4) && (demanded_mcs == 1)))) + return; + + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + tbf_cleanup(dl_tbf); +} + static void establish_and_use_egprs_dl_tbf_for_retx(BTS *the_bts, int mcs, int demanded_mcs) { @@ -1972,6 +2169,9 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; + /* First parameter is current MCS, second one is demanded_mcs */ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 6); @@ -1981,6 +2181,38 @@ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 9); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 7, 5); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 9, 6); + + printf("=== end %s ===\n", __func__); +} + +static void test_tbf_egprs_spb_dl(void) +{ + BTS the_bts; + gprs_rlcmac_bts *bts; + uint8_t ts_no = 4; + int i, j; + + printf("=== start %s ===\n", __func__); + + bts = the_bts.bts_data(); + bts->cs_downgrade_threshold = 0; + setup_bts(&the_bts, ts_no); + bts->dl_tbf_idle_msec = 200; + bts->egprs_enabled = 1; + + /* ARQ I resegmentation support */ + bts->dl_arq_type = EGPRS_ARQ1; + + /* + * First parameter is current MCS, second one is demanded_mcs + * currently only MCS5->MCS2, MCS6->3, MCS4->MCS1 is tested in UT + * rest scenarios has been integration tested + */ + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 6, 3); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 5, 2); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 4, 1); + /* check MCS6->(MCS3+MCS3)->MCS6 case */ + egprs_spb_to_normal_validation(&the_bts, 6, 3); printf("=== end %s ===\n", __func__); } @@ -1999,6 +2231,8 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; for (i = 1; i <= 9; i++) establish_and_use_egprs_dl_tbf(&the_bts, i); @@ -2071,6 +2305,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_egprs_spb_dl(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..1ba4189 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -72,6 +72,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -81,6 +82,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -157,6 +159,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -166,6 +169,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -242,6 +246,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -251,6 +256,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -259,6 +265,7 @@ - Sending new block at BSN 2, CS=CS-1 -- Chunk with length 160 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=13 block=3 data=07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b @@ -267,6 +274,7 @@ - Sending new block at BSN 3, CS=CS-1 -- Chunk with length 140 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=17 block=4 data=07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @@ -275,6 +283,7 @@ - Sending new block at BSN 4, CS=CS-1 -- Chunk with length 120 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=21 block=5 data=07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 @@ -283,6 +292,7 @@ - Sending new block at BSN 5, CS=CS-1 -- Chunk with length 100 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=26 block=6 data=07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 @@ -291,6 +301,7 @@ - Sending new block at BSN 6, CS=CS-1 -- Chunk with length 80 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=30 block=7 data=07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b @@ -299,6 +310,7 @@ - Sending new block at BSN 7, CS=CS-1 -- Chunk with length 60 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=34 block=8 data=07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f @@ -307,6 +319,7 @@ - Sending new block at BSN 8, CS=CS-1 -- Chunk with length 40 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=39 block=9 data=07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 @@ -315,6 +328,7 @@ - Sending new block at BSN 9, CS=CS-1 -- Chunk with length 20 would exactly fit into space (20): add length header with LI=0, to make frame extend to next block, and we are done data block (BSN 9, CS-1): 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=43 block=10 data=07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 @@ -326,6 +340,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=47 block=11 data=07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 @@ -334,6 +349,7 @@ - Sending new block at BSN 11, CS=CS-1 -- Chunk with length 182 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=52 block=0 data=07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 @@ -342,6 +358,7 @@ - Sending new block at BSN 12, CS=CS-1 -- Chunk with length 162 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=56 block=1 data=07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 @@ -350,6 +367,7 @@ - Sending new block at BSN 13, CS=CS-1 -- Chunk with length 142 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 13, CS-1): 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=60 block=2 data=07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d @@ -358,6 +376,7 @@ - Sending new block at BSN 14, CS=CS-1 -- Chunk with length 122 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=65 block=3 data=07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 @@ -366,6 +385,7 @@ - Sending new block at BSN 15, CS=CS-1 -- Chunk with length 102 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=69 block=4 data=07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 @@ -374,6 +394,7 @@ - Sending new block at BSN 16, CS=CS-1 -- Chunk with length 82 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=73 block=5 data=07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 @@ -382,6 +403,7 @@ - Sending new block at BSN 17, CS=CS-1 -- Chunk with length 62 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=78 block=6 data=07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d @@ -390,6 +412,7 @@ - Sending new block at BSN 18, CS=CS-1 -- Chunk with length 42 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=82 block=7 data=07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 @@ -398,6 +421,7 @@ - Sending new block at BSN 19, CS=CS-1 -- Chunk with length 22 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=86 block=8 data=07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 @@ -411,6 +435,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=16 data block (BSN 20, CS-1): 0a 41 c6 c7 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -449,6 +474,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 data block (BSN 21, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -468,6 +494,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 22, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FINISHED) @@ -1481,6 +1508,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 0, CS-1): 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 MSG = 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 @@ -1491,6 +1519,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 1, CS-1): 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 MSG = 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 @@ -1501,6 +1530,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FINISHED data block (BSN 2, CS-1): 4d 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling cannot be scheduled in this TS 7 (first control TS 4) @@ -1784,6 +1814,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=10 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 0, CS-4): 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654292 TS 7 @@ -1797,6 +1828,7 @@ TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) downlink (V(A)==0 .. V(S)==1) - Restarting at BSN 0, because all blocks have been transmitted. - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-4): 07 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 @@ -2365,6 +2397,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654279 block=10 data=00 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 @@ -2384,6 +2417,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -2406,6 +2440,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654288 block=0 data=00 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 @@ -2425,6 +2460,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654292 block=1 data=00 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2447,6 +2483,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654296 block=2 data=00 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c @@ -2466,6 +2503,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654301 block=3 data=00 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b @@ -2488,6 +2526,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 6, CS-1): 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654305 block=4 data=00 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 @@ -2507,6 +2546,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654309 block=5 data=00 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 @@ -2526,6 +2566,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654314 block=6 data=00 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 @@ -2548,6 +2589,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654318 block=7 data=00 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 @@ -2567,6 +2609,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654322 block=8 data=00 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2589,6 +2632,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654327 block=9 data=00 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c @@ -2608,6 +2652,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654331 block=10 data=00 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b @@ -2630,6 +2675,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 13, CS-1): 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654335 block=11 data=00 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 @@ -2649,6 +2695,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654340 block=0 data=00 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 @@ -2668,6 +2715,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654344 block=1 data=00 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 @@ -2690,6 +2738,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654348 block=2 data=00 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 @@ -2709,6 +2758,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654353 block=3 data=00 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2731,6 +2781,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654357 block=4 data=00 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c @@ -2750,6 +2801,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654361 block=5 data=00 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b @@ -2772,6 +2824,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 20, CS-1): 16 35 45 54 20 32 38 4c 4c 43 20 50 41 43 4b 45 54 20 32 39 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because 20 blocks sent. TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW): Scheduling polling at FN 2654379 TS 7 @@ -2795,6 +2848,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 21, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) msg block (BSN 21, CS-1): 07 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654370 block=7 data=00 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 @@ -2814,6 +2868,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 22, CS-1): 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) msg block (BSN 22, CS-1): 07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654374 block=8 data=07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 @@ -2836,6 +2891,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 23, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) msg block (BSN 23, CS-1): 07 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654379 block=9 data=00 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 @@ -2855,6 +2911,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 24, CS-1): 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) msg block (BSN 24, CS-1): 07 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654383 block=10 data=00 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2877,6 +2934,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 25, CS-1): 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 25 BSN2 -1) - Copying data unit 0 (BSN 25) msg block (BSN 25, CS-1): 07 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654387 block=11 data=00 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c @@ -2896,6 +2954,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 26, CS-1): 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 26 BSN2 -1) - Copying data unit 0 (BSN 26) msg block (BSN 26, CS-1): 07 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654392 block=0 data=00 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b @@ -2918,6 +2977,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 27, CS-1): 16 35 45 54 20 33 38 4c 4c 43 20 50 41 43 4b 45 54 20 33 39 +- need_padding 0 spb_status 0 spb 0(BSN1 27 BSN2 -1) - Copying data unit 0 (BSN 27) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) @@ -3028,6 +3088,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654405 block=3 data=00 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 @@ -3047,6 +3108,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654409 block=4 data=00 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 @@ -3066,6 +3128,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (16) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654413 block=5 data=00 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 @@ -3085,6 +3148,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (14) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654418 block=6 data=00 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 @@ -3104,6 +3168,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654422 block=7 data=00 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -3123,6 +3188,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654426 block=8 data=00 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 @@ -3142,6 +3208,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654431 block=9 data=00 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b @@ -3161,6 +3228,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654435 block=10 data=00 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 @@ -3180,6 +3248,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654439 block=11 data=00 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 @@ -3199,6 +3268,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654444 block=0 data=00 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c @@ -3218,6 +3288,7 @@ Complete DL frame for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=21 TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 10, CS-1): 4d 43 20 50 41 43 4b 45 54 20 30 39 20 28 54 42 46 20 32 29 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654461 TS 7 @@ -3698,6 +3769,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 0, MCS-1): 14 15 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3711,6 +3783,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3721,6 +3794,7 @@ - Sending new block at BSN 2, CS=MCS-1 -- Chunk with length 490 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3731,6 +3805,7 @@ - Sending new block at BSN 3, CS=MCS-1 -- Chunk with length 468 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3741,6 +3816,7 @@ - Sending new block at BSN 4, CS=MCS-1 -- Chunk with length 446 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3751,6 +3827,7 @@ - Sending new block at BSN 5, CS=MCS-1 -- Chunk with length 424 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3761,6 +3838,7 @@ - Sending new block at BSN 6, CS=MCS-1 -- Chunk with length 402 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3771,6 +3849,7 @@ - Sending new block at BSN 7, CS=MCS-1 -- Chunk with length 380 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3781,6 +3860,7 @@ - Sending new block at BSN 8, CS=MCS-1 -- Chunk with length 358 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3791,6 +3871,7 @@ - Sending new block at BSN 9, CS=MCS-1 -- Chunk with length 336 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3801,6 +3882,7 @@ - Sending new block at BSN 10, CS=MCS-1 -- Chunk with length 314 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3811,6 +3893,7 @@ - Sending new block at BSN 11, CS=MCS-1 -- Chunk with length 292 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3821,6 +3904,7 @@ - Sending new block at BSN 12, CS=MCS-1 -- Chunk with length 270 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3831,6 +3915,7 @@ - Sending new block at BSN 13, CS=MCS-1 -- Chunk with length 248 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3841,6 +3926,7 @@ - Sending new block at BSN 14, CS=MCS-1 -- Chunk with length 226 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3851,6 +3937,7 @@ - Sending new block at BSN 15, CS=MCS-1 -- Chunk with length 204 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3861,6 +3948,7 @@ - Sending new block at BSN 16, CS=MCS-1 -- Chunk with length 182 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3871,6 +3959,7 @@ - Sending new block at BSN 17, CS=MCS-1 -- Chunk with length 160 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3881,6 +3970,7 @@ - Sending new block at BSN 18, CS=MCS-1 -- Chunk with length 138 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3891,6 +3981,7 @@ - Sending new block at BSN 19, CS=MCS-1 -- Chunk with length 116 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 19, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3901,6 +3992,7 @@ - Sending new block at BSN 20, CS=MCS-1 -- Chunk with length 94 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 20, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3911,6 +4003,7 @@ - Sending new block at BSN 21, CS=MCS-1 -- Chunk with length 72 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 21, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3921,6 +4014,7 @@ - Sending new block at BSN 22, CS=MCS-1 -- Chunk with length 50 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 22, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3931,6 +4025,7 @@ - Sending new block at BSN 23, CS=MCS-1 -- Chunk with length 28 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 23, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3946,6 +4041,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 24, MCS-1): 0c 1d 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4006,6 +4102,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=16 data block (BSN 0, MCS-2): 14 21 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4019,6 +4116,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4029,6 +4127,7 @@ - Sending new block at BSN 2, CS=MCS-2 -- Chunk with length 484 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4039,6 +4138,7 @@ - Sending new block at BSN 3, CS=MCS-2 -- Chunk with length 456 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4049,6 +4149,7 @@ - Sending new block at BSN 4, CS=MCS-2 -- Chunk with length 428 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4059,6 +4160,7 @@ - Sending new block at BSN 5, CS=MCS-2 -- Chunk with length 400 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4069,6 +4171,7 @@ - Sending new block at BSN 6, CS=MCS-2 -- Chunk with length 372 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4079,6 +4182,7 @@ - Sending new block at BSN 7, CS=MCS-2 -- Chunk with length 344 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4089,6 +4193,7 @@ - Sending new block at BSN 8, CS=MCS-2 -- Chunk with length 316 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4099,6 +4204,7 @@ - Sending new block at BSN 9, CS=MCS-2 -- Chunk with length 288 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4109,6 +4215,7 @@ - Sending new block at BSN 10, CS=MCS-2 -- Chunk with length 260 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4119,6 +4226,7 @@ - Sending new block at BSN 11, CS=MCS-2 -- Chunk with length 232 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4129,6 +4237,7 @@ - Sending new block at BSN 12, CS=MCS-2 -- Chunk with length 204 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4139,6 +4248,7 @@ - Sending new block at BSN 13, CS=MCS-2 -- Chunk with length 176 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4149,6 +4259,7 @@ - Sending new block at BSN 14, CS=MCS-2 -- Chunk with length 148 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4159,6 +4270,7 @@ - Sending new block at BSN 15, CS=MCS-2 -- Chunk with length 120 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4169,6 +4281,7 @@ - Sending new block at BSN 16, CS=MCS-2 -- Chunk with length 92 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4179,6 +4292,7 @@ - Sending new block at BSN 17, CS=MCS-2 -- Chunk with length 64 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4189,6 +4303,7 @@ - Sending new block at BSN 18, CS=MCS-2 -- Chunk with length 36 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4204,6 +4319,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=18 data block (BSN 19, MCS-2): 10 25 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4264,6 +4380,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=25 data block (BSN 0, MCS-3): 14 33 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4277,6 +4394,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4287,6 +4405,7 @@ - Sending new block at BSN 2, CS=MCS-3 -- Chunk with length 475 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4297,6 +4416,7 @@ - Sending new block at BSN 3, CS=MCS-3 -- Chunk with length 438 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4307,6 +4427,7 @@ - Sending new block at BSN 4, CS=MCS-3 -- Chunk with length 401 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4317,6 +4438,7 @@ - Sending new block at BSN 5, CS=MCS-3 -- Chunk with length 364 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4327,6 +4449,7 @@ - Sending new block at BSN 6, CS=MCS-3 -- Chunk with length 327 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4337,6 +4460,7 @@ - Sending new block at BSN 7, CS=MCS-3 -- Chunk with length 290 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4347,6 +4471,7 @@ - Sending new block at BSN 8, CS=MCS-3 -- Chunk with length 253 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4357,6 +4482,7 @@ - Sending new block at BSN 9, CS=MCS-3 -- Chunk with length 216 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4367,6 +4493,7 @@ - Sending new block at BSN 10, CS=MCS-3 -- Chunk with length 179 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4377,6 +4504,7 @@ - Sending new block at BSN 11, CS=MCS-3 -- Chunk with length 142 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4387,6 +4515,7 @@ - Sending new block at BSN 12, CS=MCS-3 -- Chunk with length 105 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4397,6 +4526,7 @@ - Sending new block at BSN 13, CS=MCS-3 -- Chunk with length 68 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4410,6 +4540,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-3): 3f 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4425,6 +4556,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=34 data block (BSN 15, MCS-3): 02 45 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4485,6 +4617,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=32 data block (BSN 0, MCS-4): 14 41 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4498,6 +4631,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4508,6 +4642,7 @@ - Sending new block at BSN 2, CS=MCS-4 -- Chunk with length 468 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4518,6 +4653,7 @@ - Sending new block at BSN 3, CS=MCS-4 -- Chunk with length 424 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4528,6 +4664,7 @@ - Sending new block at BSN 4, CS=MCS-4 -- Chunk with length 380 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4538,6 +4675,7 @@ - Sending new block at BSN 5, CS=MCS-4 -- Chunk with length 336 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4548,6 +4686,7 @@ - Sending new block at BSN 6, CS=MCS-4 -- Chunk with length 292 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4558,6 +4697,7 @@ - Sending new block at BSN 7, CS=MCS-4 -- Chunk with length 248 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4568,6 +4708,7 @@ - Sending new block at BSN 8, CS=MCS-4 -- Chunk with length 204 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4578,6 +4719,7 @@ - Sending new block at BSN 9, CS=MCS-4 -- Chunk with length 160 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4588,6 +4730,7 @@ - Sending new block at BSN 10, CS=MCS-4 -- Chunk with length 116 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4598,6 +4741,7 @@ - Sending new block at BSN 11, CS=MCS-4 -- Chunk with length 72 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4613,6 +4757,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 12, MCS-4): 38 1d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4673,6 +4818,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-5): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4686,6 +4832,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4696,6 +4843,7 @@ - Sending new block at BSN 2, CS=MCS-5 -- Chunk with length 456 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4706,6 +4854,7 @@ - Sending new block at BSN 3, CS=MCS-5 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4716,6 +4865,7 @@ - Sending new block at BSN 4, CS=MCS-5 -- Chunk with length 344 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4726,6 +4876,7 @@ - Sending new block at BSN 5, CS=MCS-5 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4736,6 +4887,7 @@ - Sending new block at BSN 6, CS=MCS-5 -- Chunk with length 232 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4746,6 +4898,7 @@ - Sending new block at BSN 7, CS=MCS-5 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4756,6 +4909,7 @@ - Sending new block at BSN 8, CS=MCS-5 -- Chunk with length 120 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4766,6 +4920,7 @@ - Sending new block at BSN 9, CS=MCS-5 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4781,6 +4936,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-5): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4841,6 +4997,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-6): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4854,6 +5011,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4864,6 +5022,7 @@ - Sending new block at BSN 2, CS=MCS-6 -- Chunk with length 438 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4874,6 +5033,7 @@ - Sending new block at BSN 3, CS=MCS-6 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4884,6 +5044,7 @@ - Sending new block at BSN 4, CS=MCS-6 -- Chunk with length 290 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4894,6 +5055,7 @@ - Sending new block at BSN 5, CS=MCS-6 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4904,6 +5066,7 @@ - Sending new block at BSN 6, CS=MCS-6 -- Chunk with length 142 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4917,6 +5080,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-6): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4932,6 +5096,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-6): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4993,6 +5158,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-7): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5002,12 +5168,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(7) last_mcs(5) demanded_mcs(7) cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-7 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5022,6 +5189,7 @@ - Sending new block at BSN 3, CS=MCS-7 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5036,6 +5204,7 @@ - Sending new block at BSN 5, CS=MCS-7 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5050,6 +5219,7 @@ - Sending new block at BSN 7, CS=MCS-7 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5064,6 +5234,7 @@ - Sending new block at BSN 9, CS=MCS-7 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 9) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5081,6 +5252,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-7): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5142,6 +5314,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=56 data block (BSN 0, MCS-8): 14 71 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5152,12 +5325,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(8) demanded_mcs(8) cs_trans(8) +- initial_cs_dl(8) last_mcs(8) demanded_mcs(8) cs_trans(8) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-8 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5172,6 +5346,7 @@ - Sending new block at BSN 3, CS=MCS-8 -- Chunk with length 376 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5186,6 +5361,7 @@ - Sending new block at BSN 5, CS=MCS-8 -- Chunk with length 240 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5200,6 +5376,7 @@ - Sending new block at BSN 7, CS=MCS-8 -- Chunk with length 104 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5217,6 +5394,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=30 data block (BSN 8, MCS-8): 48 3d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5279,6 +5457,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-9): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5288,12 +5467,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(9) last_mcs(6) demanded_mcs(9) cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-9 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5308,6 +5488,7 @@ - Sending new block at BSN 3, CS=MCS-9 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5322,6 +5503,7 @@ - Sending new block at BSN 5, CS=MCS-9 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5339,6 +5521,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-9): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5356,6 +5539,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-9): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5402,11 +5586,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(6) cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5450,11 +5636,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 96 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(1) demanded_mcs(1) cs_trans(1) +- initial_cs_dl(1) last_mcs(1) demanded_mcs(1) cs_trans(1) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 98 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5498,11 +5686,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-2): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 92 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(2) demanded_mcs(2) cs_trans(2) +- initial_cs_dl(2) last_mcs(2) demanded_mcs(2) cs_trans(2) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 94 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5546,6 +5736,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5557,6 +5748,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-5): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5564,10 +5756,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-5): 0f 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7) cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7) cs_trans(7) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-7): 07 00 00 02 c0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 @@ -5612,6 +5805,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5623,6 +5817,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-6): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5630,10 +5825,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-6): 0f 40 00 00 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9) cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9) cs_trans(9) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-9): 07 00 00 02 28 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 @@ -5686,6 +5882,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-7): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5694,13 +5891,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-7): 0f 00 00 02 a0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5) cs_trans(5) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5) cs_trans(5) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-5): 07 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5752,6 +5951,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-9): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5760,13 +5960,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-9): 0f 00 00 02 00 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6) cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6) cs_trans(6) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-6): 07 40 00 02 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5780,3 +5982,233 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-5 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(2) cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 d2 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(2) demanded_mcs(2) cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 f2 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-4 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (44) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-4): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-4): 07 00 00 80 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(4) demanded_mcs(1) cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 d6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(1) demanded_mcs(1) cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 f6 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(6) cs_trans(6) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 2 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..c38417d 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,9 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_egprs_spb_dl === +Testing retx for MCS 6 to reseg_mcs 3 +Testing retx for MCS 5 to reseg_mcs 2 +Testing retx for MCS 4 to reseg_mcs 1 +Testing retx for MCS 6 to reseg_mcs 3 +=== end test_tbf_egprs_spb_dl === -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 22 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Tue Aug 23 10:19:02 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 23 Aug 2016 10:19:02 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 22: (1 comment) https://gerrit.osmocom.org/#/c/655/21//COMMIT_MSG Commit Message: Line 10: Retx. This patch will also Upgrade the test suite with test cases > hm, was about to +2, but I don't see the test cases this commit log is talk Hi Neels, Please refer TbfTest.cpp file in this patch for test added to verify this feature. Thanks, Aravind Sirsikar -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 22 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 23 10:24:44 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 23 Aug 2016 10:24:44 +0000 Subject: osmo-pcu[master]: Describe the issue with EGPRS PUAN encoding In-Reply-To: References: Message-ID: Patch Set 5: (5 comments) Almost adding my +2 but the commit log just isn't satisfactory yet... https://gerrit.osmocom.org/#/c/702/5//COMMIT_MSG Commit Message: Line 7: Describe the issue with EGPRS PUAN encoding This summary line is still unsatisfactory: "the issue" is too general and no test case mentioned. Make it: "EGPRS: PUAN encoding: add test case to show wrong urbb_len issue" Line 9: This patch is related to bug https://osmocom.org/issues/1793 (we often place a line "Related: OS#1793" in the bottom) Line 14: corrected in the subsequent commit related to this topic including "This patch adds a test case which expects a current bug with EGPRS PUAN encoding when VQ != VR. The test's expectation is corrected along with the bugfix in a subsequent commit." -- stop. I don't think we want to reference gerrit from here. In the future, you could add a gerrit comment instead. But if we look at the git history years from now, who knows whether our gerrit will still be available. If you want, you could state the commit summary line here for reference? Line 17: The test_tbf_puan_issue test describes the issue with initially "Add test_tbf_puan_issue to describe..." Actually I notice now that the test name is too general. Line 23: This is considerable issue with OTA. I would write: "Add test_tbf_puan_urbb_len to describe the following bug: EGPRS PUAN encoding disregards the urbb_len, leading to identical PUAN messages regardless of the urbb_len." (and drop all hex dumps and BSN references, they are in the code. All has been said.) -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 5 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 23 10:41:49 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 23 Aug 2016 10:41:49 +0000 Subject: [PATCH] osmo-pcu[master]: EGPRS: PUAN encoding: add test case to show wrong urbb_len i... In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/702 to look at the new patch set (#6). EGPRS: PUAN encoding: add test case to show wrong urbb_len issue This patch adds a test case which expects a current bug with EGPRS PUAN encoding when VQ != VR. The test's expectation is corrected along with the bugfix in a subsequent commit AddS test_tbf_puan_urbb_len to describe the following bug: EGPRS PUAN encoding disregards the urbb_len, leading to identical PUAN messages regardless of the urbb_len. "Related: OS#1793" Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 --- M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 3 files changed, 298 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/02/702/6 diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..5a73a43 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -618,6 +618,143 @@ &ulreq, tbf->poll_fn); } +static gprs_rlcmac_ul_tbf *puan_issue(BTS *the_bts, + uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, + uint8_t ms_class, uint8_t egprs_ms_class) +{ + GprsMs *ms; + uint32_t rach_fn = *fn - 51; + uint32_t sba_fn = *fn + 52; + uint8_t trx_no = 0; + int tfi = 0, i = 0; + gprs_rlcmac_ul_tbf *ul_tbf; + struct gprs_rlcmac_pdch *pdch; + gprs_rlcmac_bts *bts; + RlcMacUplink_t ulreq = {0}; + struct pcu_l1_meas meas; + struct gprs_rlc_ul_header_egprs_3 *egprs3 = NULL; + GprsCodingScheme cs; + + meas.set_rssi(31); + bts = the_bts->bts_data(); + + /* needed to set last_rts_fn in the PDCH object */ + request_dl_rlc_block(bts, trx_no, ts_no, fn); + + /* + * simulate RACH, this sends an Immediate + * Assignment Uplink on the AGCH + */ + the_bts->rcv_rach(0x73, rach_fn, qta); + + /* get next free TFI */ + tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1); + + /* fake a resource request */ + ulreq.u.MESSAGE_TYPE = MT_PACKET_RESOURCE_REQUEST; + ulreq.u.Packet_Resource_Request.PayloadType = GPRS_RLCMAC_CONTROL_BLOCK; + ulreq.u.Packet_Resource_Request.ID.UnionType = 1; /* != 0 */ + ulreq.u.Packet_Resource_Request.ID.u.TLLI = tlli; + ulreq.u.Packet_Resource_Request.Exist_MS_Radio_Access_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + Count_MS_RA_capability_value = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Exist_Multislot_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + Exist_GPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + GPRS_multislot_class = ms_class; + if (egprs_ms_class) { + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Multislot_capability.Exist_EGPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Multislot_capability.EGPRS_multislot_class = ms_class; + } + + send_ul_mac_block(the_bts, trx_no, ts_no, &ulreq, sba_fn); + + /* check the TBF */ + ul_tbf = the_bts->ul_tbf_by_tfi(tfi, trx_no, ts_no); + OSMO_ASSERT(ul_tbf); + OSMO_ASSERT(ul_tbf->ta() == qta / 4); + + /* send packet uplink assignment */ + *fn = sba_fn; + request_dl_rlc_block(ul_tbf, fn); + + /* send real acknowledgement */ + send_control_ack(ul_tbf); + + check_tbf(ul_tbf); + /* send fake data */ + uint8_t data_msg[42] = { + 0xf << 2, /* GPRS_RLCMAC_DATA_BLOCK << 6, CV = 15 */ + tfi << 1, + 1, /* BSN:7, E:1 */ + }; + + pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no]; + pdch->rcv_block(&data_msg[0], 23, *fn, &meas); + + ms = the_bts->ms_by_tlli(tlli); + OSMO_ASSERT(ms != NULL); + OSMO_ASSERT(ms->ta() == qta/4); + OSMO_ASSERT(ms->ul_tbf() == ul_tbf); + + /* + * TS 44.060, B.8.1 + * first seg received first, later second seg + */ + cs = GprsCodingScheme::MCS3; + egprs3 = (struct gprs_rlc_ul_header_egprs_3 *) data_msg; + egprs3->si = 0; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 1; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 0; + egprs3->pi = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + struct msgb *msg1 = ul_tbf->create_ul_ack(*fn, ts_no); + + egprs3->si = 0; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 4; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + struct msgb *msg2 = ul_tbf->create_ul_ack(*fn, ts_no); + + /* TODO: Need to modify the assert */ + OSMO_ASSERT(!memcmp(msg2->data, msg1->data, msg1->data_len)); + + return ul_tbf; +} + static gprs_rlcmac_ul_tbf *establish_ul_tbf_two_phase_spb(BTS *the_bts, uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, uint8_t ms_class, uint8_t egprs_ms_class) @@ -1631,6 +1768,41 @@ gprs_bssgp_destroy(); } +static void test_tbf_puan_issue(void) +{ + BTS the_bts; + int ts_no = 7; + uint32_t fn = 2654218; + uint16_t qta = 31; + uint32_t tlli = 0xf1223344; + const char *imsi = "0011223344"; + uint8_t ms_class = 1; + uint8_t egprs_ms_class = 1; + gprs_rlcmac_ul_tbf *ul_tbf; + GprsMs *ms; + uint8_t test_data[256]; + + printf("=== start %s ===\n", __func__); + + memset(test_data, 1, sizeof(test_data)); + + setup_bts(&the_bts, ts_no, 4); + the_bts.bts_data()->initial_mcs_dl = 9; + the_bts.bts_data()->egprs_enabled = 1; + + ul_tbf = puan_issue(&the_bts, ts_no, tlli, &fn, qta, + ms_class, egprs_ms_class); + + ms = ul_tbf->ms(); + fprintf(stderr, "Got '%s', TA=%d\n", ul_tbf->name(), ul_tbf->ta()); + fprintf(stderr, + "Got MS: TLLI = 0x%08x, TA = %d\n", ms->tlli(), ms->ta()); + + send_dl_data(&the_bts, tlli, imsi, test_data, sizeof(test_data)); + + printf("=== end %s ===\n", __func__); +} + static void test_tbf_egprs_two_phase_spb(void) { BTS the_bts; @@ -2071,6 +2243,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_puan_issue(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..aa8a087 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -5780,3 +5780,126 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654218 block=8 data=47 94 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +MS requests UL TBF on RACH, so we provide one: +MS requests single block allocation +RX: [PCU <- BTS] RACH qbit-ta=31 ra=0x73, Fn=2654167 (17,25,9), SBFn=2654270 +TX: Immediate Assignment Uplink (AGCH) + - TRX=0 (0) TS=7 TA=7 TSC=0 TFI=-1 USF=7 +Sending data request: trx=0 ts=0 sapi=2 arfcn=0 fn=0 block=0 data=2d 06 3f 10 0f 00 00 73 8b 29 07 00 c0 0c 5a 43 2b 2b 2b 2b 2b 2b 2b +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +MS requests UL TBF in packet resource request of single block, so we provide one: +MS supports EGPRS multislot class 1. +********** TBF starts here ********** +Allocating UL TBF: MS_CLASS=1/1 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 1 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 1 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign uplink TS=7 TFI=0 USF=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 00 +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=ASSIGN EGPRS) starting timer 3169. +Modifying MS object, UL TLLI: 0x00000000 -> 0xf1223344, not yet confirmed +Modifying MS object, TLLI = 0xf1223344, TA 0 -> 7 +Change control TS to 7 until assinment is complete. +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS)s start Packet Uplink Assignment (PACCH) ++++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++ +------------------------- TX : Packet Uplink Assignment ------------------------- +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS): Scheduling polling at FN 2654283 TS 7 +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS) changes state from ASSIGN to WAIT ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Scheduled UL Assignment polling on FN=2654283, TS=7 +Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) (TRX=0, TS=7) +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654270 block=8 data=4f 28 5e 24 46 68 90 f8 0a 39 00 00 88 00 08 2b 2b 2b 2b 2b 2b 2b 2b +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Packet Control Ack +TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) changes state from WAIT ASSIGN to FLOW +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=0 .. V(R)=0) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got CS-1 RLC data block: CV=15, BSN=0, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 0 storing in window (0..63) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 1 +- Taking block 0 out, raising V(Q) to 1 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=0 CV=15 +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1d 08 40 c1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=0, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=1) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=1, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 1 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 2 +- Taking block 1 out, raising V(Q) to 2 +- Assembling frames: (len=37) +-- Frame 1 starts at offset 0, length=37, is_complete=0 +- No gaps in received block, last block: BSN=1 CV=7 +Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) + - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 2, BOW, EOW +Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1d 20 40 c1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=0, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=2 .. V(R)=2) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=4, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 4 storing in window (2..65) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 5 +Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) + - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 5, BOW, EOW +Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got 'TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS)', TA=7 +Got MS: TLLI = 0xf1223344, TA = 7 +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=1/1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign downlink TS=7 TFI=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0xf1223344, TBF = TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 80 +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +Modifying MS object, TLLI: 0xf1223344 confirmed +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) [DOWNLINK] START +Modifying MS object, TLLI = 0xf1223344, IMSI '' -> '0011223344' +Send dowlink assignment on PACCH, because TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) exists +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) starting timer 0. +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) append diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..6b99857 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,5 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_puan_issue === +=== end test_tbf_puan_issue === -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 6 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Tue Aug 23 10:42:16 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 23 Aug 2016 10:42:16 +0000 Subject: osmo-pcu[master]: EGPRS: PUAN encoding: add test case to show wrong urbb_len i... In-Reply-To: References: Message-ID: Patch Set 6: (1 comment) https://gerrit.osmocom.org/#/c/702/6//COMMIT_MSG Commit Message: Line 17: "Related: OS#1793" fix here -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 6 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 23 10:42:38 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 23 Aug 2016 10:42:38 +0000 Subject: [PATCH] osmo-pcu[master]: EGPRS: PUAN encoding: add test case to show wrong urbb_len i... In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/702 to look at the new patch set (#7). EGPRS: PUAN encoding: add test case to show wrong urbb_len issue This patch adds a test case which expects a current bug with EGPRS PUAN encoding when VQ != VR. The test's expectation is corrected along with the bugfix in a subsequent commit AddS test_tbf_puan_urbb_len to describe the following bug: EGPRS PUAN encoding disregards the urbb_len, leading to identical PUAN messages regardless of the urbb_len. "Related: OS#1793" Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 --- M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 3 files changed, 298 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/02/702/7 diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..5a73a43 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -618,6 +618,143 @@ &ulreq, tbf->poll_fn); } +static gprs_rlcmac_ul_tbf *puan_issue(BTS *the_bts, + uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, + uint8_t ms_class, uint8_t egprs_ms_class) +{ + GprsMs *ms; + uint32_t rach_fn = *fn - 51; + uint32_t sba_fn = *fn + 52; + uint8_t trx_no = 0; + int tfi = 0, i = 0; + gprs_rlcmac_ul_tbf *ul_tbf; + struct gprs_rlcmac_pdch *pdch; + gprs_rlcmac_bts *bts; + RlcMacUplink_t ulreq = {0}; + struct pcu_l1_meas meas; + struct gprs_rlc_ul_header_egprs_3 *egprs3 = NULL; + GprsCodingScheme cs; + + meas.set_rssi(31); + bts = the_bts->bts_data(); + + /* needed to set last_rts_fn in the PDCH object */ + request_dl_rlc_block(bts, trx_no, ts_no, fn); + + /* + * simulate RACH, this sends an Immediate + * Assignment Uplink on the AGCH + */ + the_bts->rcv_rach(0x73, rach_fn, qta); + + /* get next free TFI */ + tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1); + + /* fake a resource request */ + ulreq.u.MESSAGE_TYPE = MT_PACKET_RESOURCE_REQUEST; + ulreq.u.Packet_Resource_Request.PayloadType = GPRS_RLCMAC_CONTROL_BLOCK; + ulreq.u.Packet_Resource_Request.ID.UnionType = 1; /* != 0 */ + ulreq.u.Packet_Resource_Request.ID.u.TLLI = tlli; + ulreq.u.Packet_Resource_Request.Exist_MS_Radio_Access_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + Count_MS_RA_capability_value = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Exist_Multislot_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + Exist_GPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + GPRS_multislot_class = ms_class; + if (egprs_ms_class) { + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Multislot_capability.Exist_EGPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Multislot_capability.EGPRS_multislot_class = ms_class; + } + + send_ul_mac_block(the_bts, trx_no, ts_no, &ulreq, sba_fn); + + /* check the TBF */ + ul_tbf = the_bts->ul_tbf_by_tfi(tfi, trx_no, ts_no); + OSMO_ASSERT(ul_tbf); + OSMO_ASSERT(ul_tbf->ta() == qta / 4); + + /* send packet uplink assignment */ + *fn = sba_fn; + request_dl_rlc_block(ul_tbf, fn); + + /* send real acknowledgement */ + send_control_ack(ul_tbf); + + check_tbf(ul_tbf); + /* send fake data */ + uint8_t data_msg[42] = { + 0xf << 2, /* GPRS_RLCMAC_DATA_BLOCK << 6, CV = 15 */ + tfi << 1, + 1, /* BSN:7, E:1 */ + }; + + pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no]; + pdch->rcv_block(&data_msg[0], 23, *fn, &meas); + + ms = the_bts->ms_by_tlli(tlli); + OSMO_ASSERT(ms != NULL); + OSMO_ASSERT(ms->ta() == qta/4); + OSMO_ASSERT(ms->ul_tbf() == ul_tbf); + + /* + * TS 44.060, B.8.1 + * first seg received first, later second seg + */ + cs = GprsCodingScheme::MCS3; + egprs3 = (struct gprs_rlc_ul_header_egprs_3 *) data_msg; + egprs3->si = 0; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 1; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 0; + egprs3->pi = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + struct msgb *msg1 = ul_tbf->create_ul_ack(*fn, ts_no); + + egprs3->si = 0; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 4; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + struct msgb *msg2 = ul_tbf->create_ul_ack(*fn, ts_no); + + /* TODO: Need to modify the assert */ + OSMO_ASSERT(!memcmp(msg2->data, msg1->data, msg1->data_len)); + + return ul_tbf; +} + static gprs_rlcmac_ul_tbf *establish_ul_tbf_two_phase_spb(BTS *the_bts, uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, uint8_t ms_class, uint8_t egprs_ms_class) @@ -1631,6 +1768,41 @@ gprs_bssgp_destroy(); } +static void test_tbf_puan_issue(void) +{ + BTS the_bts; + int ts_no = 7; + uint32_t fn = 2654218; + uint16_t qta = 31; + uint32_t tlli = 0xf1223344; + const char *imsi = "0011223344"; + uint8_t ms_class = 1; + uint8_t egprs_ms_class = 1; + gprs_rlcmac_ul_tbf *ul_tbf; + GprsMs *ms; + uint8_t test_data[256]; + + printf("=== start %s ===\n", __func__); + + memset(test_data, 1, sizeof(test_data)); + + setup_bts(&the_bts, ts_no, 4); + the_bts.bts_data()->initial_mcs_dl = 9; + the_bts.bts_data()->egprs_enabled = 1; + + ul_tbf = puan_issue(&the_bts, ts_no, tlli, &fn, qta, + ms_class, egprs_ms_class); + + ms = ul_tbf->ms(); + fprintf(stderr, "Got '%s', TA=%d\n", ul_tbf->name(), ul_tbf->ta()); + fprintf(stderr, + "Got MS: TLLI = 0x%08x, TA = %d\n", ms->tlli(), ms->ta()); + + send_dl_data(&the_bts, tlli, imsi, test_data, sizeof(test_data)); + + printf("=== end %s ===\n", __func__); +} + static void test_tbf_egprs_two_phase_spb(void) { BTS the_bts; @@ -2071,6 +2243,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_puan_issue(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..aa8a087 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -5780,3 +5780,126 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654218 block=8 data=47 94 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +MS requests UL TBF on RACH, so we provide one: +MS requests single block allocation +RX: [PCU <- BTS] RACH qbit-ta=31 ra=0x73, Fn=2654167 (17,25,9), SBFn=2654270 +TX: Immediate Assignment Uplink (AGCH) + - TRX=0 (0) TS=7 TA=7 TSC=0 TFI=-1 USF=7 +Sending data request: trx=0 ts=0 sapi=2 arfcn=0 fn=0 block=0 data=2d 06 3f 10 0f 00 00 73 8b 29 07 00 c0 0c 5a 43 2b 2b 2b 2b 2b 2b 2b +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +MS requests UL TBF in packet resource request of single block, so we provide one: +MS supports EGPRS multislot class 1. +********** TBF starts here ********** +Allocating UL TBF: MS_CLASS=1/1 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 1 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 1 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign uplink TS=7 TFI=0 USF=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 00 +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=ASSIGN EGPRS) starting timer 3169. +Modifying MS object, UL TLLI: 0x00000000 -> 0xf1223344, not yet confirmed +Modifying MS object, TLLI = 0xf1223344, TA 0 -> 7 +Change control TS to 7 until assinment is complete. +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS)s start Packet Uplink Assignment (PACCH) ++++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++ +------------------------- TX : Packet Uplink Assignment ------------------------- +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS): Scheduling polling at FN 2654283 TS 7 +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS) changes state from ASSIGN to WAIT ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Scheduled UL Assignment polling on FN=2654283, TS=7 +Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) (TRX=0, TS=7) +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654270 block=8 data=4f 28 5e 24 46 68 90 f8 0a 39 00 00 88 00 08 2b 2b 2b 2b 2b 2b 2b 2b +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Packet Control Ack +TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) changes state from WAIT ASSIGN to FLOW +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=0 .. V(R)=0) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got CS-1 RLC data block: CV=15, BSN=0, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 0 storing in window (0..63) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 1 +- Taking block 0 out, raising V(Q) to 1 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=0 CV=15 +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1d 08 40 c1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=0, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=1) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=1, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 1 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 2 +- Taking block 1 out, raising V(Q) to 2 +- Assembling frames: (len=37) +-- Frame 1 starts at offset 0, length=37, is_complete=0 +- No gaps in received block, last block: BSN=1 CV=7 +Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) + - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 2, BOW, EOW +Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1d 20 40 c1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=0, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=2 .. V(R)=2) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=4, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 4 storing in window (2..65) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 5 +Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) + - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 5, BOW, EOW +Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got 'TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS)', TA=7 +Got MS: TLLI = 0xf1223344, TA = 7 +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=1/1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign downlink TS=7 TFI=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0xf1223344, TBF = TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 80 +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +Modifying MS object, TLLI: 0xf1223344 confirmed +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) [DOWNLINK] START +Modifying MS object, TLLI = 0xf1223344, IMSI '' -> '0011223344' +Send dowlink assignment on PACCH, because TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) exists +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) starting timer 0. +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) append diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..6b99857 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,5 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_puan_issue === +=== end test_tbf_puan_issue === -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 7 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Tue Aug 23 10:44:46 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 23 Aug 2016 10:44:46 +0000 Subject: openbsc[master]: chan_alloc.c: use ts_subslots() instead of subslots_per_pchan[] In-Reply-To: References: Message-ID: Patch Set 1: > i.e. in chan_alloc.c well, the other patch is also in chan_alloc.c, so I intended to say "i.e. in lchan_alloc() / _lc_find_trx()" -- To view, visit https://gerrit.osmocom.org/668 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Icbea7dbd78abf6144e5291f531a97f96507d8cbf Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 23 10:52:49 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 23 Aug 2016 10:52:49 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 22: I think the gerrit website caused a mix up here. I think for some reason I did not see all the files of the patch. Looking at the patch again I do see the test. Sorry for the noise... -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 22 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 23 10:54:37 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 23 Aug 2016 10:54:37 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 22: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 22 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 23 10:58:43 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 23 Aug 2016 10:58:43 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 22: Finally, we're through. Thank you for your patience and bearing with us. You may have noticed that we care a lot about coding style and log history; for the good reason of long term maintainability. As you get used to the osmocom code, writing patches should go a lot smoother than this one. Patches are always welcome, and keep up the good work! -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 22 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 23 11:05:58 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 23 Aug 2016 11:05:58 +0000 Subject: osmo-pcu[master]: EGPRS: PUAN encoding: add test case to show wrong urbb_len i... In-Reply-To: References: Message-ID: Patch Set 7: (3 comments) https://gerrit.osmocom.org/#/c/702/7//COMMIT_MSG Commit Message: Line 13: AddS test_tbf_puan_urbb_len to describe the following bug: It's nice that you accept my text, but indeed the test case has a different name. Either rename the test case or use the correct name here. ("AddS" looks like a typo) Line 17: "Related: OS#1793" ah, no quotes around it, then it's perfect. https://gerrit.osmocom.org/#/c/702/7/tests/tbf/TbfTest.cpp File tests/tbf/TbfTest.cpp: Line 1771: static void test_tbf_puan_issue(void) ...this name. As suggested in the commit log, IMHO "puan_issue" is too general. There may be more PUAN issues coming up in the future (or the past). -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 7 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 23 11:09:02 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 23 Aug 2016 11:09:02 +0000 Subject: osmo-pcu[master]: Update the function immediate assignment for EGPRS In-Reply-To: References: Message-ID: Patch Set 4: (1 comment) still waiting for a fix or comment on the #include moves. https://gerrit.osmocom.org/#/c/431/4/src/encoding.h File src/encoding.h: Line 43: bitvec * dest, uint8_t downlink, uint16_t ra, > the patch is about 11bit rach. I think it is rather obvious that this won't that's right, sorry. (Still could be nice to mention this in the log... but nevermind.) -- To view, visit https://gerrit.osmocom.org/431 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ie5e309156e5dbbb6add74a1b4d257c4ee2332e52 Gerrit-PatchSet: 4 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: bhargava_abhyankar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 23 11:38:56 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 23 Aug 2016 11:38:56 +0000 Subject: [PATCH] osmo-pcu[master]: EGPRS: PUAN encoding: add test case to show wrong urbb_len i... In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/702 to look at the new patch set (#8). EGPRS: PUAN encoding: add test case to show wrong urbb_len issue This patch adds a test case which expects a current bug with EGPRS PUAN encoding when VQ != VR. The test's expectation is corrected along with the bugfix in a subsequent commit Adds test_tbf_puan_urbb_len to describe the following bug: EGPRS PUAN encoding disregards the urbb_len, leading to identical PUAN messages regardless of the urbb_len. Related: OS#1793 Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 --- M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 3 files changed, 298 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/02/702/8 diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..f8e953f 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -618,6 +618,143 @@ &ulreq, tbf->poll_fn); } +static gprs_rlcmac_ul_tbf *puan_issue(BTS *the_bts, + uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, + uint8_t ms_class, uint8_t egprs_ms_class) +{ + GprsMs *ms; + uint32_t rach_fn = *fn - 51; + uint32_t sba_fn = *fn + 52; + uint8_t trx_no = 0; + int tfi = 0, i = 0; + gprs_rlcmac_ul_tbf *ul_tbf; + struct gprs_rlcmac_pdch *pdch; + gprs_rlcmac_bts *bts; + RlcMacUplink_t ulreq = {0}; + struct pcu_l1_meas meas; + struct gprs_rlc_ul_header_egprs_3 *egprs3 = NULL; + GprsCodingScheme cs; + + meas.set_rssi(31); + bts = the_bts->bts_data(); + + /* needed to set last_rts_fn in the PDCH object */ + request_dl_rlc_block(bts, trx_no, ts_no, fn); + + /* + * simulate RACH, this sends an Immediate + * Assignment Uplink on the AGCH + */ + the_bts->rcv_rach(0x73, rach_fn, qta); + + /* get next free TFI */ + tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1); + + /* fake a resource request */ + ulreq.u.MESSAGE_TYPE = MT_PACKET_RESOURCE_REQUEST; + ulreq.u.Packet_Resource_Request.PayloadType = GPRS_RLCMAC_CONTROL_BLOCK; + ulreq.u.Packet_Resource_Request.ID.UnionType = 1; /* != 0 */ + ulreq.u.Packet_Resource_Request.ID.u.TLLI = tlli; + ulreq.u.Packet_Resource_Request.Exist_MS_Radio_Access_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + Count_MS_RA_capability_value = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Exist_Multislot_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + Exist_GPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + GPRS_multislot_class = ms_class; + if (egprs_ms_class) { + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Multislot_capability.Exist_EGPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Multislot_capability.EGPRS_multislot_class = ms_class; + } + + send_ul_mac_block(the_bts, trx_no, ts_no, &ulreq, sba_fn); + + /* check the TBF */ + ul_tbf = the_bts->ul_tbf_by_tfi(tfi, trx_no, ts_no); + OSMO_ASSERT(ul_tbf); + OSMO_ASSERT(ul_tbf->ta() == qta / 4); + + /* send packet uplink assignment */ + *fn = sba_fn; + request_dl_rlc_block(ul_tbf, fn); + + /* send real acknowledgement */ + send_control_ack(ul_tbf); + + check_tbf(ul_tbf); + /* send fake data */ + uint8_t data_msg[42] = { + 0xf << 2, /* GPRS_RLCMAC_DATA_BLOCK << 6, CV = 15 */ + tfi << 1, + 1, /* BSN:7, E:1 */ + }; + + pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no]; + pdch->rcv_block(&data_msg[0], 23, *fn, &meas); + + ms = the_bts->ms_by_tlli(tlli); + OSMO_ASSERT(ms != NULL); + OSMO_ASSERT(ms->ta() == qta/4); + OSMO_ASSERT(ms->ul_tbf() == ul_tbf); + + /* + * TS 44.060, B.8.1 + * first seg received first, later second seg + */ + cs = GprsCodingScheme::MCS3; + egprs3 = (struct gprs_rlc_ul_header_egprs_3 *) data_msg; + egprs3->si = 0; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 1; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 0; + egprs3->pi = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + struct msgb *msg1 = ul_tbf->create_ul_ack(*fn, ts_no); + + egprs3->si = 0; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 4; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + struct msgb *msg2 = ul_tbf->create_ul_ack(*fn, ts_no); + + /* TODO: Need to modify the assert */ + OSMO_ASSERT(!memcmp(msg2->data, msg1->data, msg1->data_len)); + + return ul_tbf; +} + static gprs_rlcmac_ul_tbf *establish_ul_tbf_two_phase_spb(BTS *the_bts, uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, uint8_t ms_class, uint8_t egprs_ms_class) @@ -1631,6 +1768,41 @@ gprs_bssgp_destroy(); } +static void test_tbf_puan_urbb_len(void) +{ + BTS the_bts; + int ts_no = 7; + uint32_t fn = 2654218; + uint16_t qta = 31; + uint32_t tlli = 0xf1223344; + const char *imsi = "0011223344"; + uint8_t ms_class = 1; + uint8_t egprs_ms_class = 1; + gprs_rlcmac_ul_tbf *ul_tbf; + GprsMs *ms; + uint8_t test_data[256]; + + printf("=== start %s ===\n", __func__); + + memset(test_data, 1, sizeof(test_data)); + + setup_bts(&the_bts, ts_no, 4); + the_bts.bts_data()->initial_mcs_dl = 9; + the_bts.bts_data()->egprs_enabled = 1; + + ul_tbf = puan_issue(&the_bts, ts_no, tlli, &fn, qta, + ms_class, egprs_ms_class); + + ms = ul_tbf->ms(); + fprintf(stderr, "Got '%s', TA=%d\n", ul_tbf->name(), ul_tbf->ta()); + fprintf(stderr, + "Got MS: TLLI = 0x%08x, TA = %d\n", ms->tlli(), ms->ta()); + + send_dl_data(&the_bts, tlli, imsi, test_data, sizeof(test_data)); + + printf("=== end %s ===\n", __func__); +} + static void test_tbf_egprs_two_phase_spb(void) { BTS the_bts; @@ -2071,6 +2243,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_puan_urbb_len(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..aa8a087 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -5780,3 +5780,126 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654218 block=8 data=47 94 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +MS requests UL TBF on RACH, so we provide one: +MS requests single block allocation +RX: [PCU <- BTS] RACH qbit-ta=31 ra=0x73, Fn=2654167 (17,25,9), SBFn=2654270 +TX: Immediate Assignment Uplink (AGCH) + - TRX=0 (0) TS=7 TA=7 TSC=0 TFI=-1 USF=7 +Sending data request: trx=0 ts=0 sapi=2 arfcn=0 fn=0 block=0 data=2d 06 3f 10 0f 00 00 73 8b 29 07 00 c0 0c 5a 43 2b 2b 2b 2b 2b 2b 2b +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +MS requests UL TBF in packet resource request of single block, so we provide one: +MS supports EGPRS multislot class 1. +********** TBF starts here ********** +Allocating UL TBF: MS_CLASS=1/1 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 1 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 1 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign uplink TS=7 TFI=0 USF=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 00 +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=ASSIGN EGPRS) starting timer 3169. +Modifying MS object, UL TLLI: 0x00000000 -> 0xf1223344, not yet confirmed +Modifying MS object, TLLI = 0xf1223344, TA 0 -> 7 +Change control TS to 7 until assinment is complete. +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS)s start Packet Uplink Assignment (PACCH) ++++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++ +------------------------- TX : Packet Uplink Assignment ------------------------- +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS): Scheduling polling at FN 2654283 TS 7 +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS) changes state from ASSIGN to WAIT ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Scheduled UL Assignment polling on FN=2654283, TS=7 +Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) (TRX=0, TS=7) +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654270 block=8 data=4f 28 5e 24 46 68 90 f8 0a 39 00 00 88 00 08 2b 2b 2b 2b 2b 2b 2b 2b +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Packet Control Ack +TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) changes state from WAIT ASSIGN to FLOW +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=0 .. V(R)=0) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got CS-1 RLC data block: CV=15, BSN=0, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 0 storing in window (0..63) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 1 +- Taking block 0 out, raising V(Q) to 1 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=0 CV=15 +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1d 08 40 c1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=0, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=1) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=1, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 1 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 2 +- Taking block 1 out, raising V(Q) to 2 +- Assembling frames: (len=37) +-- Frame 1 starts at offset 0, length=37, is_complete=0 +- No gaps in received block, last block: BSN=1 CV=7 +Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) + - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 2, BOW, EOW +Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1d 20 40 c1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=0, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=2 .. V(R)=2) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=4, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 4 storing in window (2..65) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 5 +Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) + - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 5, BOW, EOW +Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got 'TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS)', TA=7 +Got MS: TLLI = 0xf1223344, TA = 7 +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=1/1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign downlink TS=7 TFI=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0xf1223344, TBF = TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 80 +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +Modifying MS object, TLLI: 0xf1223344 confirmed +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) [DOWNLINK] START +Modifying MS object, TLLI = 0xf1223344, IMSI '' -> '0011223344' +Send dowlink assignment on PACCH, because TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) exists +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) starting timer 0. +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) append diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..6b99857 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,5 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_puan_issue === +=== end test_tbf_puan_issue === -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 8 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Tue Aug 23 11:41:43 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 23 Aug 2016 11:41:43 +0000 Subject: osmo-pcu[master]: EGPRS: PUAN encoding: add test case to show wrong urbb_len i... In-Reply-To: References: Message-ID: Patch Set 8: (1 comment) https://gerrit.osmocom.org/#/c/702/8/tests/tbf/TbfTest.ok File tests/tbf/TbfTest.ok: Line 57: === start test_tbf_puan_issue === fix this -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 8 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 23 11:42:07 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 23 Aug 2016 11:42:07 +0000 Subject: [PATCH] osmo-pcu[master]: EGPRS: PUAN encoding: add test case to show wrong urbb_len i... In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/702 to look at the new patch set (#9). EGPRS: PUAN encoding: add test case to show wrong urbb_len issue This patch adds a test case which expects a current bug with EGPRS PUAN encoding when VQ != VR. The test's expectation is corrected along with the bugfix in a subsequent commit Adds test_tbf_puan_urbb_len to describe the following bug: EGPRS PUAN encoding disregards the urbb_len, leading to identical PUAN messages regardless of the urbb_len. Related: OS#1793 Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 --- M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 3 files changed, 298 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/02/702/9 diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..f8e953f 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -618,6 +618,143 @@ &ulreq, tbf->poll_fn); } +static gprs_rlcmac_ul_tbf *puan_issue(BTS *the_bts, + uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, + uint8_t ms_class, uint8_t egprs_ms_class) +{ + GprsMs *ms; + uint32_t rach_fn = *fn - 51; + uint32_t sba_fn = *fn + 52; + uint8_t trx_no = 0; + int tfi = 0, i = 0; + gprs_rlcmac_ul_tbf *ul_tbf; + struct gprs_rlcmac_pdch *pdch; + gprs_rlcmac_bts *bts; + RlcMacUplink_t ulreq = {0}; + struct pcu_l1_meas meas; + struct gprs_rlc_ul_header_egprs_3 *egprs3 = NULL; + GprsCodingScheme cs; + + meas.set_rssi(31); + bts = the_bts->bts_data(); + + /* needed to set last_rts_fn in the PDCH object */ + request_dl_rlc_block(bts, trx_no, ts_no, fn); + + /* + * simulate RACH, this sends an Immediate + * Assignment Uplink on the AGCH + */ + the_bts->rcv_rach(0x73, rach_fn, qta); + + /* get next free TFI */ + tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1); + + /* fake a resource request */ + ulreq.u.MESSAGE_TYPE = MT_PACKET_RESOURCE_REQUEST; + ulreq.u.Packet_Resource_Request.PayloadType = GPRS_RLCMAC_CONTROL_BLOCK; + ulreq.u.Packet_Resource_Request.ID.UnionType = 1; /* != 0 */ + ulreq.u.Packet_Resource_Request.ID.u.TLLI = tlli; + ulreq.u.Packet_Resource_Request.Exist_MS_Radio_Access_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + Count_MS_RA_capability_value = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Exist_Multislot_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + Exist_GPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + GPRS_multislot_class = ms_class; + if (egprs_ms_class) { + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Multislot_capability.Exist_EGPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Multislot_capability.EGPRS_multislot_class = ms_class; + } + + send_ul_mac_block(the_bts, trx_no, ts_no, &ulreq, sba_fn); + + /* check the TBF */ + ul_tbf = the_bts->ul_tbf_by_tfi(tfi, trx_no, ts_no); + OSMO_ASSERT(ul_tbf); + OSMO_ASSERT(ul_tbf->ta() == qta / 4); + + /* send packet uplink assignment */ + *fn = sba_fn; + request_dl_rlc_block(ul_tbf, fn); + + /* send real acknowledgement */ + send_control_ack(ul_tbf); + + check_tbf(ul_tbf); + /* send fake data */ + uint8_t data_msg[42] = { + 0xf << 2, /* GPRS_RLCMAC_DATA_BLOCK << 6, CV = 15 */ + tfi << 1, + 1, /* BSN:7, E:1 */ + }; + + pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no]; + pdch->rcv_block(&data_msg[0], 23, *fn, &meas); + + ms = the_bts->ms_by_tlli(tlli); + OSMO_ASSERT(ms != NULL); + OSMO_ASSERT(ms->ta() == qta/4); + OSMO_ASSERT(ms->ul_tbf() == ul_tbf); + + /* + * TS 44.060, B.8.1 + * first seg received first, later second seg + */ + cs = GprsCodingScheme::MCS3; + egprs3 = (struct gprs_rlc_ul_header_egprs_3 *) data_msg; + egprs3->si = 0; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 1; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 0; + egprs3->pi = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + struct msgb *msg1 = ul_tbf->create_ul_ack(*fn, ts_no); + + egprs3->si = 0; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 4; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + struct msgb *msg2 = ul_tbf->create_ul_ack(*fn, ts_no); + + /* TODO: Need to modify the assert */ + OSMO_ASSERT(!memcmp(msg2->data, msg1->data, msg1->data_len)); + + return ul_tbf; +} + static gprs_rlcmac_ul_tbf *establish_ul_tbf_two_phase_spb(BTS *the_bts, uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, uint8_t ms_class, uint8_t egprs_ms_class) @@ -1631,6 +1768,41 @@ gprs_bssgp_destroy(); } +static void test_tbf_puan_urbb_len(void) +{ + BTS the_bts; + int ts_no = 7; + uint32_t fn = 2654218; + uint16_t qta = 31; + uint32_t tlli = 0xf1223344; + const char *imsi = "0011223344"; + uint8_t ms_class = 1; + uint8_t egprs_ms_class = 1; + gprs_rlcmac_ul_tbf *ul_tbf; + GprsMs *ms; + uint8_t test_data[256]; + + printf("=== start %s ===\n", __func__); + + memset(test_data, 1, sizeof(test_data)); + + setup_bts(&the_bts, ts_no, 4); + the_bts.bts_data()->initial_mcs_dl = 9; + the_bts.bts_data()->egprs_enabled = 1; + + ul_tbf = puan_issue(&the_bts, ts_no, tlli, &fn, qta, + ms_class, egprs_ms_class); + + ms = ul_tbf->ms(); + fprintf(stderr, "Got '%s', TA=%d\n", ul_tbf->name(), ul_tbf->ta()); + fprintf(stderr, + "Got MS: TLLI = 0x%08x, TA = %d\n", ms->tlli(), ms->ta()); + + send_dl_data(&the_bts, tlli, imsi, test_data, sizeof(test_data)); + + printf("=== end %s ===\n", __func__); +} + static void test_tbf_egprs_two_phase_spb(void) { BTS the_bts; @@ -2071,6 +2243,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_puan_urbb_len(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..aa8a087 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -5780,3 +5780,126 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654218 block=8 data=47 94 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +MS requests UL TBF on RACH, so we provide one: +MS requests single block allocation +RX: [PCU <- BTS] RACH qbit-ta=31 ra=0x73, Fn=2654167 (17,25,9), SBFn=2654270 +TX: Immediate Assignment Uplink (AGCH) + - TRX=0 (0) TS=7 TA=7 TSC=0 TFI=-1 USF=7 +Sending data request: trx=0 ts=0 sapi=2 arfcn=0 fn=0 block=0 data=2d 06 3f 10 0f 00 00 73 8b 29 07 00 c0 0c 5a 43 2b 2b 2b 2b 2b 2b 2b +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +MS requests UL TBF in packet resource request of single block, so we provide one: +MS supports EGPRS multislot class 1. +********** TBF starts here ********** +Allocating UL TBF: MS_CLASS=1/1 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 1 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 1 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign uplink TS=7 TFI=0 USF=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 00 +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=ASSIGN EGPRS) starting timer 3169. +Modifying MS object, UL TLLI: 0x00000000 -> 0xf1223344, not yet confirmed +Modifying MS object, TLLI = 0xf1223344, TA 0 -> 7 +Change control TS to 7 until assinment is complete. +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS)s start Packet Uplink Assignment (PACCH) ++++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++ +------------------------- TX : Packet Uplink Assignment ------------------------- +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS): Scheduling polling at FN 2654283 TS 7 +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS) changes state from ASSIGN to WAIT ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Scheduled UL Assignment polling on FN=2654283, TS=7 +Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) (TRX=0, TS=7) +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654270 block=8 data=4f 28 5e 24 46 68 90 f8 0a 39 00 00 88 00 08 2b 2b 2b 2b 2b 2b 2b 2b +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Packet Control Ack +TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) changes state from WAIT ASSIGN to FLOW +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=0 .. V(R)=0) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got CS-1 RLC data block: CV=15, BSN=0, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 0 storing in window (0..63) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 1 +- Taking block 0 out, raising V(Q) to 1 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=0 CV=15 +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1d 08 40 c1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=0, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=1) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=1, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 1 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 2 +- Taking block 1 out, raising V(Q) to 2 +- Assembling frames: (len=37) +-- Frame 1 starts at offset 0, length=37, is_complete=0 +- No gaps in received block, last block: BSN=1 CV=7 +Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) + - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 2, BOW, EOW +Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1d 20 40 c1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=0, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=2 .. V(R)=2) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=4, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 4 storing in window (2..65) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 5 +Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) + - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 5, BOW, EOW +Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got 'TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS)', TA=7 +Got MS: TLLI = 0xf1223344, TA = 7 +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=1/1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign downlink TS=7 TFI=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0xf1223344, TBF = TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 80 +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +Modifying MS object, TLLI: 0xf1223344 confirmed +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) [DOWNLINK] START +Modifying MS object, TLLI = 0xf1223344, IMSI '' -> '0011223344' +Send dowlink assignment on PACCH, because TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) exists +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) starting timer 0. +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) append diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..16ac5da 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,5 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_puan_urbb_len === +=== end test_tbf_puan_urbb_len === -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 9 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Tue Aug 23 11:45:12 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 23 Aug 2016 11:45:12 +0000 Subject: osmo-pcu[master]: EGPRS: PUAN encoding: add test case to show wrong urbb_len i... In-Reply-To: References: Message-ID: Patch Set 9: (2 comments) https://gerrit.osmocom.org/#/c/702/7//COMMIT_MSG Commit Message: Line 13: Adds test_tbf_puan_urbb_len to describe the following bug: > It's nice that you accept my text, but indeed the test case has a different Done Line 17: Related: OS#1793 > ah, no quotes around it, then it's perfect. Done -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 9 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 23 11:46:42 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 23 Aug 2016 11:46:42 +0000 Subject: openbsc[master]: lchan: Release channel in case of late activation ack In-Reply-To: References: Message-ID: Patch Set 2: broken channel state can come from * chan act timeout * chan deact timeout * rx chan act nack (see rsl_lchan_mark_broken() in abis_rsl.c) -- To view, visit https://gerrit.osmocom.org/713 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I63dc0deaf15ba7c21e20b1e0c7b85f0437e183ed Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 23 11:46:56 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 23 Aug 2016 11:46:56 +0000 Subject: openbsc[master]: lchan: Release channel in case of late activation ack In-Reply-To: References: Message-ID: Patch Set 2: See also http://osmocom.org/issues/1798 -- To view, visit https://gerrit.osmocom.org/713 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I63dc0deaf15ba7c21e20b1e0c7b85f0437e183ed Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 23 11:48:08 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 23 Aug 2016 11:48:08 +0000 Subject: osmo-pcu[master]: EGPRS: PUAN encoding: add test case to show wrong urbb_len i... In-Reply-To: References: Message-ID: Patch Set 9: (1 comment) https://gerrit.osmocom.org/#/c/702/9/tests/tbf/TbfTest.cpp File tests/tbf/TbfTest.cpp: Line 621: static gprs_rlcmac_ul_tbf *puan_issue(BTS *the_bts, edit here -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 9 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 23 11:49:49 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 23 Aug 2016 11:49:49 +0000 Subject: [PATCH] osmo-pcu[master]: EGPRS: PUAN encoding: add test case to show wrong urbb_len i... In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/702 to look at the new patch set (#10). EGPRS: PUAN encoding: add test case to show wrong urbb_len issue This patch adds a test case which expects a current bug with EGPRS PUAN encoding when VQ != VR. The test's expectation is corrected along with the bugfix in a subsequent commit Adds test_tbf_puan_urbb_len to describe the following bug: EGPRS PUAN encoding disregards the urbb_len, leading to identical PUAN messages regardless of the urbb_len. Related: OS#1793 Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 --- M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 3 files changed, 298 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/02/702/10 diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..883ef26 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -618,6 +618,143 @@ &ulreq, tbf->poll_fn); } +static gprs_rlcmac_ul_tbf *puan_urbb_len_issue(BTS *the_bts, + uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, + uint8_t ms_class, uint8_t egprs_ms_class) +{ + GprsMs *ms; + uint32_t rach_fn = *fn - 51; + uint32_t sba_fn = *fn + 52; + uint8_t trx_no = 0; + int tfi = 0, i = 0; + gprs_rlcmac_ul_tbf *ul_tbf; + struct gprs_rlcmac_pdch *pdch; + gprs_rlcmac_bts *bts; + RlcMacUplink_t ulreq = {0}; + struct pcu_l1_meas meas; + struct gprs_rlc_ul_header_egprs_3 *egprs3 = NULL; + GprsCodingScheme cs; + + meas.set_rssi(31); + bts = the_bts->bts_data(); + + /* needed to set last_rts_fn in the PDCH object */ + request_dl_rlc_block(bts, trx_no, ts_no, fn); + + /* + * simulate RACH, this sends an Immediate + * Assignment Uplink on the AGCH + */ + the_bts->rcv_rach(0x73, rach_fn, qta); + + /* get next free TFI */ + tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1); + + /* fake a resource request */ + ulreq.u.MESSAGE_TYPE = MT_PACKET_RESOURCE_REQUEST; + ulreq.u.Packet_Resource_Request.PayloadType = GPRS_RLCMAC_CONTROL_BLOCK; + ulreq.u.Packet_Resource_Request.ID.UnionType = 1; /* != 0 */ + ulreq.u.Packet_Resource_Request.ID.u.TLLI = tlli; + ulreq.u.Packet_Resource_Request.Exist_MS_Radio_Access_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + Count_MS_RA_capability_value = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Exist_Multislot_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + Exist_GPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + GPRS_multislot_class = ms_class; + if (egprs_ms_class) { + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Multislot_capability.Exist_EGPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Multislot_capability.EGPRS_multislot_class = ms_class; + } + + send_ul_mac_block(the_bts, trx_no, ts_no, &ulreq, sba_fn); + + /* check the TBF */ + ul_tbf = the_bts->ul_tbf_by_tfi(tfi, trx_no, ts_no); + OSMO_ASSERT(ul_tbf); + OSMO_ASSERT(ul_tbf->ta() == qta / 4); + + /* send packet uplink assignment */ + *fn = sba_fn; + request_dl_rlc_block(ul_tbf, fn); + + /* send real acknowledgement */ + send_control_ack(ul_tbf); + + check_tbf(ul_tbf); + /* send fake data */ + uint8_t data_msg[42] = { + 0xf << 2, /* GPRS_RLCMAC_DATA_BLOCK << 6, CV = 15 */ + tfi << 1, + 1, /* BSN:7, E:1 */ + }; + + pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no]; + pdch->rcv_block(&data_msg[0], 23, *fn, &meas); + + ms = the_bts->ms_by_tlli(tlli); + OSMO_ASSERT(ms != NULL); + OSMO_ASSERT(ms->ta() == qta/4); + OSMO_ASSERT(ms->ul_tbf() == ul_tbf); + + /* + * TS 44.060, B.8.1 + * first seg received first, later second seg + */ + cs = GprsCodingScheme::MCS3; + egprs3 = (struct gprs_rlc_ul_header_egprs_3 *) data_msg; + egprs3->si = 0; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 1; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 0; + egprs3->pi = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + struct msgb *msg1 = ul_tbf->create_ul_ack(*fn, ts_no); + + egprs3->si = 0; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 4; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + struct msgb *msg2 = ul_tbf->create_ul_ack(*fn, ts_no); + + /* TODO: Need to modify the assert */ + OSMO_ASSERT(!memcmp(msg2->data, msg1->data, msg1->data_len)); + + return ul_tbf; +} + static gprs_rlcmac_ul_tbf *establish_ul_tbf_two_phase_spb(BTS *the_bts, uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, uint8_t ms_class, uint8_t egprs_ms_class) @@ -1631,6 +1768,41 @@ gprs_bssgp_destroy(); } +static void test_tbf_puan_urbb_len(void) +{ + BTS the_bts; + int ts_no = 7; + uint32_t fn = 2654218; + uint16_t qta = 31; + uint32_t tlli = 0xf1223344; + const char *imsi = "0011223344"; + uint8_t ms_class = 1; + uint8_t egprs_ms_class = 1; + gprs_rlcmac_ul_tbf *ul_tbf; + GprsMs *ms; + uint8_t test_data[256]; + + printf("=== start %s ===\n", __func__); + + memset(test_data, 1, sizeof(test_data)); + + setup_bts(&the_bts, ts_no, 4); + the_bts.bts_data()->initial_mcs_dl = 9; + the_bts.bts_data()->egprs_enabled = 1; + + ul_tbf = puan_urbb_len_issue(&the_bts, ts_no, tlli, &fn, qta, + ms_class, egprs_ms_class); + + ms = ul_tbf->ms(); + fprintf(stderr, "Got '%s', TA=%d\n", ul_tbf->name(), ul_tbf->ta()); + fprintf(stderr, + "Got MS: TLLI = 0x%08x, TA = %d\n", ms->tlli(), ms->ta()); + + send_dl_data(&the_bts, tlli, imsi, test_data, sizeof(test_data)); + + printf("=== end %s ===\n", __func__); +} + static void test_tbf_egprs_two_phase_spb(void) { BTS the_bts; @@ -2071,6 +2243,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_puan_urbb_len(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..aa8a087 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -5780,3 +5780,126 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654218 block=8 data=47 94 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +MS requests UL TBF on RACH, so we provide one: +MS requests single block allocation +RX: [PCU <- BTS] RACH qbit-ta=31 ra=0x73, Fn=2654167 (17,25,9), SBFn=2654270 +TX: Immediate Assignment Uplink (AGCH) + - TRX=0 (0) TS=7 TA=7 TSC=0 TFI=-1 USF=7 +Sending data request: trx=0 ts=0 sapi=2 arfcn=0 fn=0 block=0 data=2d 06 3f 10 0f 00 00 73 8b 29 07 00 c0 0c 5a 43 2b 2b 2b 2b 2b 2b 2b +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +MS requests UL TBF in packet resource request of single block, so we provide one: +MS supports EGPRS multislot class 1. +********** TBF starts here ********** +Allocating UL TBF: MS_CLASS=1/1 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 1 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 1 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign uplink TS=7 TFI=0 USF=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 00 +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=ASSIGN EGPRS) starting timer 3169. +Modifying MS object, UL TLLI: 0x00000000 -> 0xf1223344, not yet confirmed +Modifying MS object, TLLI = 0xf1223344, TA 0 -> 7 +Change control TS to 7 until assinment is complete. +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS)s start Packet Uplink Assignment (PACCH) ++++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++ +------------------------- TX : Packet Uplink Assignment ------------------------- +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS): Scheduling polling at FN 2654283 TS 7 +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS) changes state from ASSIGN to WAIT ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Scheduled UL Assignment polling on FN=2654283, TS=7 +Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) (TRX=0, TS=7) +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654270 block=8 data=4f 28 5e 24 46 68 90 f8 0a 39 00 00 88 00 08 2b 2b 2b 2b 2b 2b 2b 2b +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Packet Control Ack +TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) changes state from WAIT ASSIGN to FLOW +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=0 .. V(R)=0) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got CS-1 RLC data block: CV=15, BSN=0, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 0 storing in window (0..63) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 1 +- Taking block 0 out, raising V(Q) to 1 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=0 CV=15 +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1d 08 40 c1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=0, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=1) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=1, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 1 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 2 +- Taking block 1 out, raising V(Q) to 2 +- Assembling frames: (len=37) +-- Frame 1 starts at offset 0, length=37, is_complete=0 +- No gaps in received block, last block: BSN=1 CV=7 +Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) + - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 2, BOW, EOW +Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1d 20 40 c1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=0, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=2 .. V(R)=2) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=4, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 4 storing in window (2..65) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 5 +Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) + - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 5, BOW, EOW +Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got 'TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS)', TA=7 +Got MS: TLLI = 0xf1223344, TA = 7 +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=1/1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign downlink TS=7 TFI=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0xf1223344, TBF = TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 80 +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +Modifying MS object, TLLI: 0xf1223344 confirmed +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) [DOWNLINK] START +Modifying MS object, TLLI = 0xf1223344, IMSI '' -> '0011223344' +Send dowlink assignment on PACCH, because TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) exists +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) starting timer 0. +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) append diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..16ac5da 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,5 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_puan_urbb_len === +=== end test_tbf_puan_urbb_len === -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 10 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Tue Aug 23 11:52:40 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 23 Aug 2016 11:52:40 +0000 Subject: osmo-pcu[master]: EGPRS: PUAN encoding: add test case to show wrong urbb_len i... In-Reply-To: References: Message-ID: Patch Set 10: Hi Neels, I have modified the patch as per your suggestion. Please have a look. Thanks, Aravind Sirsikar -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 10 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 23 12:03:05 2016 From: gerrit-no-reply at lists.osmocom.org (bhargava_abhyankar) Date: Tue, 23 Aug 2016 12:03:05 +0000 Subject: osmo-pcu[master]: Update the function immediate assignment for EGPRS In-Reply-To: References: Message-ID: Patch Set 4: (1 comment) https://gerrit.osmocom.org/#/c/431/4/src/encoding.cpp File src/encoding.cpp: Line 22: #include > is it really necessary to move this #include? It is necessary to move #include. Otherwise compilation will break. -- To view, visit https://gerrit.osmocom.org/431 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ie5e309156e5dbbb6add74a1b4d257c4ee2332e52 Gerrit-PatchSet: 4 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: bhargava_abhyankar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 23 12:05:58 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 23 Aug 2016 12:05:58 +0000 Subject: osmo-pcu[master]: EGPRS: PUAN encoding: add test case to show wrong urbb_len i... In-Reply-To: References: Message-ID: Patch Set 10: (1 comment) one (hopefully last) thing... https://gerrit.osmocom.org/#/c/702/10/tests/tbf/TbfTest.cpp File tests/tbf/TbfTest.cpp: Line 753: OSMO_ASSERT(!memcmp(msg2->data, msg1->data, msg1->data_len)); This tests for identity (when fixed non-identity) of two messages. We should rather test what's actually *in* the messages. Like: above for msg1: OSMO_ASSERT(!strcmp(osmo_hexdump(msg1->data, msg1->data_len), "01 02 03 04 [...] ff ")); here for msg2: OSMO_ASSERT(!strcmp(osmo_hexdump(msg2->data, msg2->data_len), "01 02 03 04 [...] ff ")); Then in the bugfix, you can adjust the actual bytes expected. (You could then also decide to drop msg1 entirely, but in fact it can't hurt to keep it now that it's there.) -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 10 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 23 12:11:20 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 23 Aug 2016 12:11:20 +0000 Subject: osmo-pcu[master]: EGPRS: PUAN encoding: add test case to show wrong urbb_len i... In-Reply-To: References: Message-ID: Patch Set 10: (1 comment) https://gerrit.osmocom.org/#/c/702/10/tests/tbf/TbfTest.cpp File tests/tbf/TbfTest.cpp: Line 753: OSMO_ASSERT(!memcmp(msg2->data, msg1->data, msg1->data_len)); > This tests for identity (when fixed non-identity) of two messages. Hi Neels, As the generated PUAN is not under our control it is not advisable to compare with pattern like "01 02 03 04....". May be in future with some addition of new field in the PUAN message it can generate some other hex stream. which may cause issue with this test case. Please suggest. Thanks, Aravind Sirsikar -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 10 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 23 12:41:32 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 23 Aug 2016 12:41:32 +0000 Subject: osmo-pcu[master]: Fix EGPRS PUAN encoding: use correct urbb_len In-Reply-To: References: Message-ID: Patch Set 2: (1 comment) https://gerrit.osmocom.org/#/c/703/2//COMMIT_MSG Commit Message: Line 14: "Related: OS#1793". fix this -- To view, visit https://gerrit.osmocom.org/703 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Iba7b1995028bd81749ffb080616b2ad5f2540d57 Gerrit-PatchSet: 2 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 23 12:42:12 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 23 Aug 2016 12:42:12 +0000 Subject: [PATCH] osmo-pcu[master]: Fix EGPRS PUAN encoding: use correct urbb_len In-Reply-To: References: Message-ID: Hello Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/703 to look at the new patch set (#3). Fix EGPRS PUAN encoding: use correct urbb_len Earlier there was an incorrect encoding of PUAN when VQ is not equal VR case for EGPRS UL RLC window. The PCU was encoding the same PUAN message always irrespective of radio condition. This was a bottle neck for performance testing. Which has been fixed in this patch. Related: OS#1793 unit test assertion in the previous commit is fixed in this patch. Change-Id: Iba7b1995028bd81749ffb080616b2ad5f2540d57 --- M src/encoding.cpp M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err 3 files changed, 5 insertions(+), 5 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/03/703/3 diff --git a/src/encoding.cpp b/src/encoding.cpp index 63049ac..41e0d10 100644 --- a/src/encoding.cpp +++ b/src/encoding.cpp @@ -575,7 +575,8 @@ eow = false; urbb_len = rest_bits - 9; /* TODO: use compression (see above) */ - } + } else + urbb_len = num_blocks; if (urbb_len + crbb_len == rest_bits) len = -1; diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 5a73a43..c423058 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -749,8 +749,7 @@ struct msgb *msg2 = ul_tbf->create_ul_ack(*fn, ts_no); - /* TODO: Need to modify the assert */ - OSMO_ASSERT(!memcmp(msg2->data, msg1->data, msg1->data_len)); + OSMO_ASSERT(memcmp(msg2->data, msg1->data, msg1->data_len)); return ul_tbf; } diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index aa8a087..fa0927c 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -5875,8 +5875,8 @@ TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - Raising V(R) to 5 Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) - - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 5, BOW, EOW -Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b + - EGPRS URBB, len = 2, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 5, BOW, EOW +Uplink Ack/Nack bit count 100, max 184, message = 40 24 01 3f 3e 24 46 68 90 88 b0 06 8b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b Got 'TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS)', TA=7 Got MS: TLLI = 0xf1223344, TA = 7 ********** TBF starts here ********** -- To view, visit https://gerrit.osmocom.org/703 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Iba7b1995028bd81749ffb080616b2ad5f2540d57 Gerrit-PatchSet: 3 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Tue Aug 23 14:19:50 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 23 Aug 2016 14:19:50 +0000 Subject: [PATCH] osmo-bts[master]: Fix ip.access style dyn PDCH, broken in 37af36e85eca54659508... Message-ID: Review at https://gerrit.osmocom.org/751 Fix ip.access style dyn PDCH, broken in 37af36e85eca546595081246aec010fa7f6fd0be Commit "sysmo,lc15: ts_connect_as(): log error also for pchan_as == TCH/F_PDCH" introduced a check for TCH/F_PDCH intended only for TCH/F_TCH/H_PDCH. It looked correct, but TCH/F_PDCH startup was designed differently: For TCH/F_PDCH, the idea was to look it up in pchan_to_logChComb[] and obtain the TCH/F channel combination, so that TCH/F_PDCH first initialize as TCH/F. So pchan was in fact intended to be passed as TCH/F_PDCH. For Osmocom TCH/F_TCH/H_PDCH, we've in the meantime added a ts_opstart() function that makes this decision explicitly. So, instead of reverting the erratic commit, add TCH/F_PDCH to ts_opstart(), for both sysmo and lc15. In ts_opstart(), move to a switch statement to resolve the actual pchan to use for ts_connect_as(). Drop TCH/F_PDCH and TCH/F_TCH/H_PDCH from pchan_to_logChComb[] and comment. Change-Id: I376b92a06f4cbe943c1c913dea7487fac53a7d08 --- M src/osmo-bts-litecell15/oml.c M src/osmo-bts-sysmo/oml.c 2 files changed, 38 insertions(+), 16 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/51/751/1 diff --git a/src/osmo-bts-litecell15/oml.c b/src/osmo-bts-litecell15/oml.c index 5ce510a..a175af4 100644 --- a/src/osmo-bts-litecell15/oml.c +++ b/src/osmo-bts-litecell15/oml.c @@ -89,11 +89,12 @@ [GSM_PCHAN_SDCCH8_SACCH8C] = GsmL1_LogChComb_VII, [GSM_PCHAN_SDCCH8_SACCH8C_CBCH] = GsmL1_LogChComb_VII, [GSM_PCHAN_PDCH] = GsmL1_LogChComb_XIII, - [GSM_PCHAN_TCH_F_PDCH] = GsmL1_LogChComb_I, /*< first init - like TCH/F, until PDCH ACT */ - [GSM_PCHAN_TCH_F_TCH_H_PDCH] = GsmL1_LogChComb_0, /*< first unused, - until first RSL CHAN ACT */ [GSM_PCHAN_UNKNOWN] = GsmL1_LogChComb_0, + /* + * GSM_PCHAN_TCH_F_PDCH and GSM_PCHAN_TCH_F_TCH_H_PDCH should not be + * part of this, only "real" pchan values will be looked up here. + * See the callers of ts_connect_as(). + */ }; static int trx_rf_lock(struct gsm_bts_trx *trx, int locked, l1if_compl_cb *cb); @@ -507,12 +508,22 @@ static int ts_opstart(struct gsm_bts_trx_ts *ts) { - if (ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) { - /* First connect as NONE, until first RSL CHAN ACT. */ + enum gsm_phys_chan_config pchan = ts->pchan; + switch (pchan) { + case GSM_PCHAN_TCH_F_TCH_H_PDCH: ts->dyn.pchan_is = ts->dyn.pchan_want = GSM_PCHAN_NONE; - return ts_connect_as(ts, GSM_PCHAN_NONE, opstart_compl_cb, NULL); + /* First connect as NONE, until first RSL CHAN ACT. */ + pchan = GSM_PCHAN_NONE; + break; + case GSM_PCHAN_TCH_F_PDCH: + /* First connect as TCH/F, expecting PDCH ACT. */ + pchan = GSM_PCHAN_TCH_F; + break; + default: + /* simply use ts->pchan */ + break; } - return ts_connect_as(ts, ts->pchan, opstart_compl_cb, NULL); + return ts_connect_as(ts, pchan, opstart_compl_cb, NULL); } GsmL1_Sapi_t lchan_to_GsmL1_Sapi_t(const struct gsm_lchan *lchan) diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c index 6f0629d..dea1c5e 100644 --- a/src/osmo-bts-sysmo/oml.c +++ b/src/osmo-bts-sysmo/oml.c @@ -86,11 +86,12 @@ [GSM_PCHAN_SDCCH8_SACCH8C] = GsmL1_LogChComb_VII, [GSM_PCHAN_SDCCH8_SACCH8C_CBCH] = GsmL1_LogChComb_VII, [GSM_PCHAN_PDCH] = GsmL1_LogChComb_XIII, - [GSM_PCHAN_TCH_F_PDCH] = GsmL1_LogChComb_I, /*< first init - like TCH/F, until PDCH ACT */ - [GSM_PCHAN_TCH_F_TCH_H_PDCH] = GsmL1_LogChComb_0, /*< first unused, - until first RSL CHAN ACT */ [GSM_PCHAN_UNKNOWN] = GsmL1_LogChComb_0, + /* + * GSM_PCHAN_TCH_F_PDCH and GSM_PCHAN_TCH_F_TCH_H_PDCH should not be + * part of this, only "real" pchan values will be looked up here. + * See the callers of ts_connect_as(). + */ }; static int trx_rf_lock(struct gsm_bts_trx *trx, int locked, l1if_compl_cb *cb); @@ -515,12 +516,22 @@ static int ts_opstart(struct gsm_bts_trx_ts *ts) { - if (ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) { - /* First connect as NONE, until first RSL CHAN ACT. */ + enum gsm_phys_chan_config pchan = ts->pchan; + switch (pchan) { + case GSM_PCHAN_TCH_F_TCH_H_PDCH: ts->dyn.pchan_is = ts->dyn.pchan_want = GSM_PCHAN_NONE; - return ts_connect_as(ts, GSM_PCHAN_NONE, opstart_compl_cb, NULL); + /* First connect as NONE, until first RSL CHAN ACT. */ + pchan = GSM_PCHAN_NONE; + break; + case GSM_PCHAN_TCH_F_PDCH: + /* First connect as TCH/F, expecting PDCH ACT. */ + pchan = GSM_PCHAN_TCH_F; + break; + default: + /* simply use ts->pchan */ + break; } - return ts_connect_as(ts, ts->pchan, opstart_compl_cb, NULL); + return ts_connect_as(ts, pchan, opstart_compl_cb, NULL); } GsmL1_Sapi_t lchan_to_GsmL1_Sapi_t(const struct gsm_lchan *lchan) -- To view, visit https://gerrit.osmocom.org/751 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I376b92a06f4cbe943c1c913dea7487fac53a7d08 Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Tue Aug 23 14:25:39 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 23 Aug 2016 14:25:39 +0000 Subject: osmo-bts[master]: Fix ip.access style dyn PDCH, broken in 37af36e85eca54659508... In-Reply-To: References: Message-ID: Patch Set 1: Verified+1 Verified on litecell15. TCH/F_PDCH are completely broken without this. -- To view, visit https://gerrit.osmocom.org/751 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I376b92a06f4cbe943c1c913dea7487fac53a7d08 Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 23 15:23:49 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 23 Aug 2016 15:23:49 +0000 Subject: osmo-pcu[master]: Revert "tbf: Add state WAIT_ASSIGN" In-Reply-To: References: Message-ID: Patch Set 3: Code-Review+1 Today I have verified (with lc15) that basically only the current default case breaks: Here are the permutations of having the "WAIT_ASSIGN state" patch applied or not with having the 'pcu' / 'two-phase-access' config item in the osmo-pcu.cfg or not: with WAIT_ASSIGN revert WAIT_ASSIGN no 'two-phase-access' GPRS broken GPRS works with 'two-phase-access' GPRS works GPRS works So if we revert WAIT_ASSIGN, all configurations work (for me). I haven't tried EGPRS though (not familiar with it yet). -- To view, visit https://gerrit.osmocom.org/218 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I1532f8e93194368cdc1e3846f82afa6d68cd5fbd Gerrit-PatchSet: 3 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 23 15:32:12 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 23 Aug 2016 15:32:12 +0000 Subject: [PATCH] osmo-pcu[master]: vty: use OSMO_VTY_PORT_PCU instead of number Message-ID: Review at https://gerrit.osmocom.org/752 vty: use OSMO_VTY_PORT_PCU instead of number Include vty/ports.h and use the proper constant. Change-Id: I9c5b7683f76994c539da5551f40df32379dc685e --- M src/pcu_main.cpp 1 file changed, 2 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/52/752/1 diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2d86cda..4e7a832 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -32,6 +32,7 @@ #include "pcu_vty.h" #include #include +#include #include #include #include @@ -244,7 +245,7 @@ fprintf(stderr, "No config file: '%s' Using default config.\n", config_file); - rc = telnet_init(tall_pcu_ctx, NULL, 4240); + rc = telnet_init(tall_pcu_ctx, NULL, OSMO_VTY_PORT_PCU); if (rc < 0) { fprintf(stderr, "Error initializing telnet\n"); exit(1); -- To view, visit https://gerrit.osmocom.org/752 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I9c5b7683f76994c539da5551f40df32379dc685e Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Tue Aug 23 15:32:13 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 23 Aug 2016 15:32:13 +0000 Subject: [PATCH] osmo-pcu[master]: heed VTY 'line vty'/'bind' command Message-ID: Review at https://gerrit.osmocom.org/753 heed VTY 'line vty'/'bind' command Like most other osmo-* programs, bind the telnet VTY to the address specified by the 'line vty'/'bind' command. This is added by vty_init(), so until now the PCU offered this config but ignored it. Also log the VTY bind and port. Tweak the error message in case telnet init fails (mention 'VTY' in it). Change-Id: I4cca05a212ec0d493b906014dc3a83e687ebbb1d --- M src/pcu_main.cpp 1 file changed, 5 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/53/753/1 diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 4e7a832..dcbd95f 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -245,9 +245,12 @@ fprintf(stderr, "No config file: '%s' Using default config.\n", config_file); - rc = telnet_init(tall_pcu_ctx, NULL, OSMO_VTY_PORT_PCU); + LOGP(DLGLOBAL, LOGL_NOTICE, "VTY at %s %d\n", vty_get_bind_addr(), + OSMO_VTY_PORT_PCU); + rc = telnet_init_dynif(tall_pcu_ctx, NULL, vty_get_bind_addr(), + OSMO_VTY_PORT_PCU); if (rc < 0) { - fprintf(stderr, "Error initializing telnet\n"); + fprintf(stderr, "Error initializing telnet VTY\n"); exit(1); } -- To view, visit https://gerrit.osmocom.org/753 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I4cca05a212ec0d493b906014dc3a83e687ebbb1d Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Tue Aug 23 15:39:42 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 23 Aug 2016 15:39:42 +0000 Subject: [PATCH] osmo-bts[master]: heed VTY 'line vty'/'bind' command Message-ID: Review at https://gerrit.osmocom.org/754 heed VTY 'line vty'/'bind' command Like most other osmo-* programs, bind the telnet VTY to the address specified by the 'line vty'/'bind' command. This is added by vty_init(), so until now the BTS offered this config but ignored it. Also log the VTY bind and port. Tweak the error message in case telnet init fails (mention 'VTY' in it). Change-Id: Ic4ab32aee08d8a779adeb9943892de0c828c7b3d --- M src/common/main.c 1 file changed, 5 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/54/754/1 diff --git a/src/common/main.c b/src/common/main.c index 5e0f1a1..7fc4da7 100644 --- a/src/common/main.c +++ b/src/common/main.c @@ -303,9 +303,12 @@ bts_controlif_setup(bts); - rc = telnet_init(tall_bts_ctx, NULL, g_vty_port_num); + LOGP(DLGLOBAL, LOGL_NOTICE, "VTY at %s %d\n", vty_get_bind_addr(), + g_vty_port_num); + rc = telnet_init_dynif(tall_bts_ctx, NULL, vty_get_bind_addr(), + g_vty_port_num); if (rc < 0) { - fprintf(stderr, "Error initializing telnet\n"); + fprintf(stderr, "Error initializing telnet VTY\n"); exit(1); } -- To view, visit https://gerrit.osmocom.org/754 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ic4ab32aee08d8a779adeb9943892de0c828c7b3d Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Tue Aug 23 15:41:44 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 23 Aug 2016 15:41:44 +0000 Subject: osmo-bts[master]: heed VTY 'line vty'/'bind' command In-Reply-To: References: Message-ID: Patch Set 1: note, this is in osmo-bts, an identical commit log message was also submitted in osmo-pcu. -- To view, visit https://gerrit.osmocom.org/754 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ic4ab32aee08d8a779adeb9943892de0c828c7b3d Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 23 15:53:56 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 23 Aug 2016 15:53:56 +0000 Subject: osmo-pcu[master]: EGPRS: PUAN encoding: add test case to show wrong urbb_len i... In-Reply-To: References: Message-ID: Patch Set 10: (1 comment) https://gerrit.osmocom.org/#/c/702/10/tests/tbf/TbfTest.cpp File tests/tbf/TbfTest.cpp: Line 753: OSMO_ASSERT(!memcmp(msg2->data, msg1->data, msg1->data_len)); > Hi Neels, I must admit I'm not familiar enough to know for certain, but all I see is the data that is tested here being generated in encoding.c in the osmo-pcu source tree ("bitvec_write_field..."). Please confirm that some external entity generates the PUAN (an external library?), and point me at the code that calls it, please. -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 10 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 23 15:58:15 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 23 Aug 2016 15:58:15 +0000 Subject: osmo-pcu[master]: EGPRS: PUAN encoding: add test case to show wrong urbb_len i... In-Reply-To: References: Message-ID: Patch Set 10: > May be in future with some addition of new field in the PUAN message > it can generate some other hex stream. which may cause issue with > this test case. That is the idea of a test case: if you change the code, your test suite should notice that. Adjusting test expectations is expected and desired with code moving forward. If the data is indeed generated by e.g. a kernel module or an external library, it doesn't make sense to test specific bytes here. But AFAICT this data is generated in osmo-pcu code, so let's check it. -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 10 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 23 16:11:50 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 23 Aug 2016 16:11:50 +0000 Subject: osmo-pcu[master]: Update the function immediate assignment for EGPRS In-Reply-To: References: Message-ID: Patch Set 4: (2 comments) https://gerrit.osmocom.org/#/c/431/4/src/encoding.cpp File src/encoding.cpp: Line 22: #include > It is necessary to move #include. Otherwise compilation will break. No, that's not how this works. If you need a definition in encoding.h, you add the corresponding #include to encoding.h, you absolutely do not start tweaking the order of including headers in the .cpp files. Undo these moves and add the needed header to encoding.h. https://gerrit.osmocom.org/#/c/431/4/src/encoding.h File src/encoding.h: Line 26: Add this here to be able to use enum ph_burst_type: extern "C" { #include } (I have verified that this works) -- To view, visit https://gerrit.osmocom.org/431 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ie5e309156e5dbbb6add74a1b4d257c4ee2332e52 Gerrit-PatchSet: 4 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: bhargava_abhyankar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 23 16:39:06 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 23 Aug 2016 16:39:06 +0000 Subject: openbsc[master]: Adding LLC-XID related modifications in LLC In-Reply-To: References: Message-ID: Patch Set 13: (1 comment) https://gerrit.osmocom.org/#/c/652/13/openbsc/src/gprs/gprs_llc.c File openbsc/src/gprs/gprs_llc.c: Line 152: xid_field->data); printing the data as %s directly is not a good idea, and you fix this in a subsequent commit using osmo_hexdump(). If we're being perfectionist rather do it here already... ...or make sure to submit both commits together. -- To view, visit https://gerrit.osmocom.org/652 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I65b9d625e72d3d61c99abdc7041773701d694d52 Gerrit-PatchSet: 13 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 23 16:48:03 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 23 Aug 2016 16:48:03 +0000 Subject: openbsc[master]: Adding compression control and final fixups In-Reply-To: References: Message-ID: Patch Set 23: (17 comments) quite a large patch, can't get through all of it ATM... https://gerrit.osmocom.org/#/c/642/23/openbsc/include/openbsc/gprs_llc.h File openbsc/include/openbsc/gprs_llc.h: Line 179: /* In this two list_heads we will store the "these two" https://gerrit.osmocom.org/#/c/642/23/openbsc/include/openbsc/gprs_sndcp_comp.h File openbsc/include/openbsc/gprs_sndcp_comp.h: Line 33: unsigned int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ we usually put comments above the members, not behind it. See for example: openbsc/include/openbsc/bsc_api.h openbsc/include/openbsc/gprs_llc.h openbsc/src/gprs/gprs_sndcp.h And actually, I would have added this header file in openbsc/include/openbsc/ and am surprised to find a gprs_sndcp.h in src/gprs/. Having headers in openbsc/include/openbsc allows including this header with '#include ', always. I guess we should also move gprs_sndcp.h to include/openbsc? Line 64: llist_head *comp_entities, line breaks in the middle of parameters again... https://gerrit.osmocom.org/#/c/642/23/openbsc/include/openbsc/gprs_sndcp_pcomp.h File openbsc/include/openbsc/gprs_sndcp_pcomp.h: Line 30: const struct gprs_sndcp_comp_field *comp_field); if you have tabs and spaces mixed like here, line up after the '(' column. (I think we also have three-tabs and not lining up somewhere) https://gerrit.osmocom.org/#/c/642/23/openbsc/src/gprs/gprs_llc.c File openbsc/src/gprs/gprs_llc.c: Line 150: xid_field_request_l3 = xid_field_request; Could also use llist_for_each_entry_reverse() with a 'break;' in the if {} to pick the last one. https://gerrit.osmocom.org/#/c/642/23/openbsc/src/gprs/gprs_sndcp.c File openbsc/src/gprs/gprs_sndcp.c: Line 875: /* Comile bytestream */ "Compile" Line 895: sizeof rather remove one tab indent and keep sizeof() in one line Line 913: /* Hanle header compression entites */ "Handle" Line 917: /* Note: This functions also transforms the comp_field into its english nitpicking... "This function"? "These functions"? "transform ... to" (not into). End the sentence before "The processed" Line 937: "Rejecting RFC1144 header conpression...\n"); "compression" Line 947: "Rejecting RFC2507 header conpression...\n"); "compression" Line 956: "Rejecting ROHC header conpression...\n"); "compression" Line 970: /* Note: This functions also transforms the comp_field into its s.a. -- do you really want the same comment twice? Line 984: "Rejecting V42BIS data conpression...\n"); "compression" Line 992: LOGP(DSNDCP, LOGL_DEBUG, "Rejecting V44 data conpression...\n"); "compression" Line 1133: xid_field_confirmation-> weird line break Line 1139: "Modified version of received SNDCP-XID received from the phone:\n"); only one "received"? -- To view, visit https://gerrit.osmocom.org/642 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 Gerrit-PatchSet: 23 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Wed Aug 24 10:25:18 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 24 Aug 2016 10:25:18 +0000 Subject: openbsc[master]: Adding SNDCP-XID encoder / decoder and unit test In-Reply-To: References: Message-ID: Patch Set 12: (2 comments) https://gerrit.osmocom.org/#/c/641/12/openbsc/include/openbsc/gprs_sndcp_xid.h File openbsc/include/openbsc/gprs_sndcp_xid.h: Line 36: * 3GPP TS 44.065, 6.6.1.1 Format of the data compression whitespace: two lines use tab, one uses spaces Line 57: be used unused pointers must be set to NULL! */ "...may be used. Unused pointers must be set to NULL." -- To view, visit https://gerrit.osmocom.org/641 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e Gerrit-PatchSet: 12 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Wed Aug 24 11:17:34 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 24 Aug 2016 11:17:34 +0000 Subject: openbsc[master]: Adding compression control and final fixups In-Reply-To: References: Message-ID: Patch Set 23: (25 comments) https://gerrit.osmocom.org/#/c/642/23/openbsc/src/gprs/gprs_sndcp_comp.c File openbsc/src/gprs/gprs_sndcp_comp.c: Line 40: const struct weird line breaks Line 90: OSMO_ASSERT(comp_entity->nsapi_len > 0) missing ';' and weird indent below Line 99: if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { I was going to suggest the below, but I notice that data compression might be added some day... will it? if (comp_entity->compclass != SNDCP_XID_PROTOCOL_COMPRESSION) { [...] return NULL; } if (gprs_.... Line 122: } else { from above theck this is never reached, but again a placeholder for data compression... so ok Line 151: OSMO_ASSERT(comp_entities); quite a long comment on an obvious issue. BTW, if you were to comp_free the same entities twice by accident, this assert wouldn't hit: though talloc_free() freed the mem, the comp_entities pointer would still be != NULL. So usually, asserts like this don't really have any benefit unless you *expect* calling code paths to handle NULL pointers to indicate unset data or something. Line 163: comp_entity->entity); hmm, not implemented, dead code, but making believe that it does something useful? Line 177: OSMO_ASSERT(comp_entities); (one of those asserts) Line 181: comp_entity_to_delete = comp_entity; 'break;' when found? Line 195: comp_entity_to_delete->entity); (make-believe dead code again) Line 206: struct llist_head weird line breaks Line 215: OSMO_ASSERT(comp_field); (asserts... and more below) Line 232: struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head line breaks... and more below Line 283: * all sort of compression and is assigned fix. So we what do you mean by "is assigned fix"? Line 291: return i + 1; whoa, why '+ 1'? I believe this will cause a lot of confusion. In C, we should have 0-indexing, only translating to 1-indexing for humans if really necessary, e.g. in the VTY. Now looking at the only caller gprs_sndcp_pcomp_expand() that feeds the returned value to gprs_sndcp_pcomp_rfc1144_expand(). I notice that this returns an int while gprs_sndcp_pcomp_rfc1144_expand() takes a uint8_t argument. Also in gprs_sndcp_pcomp_rfc1144_expand() the returned value seems to be expected to be exactly either 1 or 2. Could you please explain a bit further before we decide what to do? Or a different name like 'pcomp_type' could resolve the confusion; maybe with an enum defining those indexes explicitly? Line 318: return comp_entity->comp[comp_index - 1]; now -1 again :/ ;) https://gerrit.osmocom.org/#/c/642/23/openbsc/src/gprs/gprs_sndcp_pcomp.c File openbsc/src/gprs/gprs_sndcp_pcomp.c: Line 98: uint8_t *comp_ptr; /* Required by slhc_compress() */ kind of superfluous comment :) Line 141: break; this is where the 1-indexed pcomp_index value is used. What if pcomp_index < 1 or > 2? Would be good to add error messages (or asserts if it's never to be expected) in a 'default:' case. Line 150: /* Just in case the phone tags uncompressed tcp-datas ('data' is already the plural of 'datum') Line 179: OSMO_ASSERT(comp_entities); (asserts) Line 183: memcpy(data_o, data_i, len); since this happens twice, this could be a case for 'goto skip_decompression;' and having the memcpy only once below 'return rc;' at the bottom. Line 202: OSMO_ASSERT(comp_entity->algo == RFC_1144); should these two asserts rather be error messages? assertions terminate the program and disrupt service... Line 231: OSMO_ASSERT(comp_entities); (asserts) Line 249: OSMO_ASSERT(comp_entity->algo == RFC_1144); error messages? https://gerrit.osmocom.org/#/c/642/23/openbsc/src/gprs/sgsn_libgtp.c File openbsc/src/gprs/sgsn_libgtp.c: Line 330: return rc_pdp; 'return 0;' or just 'return sndcp_sn_xid_req(...)' above https://gerrit.osmocom.org/#/c/642/23/openbsc/src/gprs/sgsn_vty.c File openbsc/src/gprs/sgsn_vty.c: Line 274: g_cfg->pcomp_rfc1144.s01+1, VTY_NEWLINE); weird indenting -- To view, visit https://gerrit.osmocom.org/642 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 Gerrit-PatchSet: 23 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Wed Aug 24 11:21:18 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 24 Aug 2016 11:21:18 +0000 Subject: openbsc[master]: Adding SNDCP-XID encoder / decoder and unit test In-Reply-To: References: Message-ID: Patch Set 12: (1 comment) https://gerrit.osmocom.org/#/c/641/12/openbsc/src/gprs/gprs_sndcp_xid.c File openbsc/src/gprs/gprs_sndcp_xid.c: Line 117: OSMO_ASSERT(params->s01 <= 255); Seeing this, it would make sense to make s01 a uint8_t and handle the range entirely in the VTY (as we already do in the "final fixups" commit). -- To view, visit https://gerrit.osmocom.org/641 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e Gerrit-PatchSet: 12 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Wed Aug 24 16:54:30 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 24 Aug 2016 16:54:30 +0000 Subject: [PATCH] osmo-bts[master]: log: sysmo, lc15: tweak log about sapi_cmds queue Message-ID: Review at https://gerrit.osmocom.org/755 log: sysmo,lc15: tweak log about sapi_cmds queue The osmo-bts log used to say this a lot: DL1C <0006> oml.c:758 (bts=0,trx=0,ts=0,ss=1) End of queue encountered. Now empty? 1 - Move this to DEBUG level instead of NOTICE. - Tweak wording and logic so it says one of: [...] End of SAPI cmd queue encountered. Queue is now empty. [...] End of SAPI cmd queue encountered. More pending. Change-Id: I5a46c90d016cee9b50f32db2af568765d3cb74cc --- M src/osmo-bts-litecell15/oml.c M src/osmo-bts-sysmo/oml.c 2 files changed, 12 insertions(+), 6 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/55/755/1 diff --git a/src/osmo-bts-litecell15/oml.c b/src/osmo-bts-litecell15/oml.c index 5ce510a..c6787dd 100644 --- a/src/osmo-bts-litecell15/oml.c +++ b/src/osmo-bts-litecell15/oml.c @@ -744,9 +744,12 @@ talloc_free(cmd); if (end || llist_empty(&lchan->sapi_cmds)) { - LOGP(DL1C, LOGL_NOTICE, - "%s End of queue encountered. Now empty? %d\n", - gsm_lchan_name(lchan), llist_empty(&lchan->sapi_cmds)); + LOGP(DL1C, LOGL_DEBUG, + "%s End of SAPI cmd queue encountered.%s\n", + gsm_lchan_name(lchan), + llist_empty(&lchan->sapi_cmds) + ? " Queue is now empty." + : " More pending."); return; } diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c index 6f0629d..c4519ec 100644 --- a/src/osmo-bts-sysmo/oml.c +++ b/src/osmo-bts-sysmo/oml.c @@ -753,9 +753,12 @@ talloc_free(cmd); if (end || llist_empty(&lchan->sapi_cmds)) { - LOGP(DL1C, LOGL_NOTICE, - "%s End of queue encountered. Now empty? %d\n", - gsm_lchan_name(lchan), llist_empty(&lchan->sapi_cmds)); + LOGP(DL1C, LOGL_DEBUG, + "%s End of SAPI cmd queue encountered.%s\n", + gsm_lchan_name(lchan), + llist_empty(&lchan->sapi_cmds) + ? " Queue is now empty." + : " More pending."); return; } -- To view, visit https://gerrit.osmocom.org/755 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I5a46c90d016cee9b50f32db2af568765d3cb74cc Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Wed Aug 24 16:56:33 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 24 Aug 2016 16:56:33 +0000 Subject: [PATCH] openbsc[master]: dyn TS: move check whether to switch to PDCH to separate fun... Message-ID: Review at https://gerrit.osmocom.org/756 dyn TS: move check whether to switch to PDCH to separate function Prepares for an upcoming commit using the same check in error_timeout_cb(). Change-Id: I8abfa964631040f798212cc3e360f67f9e09b7c5 --- M openbsc/src/libbsc/abis_rsl.c 1 file changed, 33 insertions(+), 17 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/56/756/1 diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index b84a0b5..aac3558 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -723,6 +723,38 @@ return abis_rsl_sendmsg(msg); } +static bool dyn_ts_should_switch_to_pdch(struct gsm_bts_trx_ts *ts) +{ + int ss; + + if (ts->pchan != GSM_PCHAN_TCH_F_TCH_H_PDCH) + return false; + + if (ts->trx->bts->gprs.mode == BTS_GPRS_NONE) + return false; + + /* Already in PDCH mode? */ + if (ts->dyn.pchan_is == GSM_PCHAN_PDCH) + return false; + + /* See if all lchans are released. */ + for (ss = 0; ss < ts_subslots(ts); ss++) { + struct gsm_lchan *lc = &ts->lchan[ss]; + if (lc->state != LCHAN_S_NONE) { + DEBUGP(DRSL, "%s lchan %u still in use\n", + gsm_ts_and_pchan_name(ts), + lc->nr); + /* An lchan is still used. */ + return false; + } + } + + /* All channels are released, go to PDCH mode. */ + DEBUGP(DRSL, "%s back to PDCH\n", + gsm_ts_and_pchan_name(ts)); + return true; +} + static void error_timeout_cb(void *data) { struct gsm_lchan *lchan = data; @@ -824,7 +856,6 @@ static int rsl_rx_rf_chan_rel_ack(struct gsm_lchan *lchan) { - int ss; struct gsm_bts_trx_ts *ts = lchan->ts; DEBUGP(DRSL, "%s RF CHANNEL RELEASE ACK\n", gsm_lchan_name(lchan)); @@ -879,23 +910,8 @@ return dyn_ts_switchover_continue(lchan); /* (b) */ - if (ts->dyn.pchan_is != GSM_PCHAN_PDCH - && ts->trx->bts->gprs.mode != BTS_GPRS_NONE) { - for (ss = 0; ss < ts_subslots(ts); ss++) { - struct gsm_lchan *lc = &ts->lchan[ss]; - if (lc->state != LCHAN_S_NONE) { - DEBUGP(DRSL, "%s lchan %u still in use\n", - gsm_ts_and_pchan_name(ts), - lc->nr); - /* An lchan is still used. */ - return 0; - } - } - /* All channels are released, go to PDCH mode. */ - DEBUGP(DRSL, "%s back to PDCH\n", - gsm_ts_and_pchan_name(ts)); + if (dyn_ts_should_switch_to_pdch(ts)) return dyn_ts_switchover_start(lchan, GSM_PCHAN_PDCH); - } } /* -- To view, visit https://gerrit.osmocom.org/756 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I8abfa964631040f798212cc3e360f67f9e09b7c5 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Wed Aug 24 16:56:33 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 24 Aug 2016 16:56:33 +0000 Subject: [PATCH] openbsc[master]: dyn TS: fix error recovery: switch to PDCH after lchan error... Message-ID: Review at https://gerrit.osmocom.org/757 dyn TS: fix error recovery: switch to PDCH after lchan error state Tested by hacking a CHAN ACT ACK delay of a couple of seconds into osmo-bts' rsl.c for the first TCH_H lchan: [[[ diff --git a/src/common/rsl.c b/src/common/rsl.c index 3c97af9..4bfd27a 100644 --- a/src/common/rsl.c +++ b/src/common/rsl.c @@ -559,6 +559,22 @@ static int rsl_tx_chan_act_ack(struct gsm_lchan *lchan) return abis_bts_rsl_sendmsg(msg); } +struct osmo_timer_list xxx_timer; + +static void xxx_timer_cb(void *data) +{ + rsl_tx_chan_act_ack(data); +} + +static int rsl_tx_chan_act_ack_later(struct gsm_lchan *lchan) +{ + xxx_timer.cb = xxx_timer_cb; + xxx_timer.data = lchan; + osmo_timer_schedule(&xxx_timer, 10, 0); + return 0; +} + + /* 8.4.7 sending HANDOver DETection */ int rsl_tx_hando_det(struct gsm_lchan *lchan, uint8_t *ho_delay) { @@ -614,6 +630,18 @@ int rsl_tx_chan_act_acknack(struct gsm_lchan *lchan, uint8_t cause) if (cause) return rsl_tx_chan_act_nack(lchan, cause); + + static int xxx = 0; + + DEBUGP(DRSL, "%s XXXXXXXXXXXXXXXXXXXXX %d %s\n", + gsm_lchan_name(lchan), xxx, gsm_lchant_name(lchan->type)); + + if (lchan->type == GSM_LCHAN_TCH_H) { + if (!xxx) { + xxx ++; + return rsl_tx_chan_act_ack_later(lchan); + } + } return rsl_tx_chan_act_ack(lchan); } ]]] Change-Id: Ie82dec9c9fefc476fdf5b5afdad2246b9d6fe304 --- M openbsc/src/libbsc/abis_rsl.c 1 file changed, 3 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/57/757/1 diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index aac3558..58e1806 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -772,6 +772,9 @@ if (lchan->ts->pchan == GSM_PCHAN_TCH_F_PDCH && lchan->ts->trx->bts->gprs.mode != BTS_GPRS_NONE) rsl_ipacc_pdch_activate(lchan->ts, 1); + + if (dyn_ts_should_switch_to_pdch(lchan->ts)) + dyn_ts_switchover_start(lchan, GSM_PCHAN_PDCH); } static int rsl_rx_rf_chan_rel_ack(struct gsm_lchan *lchan); -- To view, visit https://gerrit.osmocom.org/757 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ie82dec9c9fefc476fdf5b5afdad2246b9d6fe304 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Wed Aug 24 16:56:33 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 24 Aug 2016 16:56:33 +0000 Subject: [PATCH] openbsc[master]: dyn TS: clearly use lchan[0], fixing minor confusion Message-ID: Review at https://gerrit.osmocom.org/758 dyn TS: clearly use lchan[0], fixing minor confusion The dyn_ts_switchover_*() functions made the impression that they act on a specific lchan of a timeslot. The assumption that we would remember to use e.g. lchan[1] across a PDCH deactivation is brain damaged to begin with; and factually we always use lchan[0] anyway (the only case for using lchan[1] would be when switching to TCH/H, but the channel allocator will always return lchan[0] for that). Instead of the brain damaged lchan args, use a ts arg across all dyn_ts_switchover_*() functions, with one exception: The dyn_ts_switchover_complete() actually receives an RSL activation ack message on a specific lchan and needs to evaluate its lchan type. This will always be lchan[0] as it is now, but we should stick with the lchan the message was sent for. For PDCH, a check to use lchan[0] already existed, when composing the ACT message in rsl_chan_activate_lchan_as_pdch(). Replace with an assertion. Adjust all callers to pass ts instead of lchan. In dyn_ts_switchover_start(), there was a dead code check that jumps to switchover_complete() in case the pchan already matches. This never hits, because we only call dyn_ts_switchover_start() when pchans mismatch. So avoid guessing at passing lchan[0] to dyn_ts_switchover_complete() by not calling it at all but logging an error instead. In rsl_chan_activate_lchan(), we remember some values before going into switchover from PDCH. Explicitly store them in lchan[0], because after a PDCH release we have always and will activate no other than lchan[0]. In dyn_ts_switchover_continue(), move the check for any existing lchan->rqd_ref further above, and more correctly check all lchans that were so far valid on the TS, instead of just one. This partly prepares for a subsequent commit to fix the act_timer use for dyn TS: with the old lchan arg, we might schedule an activation timer on lchan[1] but receive an ack on lchan[0] (for PDCH), leading to an act_timer expiry. Change-Id: I3f5d48a9bdaa49a42a1908d4a03744638c59796a --- M openbsc/include/openbsc/abis_rsl.h M openbsc/src/libbsc/abis_rsl.c M openbsc/src/libbsc/bsc_dyn_ts.c 3 files changed, 56 insertions(+), 42 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/58/758/1 diff --git a/openbsc/include/openbsc/abis_rsl.h b/openbsc/include/openbsc/abis_rsl.h index 8313f48..758c555 100644 --- a/openbsc/include/openbsc/abis_rsl.h +++ b/openbsc/include/openbsc/abis_rsl.h @@ -108,7 +108,7 @@ int rsl_direct_rf_release(struct gsm_lchan *lchan); void dyn_ts_init(struct gsm_bts_trx_ts *ts); -int dyn_ts_switchover_start(struct gsm_lchan *lchan, +int dyn_ts_switchover_start(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config to_pchan); #endif /* RSL_MT_H */ diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index 58e1806..841aa7b 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -55,8 +55,8 @@ static int rsl_send_imm_assignment(struct gsm_lchan *lchan); static void error_timeout_cb(void *data); -static int dyn_ts_switchover_continue(struct gsm_lchan *lchan); -static int dyn_ts_switchover_failed(struct gsm_lchan *lchan, int rc); +static int dyn_ts_switchover_continue(struct gsm_bts_trx_ts *ts); +static int dyn_ts_switchover_failed(struct gsm_bts_trx_ts *ts, int rc); static void dyn_ts_switchover_complete(struct gsm_lchan *lchan); static void send_lchan_signal(int sig_no, struct gsm_lchan *lchan, @@ -460,9 +460,9 @@ struct abis_rsl_dchan_hdr *dh; /* This might be called after release of the second lchan of a TCH/H, - * but PDCH activation should always happen on the first lchan. So - * switch to lchan->nr == 0. */ - lchan = lchan->ts->lchan; + * but PDCH activation must always happen on the first lchan. Make sure + * the calling code passes the correct lchan. */ + OSMO_ASSERT(lchan == lchan->ts->lchan); rsl_lchan_set_state(lchan, LCHAN_S_ACT_REQ); @@ -521,16 +521,21 @@ enum gsm_phys_chan_config pchan_want; pchan_want = pchan_for_lchant(lchan->type); if (lchan->ts->dyn.pchan_is != pchan_want) { - lchan->dyn.act_type = act_type, - lchan->dyn.ho_ref = ho_ref; - lchan->dyn.rqd_ref = lchan->rqd_ref; - lchan->dyn.rqd_ta = lchan->rqd_ta; + /* + * Make sure to record on lchan[0] so that we'll find + * it after the PDCH release. + */ + struct gsm_lchan *lchan0 = lchan->ts->lchan; + lchan0->dyn.act_type = act_type, + lchan0->dyn.ho_ref = ho_ref; + lchan0->dyn.rqd_ref = lchan->rqd_ref; + lchan0->dyn.rqd_ta = lchan->rqd_ta; lchan->rqd_ref = NULL; lchan->rqd_ta = 0; DEBUGP(DRSL, "%s saved rqd_ref=%p ta=%u\n", - gsm_lchan_name(lchan), lchan->rqd_ref, - lchan->rqd_ta); - return dyn_ts_switchover_start(lchan, pchan_want); + gsm_lchan_name(lchan0), lchan0->rqd_ref, + lchan0->rqd_ta); + return dyn_ts_switchover_start(lchan->ts, pchan_want); } } @@ -774,7 +779,7 @@ rsl_ipacc_pdch_activate(lchan->ts, 1); if (dyn_ts_should_switch_to_pdch(lchan->ts)) - dyn_ts_switchover_start(lchan, GSM_PCHAN_PDCH); + dyn_ts_switchover_start(lchan->ts, GSM_PCHAN_PDCH); } static int rsl_rx_rf_chan_rel_ack(struct gsm_lchan *lchan); @@ -910,11 +915,11 @@ /* (a) */ if (ts->dyn.pchan_is != ts->dyn.pchan_want) - return dyn_ts_switchover_continue(lchan); + return dyn_ts_switchover_continue(ts); /* (b) */ if (dyn_ts_should_switch_to_pdch(ts)) - return dyn_ts_switchover_start(lchan, GSM_PCHAN_PDCH); + return dyn_ts_switchover_start(ts, GSM_PCHAN_PDCH); } /* @@ -2338,11 +2343,10 @@ return rc; } -int dyn_ts_switchover_start(struct gsm_lchan *lchan, +int dyn_ts_switchover_start(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config to_pchan) { int ss; - struct gsm_bts_trx_ts *ts = lchan->ts; int rc = -EIO; OSMO_ASSERT(ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH); @@ -2360,15 +2364,14 @@ if (ts->dyn.pchan_is == to_pchan) { LOGP(DRSL, LOGL_INFO, - "%s %s Already is in %s mode, skipping switchover.\n", + "%s %s Already is in %s mode, cannot switchover.\n", gsm_ts_name(ts), gsm_pchan_name(ts->pchan), gsm_pchan_name(to_pchan)); - dyn_ts_switchover_complete(lchan); - return 0; + return -EINVAL; } /* Paranoia: let's make sure all is indeed released. */ - for (ss = 0; ss < ts_subslots(lchan->ts); ss++) { + for (ss = 0; ss < ts_subslots(ts); ss++) { struct gsm_lchan *lc = &ts->lchan[ss]; if (lc->state != LCHAN_S_NONE) { LOGP(DRSL, LOGL_ERROR, @@ -2386,16 +2389,16 @@ /* * To switch from PDCH, we need to initiate the release from the BSC * side. dyn_ts_switchover_continue() will be called from - * rsl_rx_rf_chan_rel_ack(). + * rsl_rx_rf_chan_rel_ack(). PDCH is always on lchan[0]. */ if (ts->dyn.pchan_is == GSM_PCHAN_PDCH) { - rsl_lchan_set_state(lchan, LCHAN_S_REL_REQ); - rc = rsl_rf_chan_release(lchan, 0, SACCH_NONE); + rsl_lchan_set_state(ts->lchan, LCHAN_S_REL_REQ); + rc = rsl_rf_chan_release(ts->lchan, 0, SACCH_NONE); if (rc) { LOGP(DRSL, LOGL_ERROR, "%s RSL RF Chan Release failed\n", gsm_ts_and_pchan_name(ts)); - return dyn_ts_switchover_failed(lchan, rc); + return dyn_ts_switchover_failed(ts, rc); } return 0; } @@ -2405,15 +2408,16 @@ * rsl_rx_rf_chan_rel_ack(), i.e. release is complete. Go ahead and * activate as new type. This will always be PDCH. */ - return dyn_ts_switchover_continue(lchan); + return dyn_ts_switchover_continue(ts); } -static int dyn_ts_switchover_continue(struct gsm_lchan *lchan) +static int dyn_ts_switchover_continue(struct gsm_bts_trx_ts *ts) { int rc; uint8_t act_type; uint8_t ho_ref; - struct gsm_bts_trx_ts *ts = lchan->ts; + int ss; + struct gsm_lchan *lchan; OSMO_ASSERT(ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH); DEBUGP(DRSL, "%s switchover: release complete," @@ -2427,6 +2431,25 @@ gsm_ts_and_pchan_name(ts)); return 0; } + + for (ss = 0; ss < ts_subslots(ts); ss++) { + lchan = &ts->lchan[ss]; + if (lchan->rqd_ref) { + LOGP(DRSL, LOGL_ERROR, + "%s During dyn TS switchover, expecting no" + " Request Reference to be pending. Discarding!\n", + gsm_lchan_name(lchan)); + talloc_free(lchan->rqd_ref); + lchan->rqd_ref = NULL; + } + } + + /* + * When switching pchan modes, all lchans are unused. So always + * activate whatever wants to be activated on the first lchan. (We + * wouldn't remember to use lchan[1] across e.g. a PDCH deact anyway) + */ + lchan = ts->lchan; /* * For TCH/x, the lchan->type has been set in lchan_alloc(), but it may @@ -2459,14 +2482,6 @@ : lchan->dyn.ho_ref; /* Fetch the rqd_ref back from before switchover started. */ - if (lchan->rqd_ref) { - LOGP(DRSL, LOGL_ERROR, - "%s During dyn TS switchover, expecting no" - " Request Reference to be pending. Discarding!\n", - gsm_lchan_name(lchan)); - talloc_free(lchan->rqd_ref); - lchan->rqd_ref = NULL; - } lchan->rqd_ref = lchan->dyn.rqd_ref; lchan->rqd_ta = lchan->dyn.rqd_ta; lchan->dyn.rqd_ref = NULL; @@ -2477,14 +2492,13 @@ LOGP(DRSL, LOGL_ERROR, "%s RSL Chan Activate failed\n", gsm_ts_and_pchan_name(ts)); - return dyn_ts_switchover_failed(lchan, rc); + return dyn_ts_switchover_failed(ts, rc); } return 0; } -static int dyn_ts_switchover_failed(struct gsm_lchan *lchan, int rc) +static int dyn_ts_switchover_failed(struct gsm_bts_trx_ts *ts, int rc) { - struct gsm_bts_trx_ts *ts = lchan->ts; ts->dyn.pchan_want = ts->dyn.pchan_is; LOGP(DRSL, LOGL_ERROR, "%s Error %d during dynamic channel switchover." " Going back to previous pchan.\n", gsm_ts_and_pchan_name(ts), @@ -2510,7 +2524,7 @@ LOGP(DRSL, LOGL_ERROR, "%s Requested transition does not match lchan type %s\n", gsm_ts_and_pchan_name(ts), - gsm_lchant_name(ts->lchan[0].type)); + gsm_lchant_name(lchan->type)); pchan_was = ts->dyn.pchan_is; ts->dyn.pchan_is = ts->dyn.pchan_want = pchan_act; diff --git a/openbsc/src/libbsc/bsc_dyn_ts.c b/openbsc/src/libbsc/bsc_dyn_ts.c index 456500a..e5422fc 100644 --- a/openbsc/src/libbsc/bsc_dyn_ts.c +++ b/openbsc/src/libbsc/bsc_dyn_ts.c @@ -52,7 +52,7 @@ return; } - dyn_ts_switchover_start(ts->lchan, GSM_PCHAN_PDCH); + dyn_ts_switchover_start(ts, GSM_PCHAN_PDCH); } void dyn_ts_init(struct gsm_bts_trx_ts *ts) -- To view, visit https://gerrit.osmocom.org/758 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I3f5d48a9bdaa49a42a1908d4a03744638c59796a Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Wed Aug 24 16:56:33 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 24 Aug 2016 16:56:33 +0000 Subject: [PATCH] openbsc[master]: dyn TS: fix: properly run an lchan activation timeout Message-ID: Review at https://gerrit.osmocom.org/759 dyn TS: fix: properly run an lchan activation timeout Actually schedule an activation timer for the activation part of a dyn TS switchover. It needs to be restarted because the channel release procedure in the first part of a switchover actually removes the activation timer. Change-Id: Ibf50d13ba10298464a8b07e34716763161438990 --- M openbsc/src/libbsc/abis_rsl.c 1 file changed, 7 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/59/759/1 diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index 841aa7b..1e9cecd 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -2487,6 +2487,13 @@ lchan->dyn.rqd_ref = NULL; lchan->dyn.rqd_ta = 0; + /* During switchover, we have received a release ack, which means that + * the act_timer has been stopped. Start the timer again so we mark + * this channel broken if the activation ack comes too late. */ + lchan->act_timer.cb = lchan_act_tmr_cb; + lchan->act_timer.data = lchan; + osmo_timer_schedule(&lchan->act_timer, 4, 0); + rc = rsl_chan_activate_lchan(lchan, act_type, ho_ref); if (rc) { LOGP(DRSL, LOGL_ERROR, -- To view, visit https://gerrit.osmocom.org/759 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ibf50d13ba10298464a8b07e34716763161438990 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Wed Aug 24 16:56:34 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 24 Aug 2016 16:56:34 +0000 Subject: [PATCH] openbsc[master]: dyn TS: fix OS#1798: on late RF CHAN REL ACK, activate PDCH Message-ID: Review at https://gerrit.osmocom.org/760 dyn TS: fix OS#1798: on late RF CHAN REL ACK, activate PDCH Tested by hacking a REL ACK delay of a couple of seconds into osmo-bts' rsl.c for the first TCH_H lchan: [[[ diff --git a/include/osmo-bts/rsl.h b/include/osmo-bts/rsl.h index 093e9cb..b35c3bb 100644 --- a/include/osmo-bts/rsl.h +++ b/include/osmo-bts/rsl.h @@ -22,6 +22,7 @@ int rsl_tx_est_ind(struct gsm_lchan *lchan, uint8_t link_id, uint8_t *data, int int rsl_tx_chan_act_acknack(struct gsm_lchan *lchan, uint8_t cause); int rsl_tx_conn_fail(struct gsm_lchan *lchan, uint8_t cause); int rsl_tx_rf_rel_ack(struct gsm_lchan *lchan); +int rsl_tx_rf_rel_ack_later(struct gsm_lchan *lchan); int rsl_tx_hando_det(struct gsm_lchan *lchan, uint8_t *ho_delay); /* call-back for LAPDm code, called when it wants to send msgs UP */ diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 3802e25..1f92b0d 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -491,7 +491,16 @@ static int l1sap_info_rel_cnf(struct gsm_bts_trx *trx, lchan = get_lchan_by_chan_nr(trx, info_act_cnf->chan_nr); - rsl_tx_rf_rel_ack(lchan); + static int yyy = 0; + + DEBUGP(DRSL, "%s YYYYYYYYYYYYYYYYYYYYY %d %s\n", + gsm_lchan_name(lchan), yyy, gsm_lchant_name(lchan->type)); + + if (lchan->type == GSM_LCHAN_TCH_H && !yyy) { + yyy ++; + rsl_tx_rf_rel_ack_later(lchan); + } else + rsl_tx_rf_rel_ack(lchan); /* During PDCH DEACT, this marks the deactivation of the PDTCH as * requested by the PCU. Next up, we disconnect the TS completely and diff --git a/src/common/rsl.c b/src/common/rsl.c index 3c97af9..7926f21 100644 --- a/src/common/rsl.c +++ b/src/common/rsl.c @@ -534,6 +534,22 @@ int rsl_tx_rf_rel_ack(struct gsm_lchan *lchan) return abis_bts_rsl_sendmsg(msg); } +struct osmo_timer_list yyy_timer; + +static void yyy_timer_cb(void *data) +{ + rsl_tx_rf_rel_ack(data); +} + +int rsl_tx_rf_rel_ack_later(struct gsm_lchan *lchan) +{ + yyy_timer.cb = yyy_timer_cb; + yyy_timer.data = lchan; + osmo_timer_schedule(&yyy_timer, 10, 0); + return 0; +} + + /* 8.4.2 sending CHANnel ACTIVation ACKnowledge */ static int rsl_tx_chan_act_ack(struct gsm_lchan *lchan) { ]]] Change-Id: I87e07e1d54882f8f3d667fa300c6e3679f5c920d Fixes: OS#1798 --- M openbsc/src/libbsc/abis_rsl.c 1 file changed, 2 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/60/760/1 diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index 1e9cecd..591c842 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -887,6 +887,8 @@ do_free ? "Releasing it" : "Keeping it broken"); if (do_free) do_lchan_free(lchan); + if (dyn_ts_should_switch_to_pdch(lchan->ts)) + dyn_ts_switchover_start(lchan->ts, GSM_PCHAN_PDCH); return 0; } -- To view, visit https://gerrit.osmocom.org/760 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I87e07e1d54882f8f3d667fa300c6e3679f5c920d Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Wed Aug 24 16:56:34 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 24 Aug 2016 16:56:34 +0000 Subject: [PATCH] openbsc[master]: dyn TS: debug log 'switchover complete' only when there was ... Message-ID: Review at https://gerrit.osmocom.org/761 dyn TS: debug log 'switchover complete' only when there was a switchover Change-Id: I7ddcb41edce1cd7b22fe91e33bdcaedb21856222 --- M openbsc/src/libbsc/abis_rsl.c 1 file changed, 3 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/61/761/1 diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index 591c842..324e0d6 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -2538,8 +2538,9 @@ pchan_was = ts->dyn.pchan_is; ts->dyn.pchan_is = ts->dyn.pchan_want = pchan_act; - LOGP(DRSL, LOGL_INFO, "%s switchover from %s complete.\n", - gsm_ts_and_pchan_name(ts), gsm_pchan_name(pchan_was)); + if (pchan_was != ts->dyn.pchan_is) + LOGP(DRSL, LOGL_INFO, "%s switchover from %s complete.\n", + gsm_ts_and_pchan_name(ts), gsm_pchan_name(pchan_was)); } /* Entry-point where L2 RSL from BTS enters */ -- To view, visit https://gerrit.osmocom.org/761 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I7ddcb41edce1cd7b22fe91e33bdcaedb21856222 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Wed Aug 24 16:56:34 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 24 Aug 2016 16:56:34 +0000 Subject: [PATCH] openbsc[master]: dyn TS: debug log: if still in use, also log lchan type and ... Message-ID: Review at https://gerrit.osmocom.org/762 dyn TS: debug log: if still in use, also log lchan type and state Change-Id: Ifbf31cde24b2d1022b7a472966c17959c96e6dda --- M openbsc/src/libbsc/abis_rsl.c 1 file changed, 5 insertions(+), 3 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/62/762/1 diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index 324e0d6..c8aa124 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -746,9 +746,11 @@ for (ss = 0; ss < ts_subslots(ts); ss++) { struct gsm_lchan *lc = &ts->lchan[ss]; if (lc->state != LCHAN_S_NONE) { - DEBUGP(DRSL, "%s lchan %u still in use\n", - gsm_ts_and_pchan_name(ts), - lc->nr); + DEBUGP(DRSL, "%s lchan %u still in use" + " (type=%s,state=%s)\n", + gsm_ts_and_pchan_name(ts), lc->nr, + gsm_lchant_name(lc->type), + gsm_lchans_name(lc->state)); /* An lchan is still used. */ return false; } -- To view, visit https://gerrit.osmocom.org/762 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ifbf31cde24b2d1022b7a472966c17959c96e6dda Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Wed Aug 24 16:56:34 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 24 Aug 2016 16:56:34 +0000 Subject: [PATCH] openbsc[master]: log: improve for rsl_lchan_mark_broken() Message-ID: Review at https://gerrit.osmocom.org/763 log: improve for rsl_lchan_mark_broken() In rsl_lchan_mark_broken(), call rsl_lchan_set_state() so the state transition gets logged in the debug log. Remove logging for the broken channel at the callers, instead log the error actually in rsl_lchan_mark_broken() itself, with the reason message passed by the caller anyway. (Removes code dup and ensures it's always logged.) Change-Id: I54ae9bbd3f193bae7b1bda1fef3e33e62b353bf5 --- M openbsc/src/libbsc/abis_rsl.c 1 file changed, 3 insertions(+), 9 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/63/763/1 diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index c8aa124..3d694c3 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -179,10 +179,6 @@ { struct gsm_lchan *lchan = data; - LOGP(DRSL, LOGL_ERROR, - "%s Timeout during activation. Marked as broken.\n", - gsm_lchan_name(lchan)); - rsl_lchan_mark_broken(lchan, "activation timeout"); lchan_free(lchan); } @@ -190,10 +186,6 @@ static void lchan_deact_tmr_cb(void *data) { struct gsm_lchan *lchan = data; - - LOGP(DRSL, LOGL_ERROR, - "%s Timeout during deactivation! Marked as broken.\n", - gsm_lchan_name(lchan)); rsl_lchan_mark_broken(lchan, "de-activation timeout"); lchan_free(lchan); @@ -1121,7 +1113,9 @@ int rsl_lchan_mark_broken(struct gsm_lchan *lchan, const char *reason) { - lchan->state = LCHAN_S_BROKEN; + LOGP(DRSL, LOGL_ERROR, "%s %s lchan broken: %s\n", + gsm_lchan_name(lchan), gsm_lchant_name(lchan->type), reason); + rsl_lchan_set_state(lchan, LCHAN_S_BROKEN); lchan->broken_reason = reason; return 0; } -- To view, visit https://gerrit.osmocom.org/763 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I54ae9bbd3f193bae7b1bda1fef3e33e62b353bf5 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Wed Aug 24 16:56:34 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 24 Aug 2016 16:56:34 +0000 Subject: [PATCH] openbsc[master]: log: rsl notice: tiny tweak for readability Message-ID: Review at https://gerrit.osmocom.org/764 log: rsl notice: tiny tweak for readability Change-Id: I57c3b7d27d857c96e3fa3dacf7b766bc43100fc3 --- M openbsc/src/libbsc/abis_rsl.c 1 file changed, 1 insertion(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/64/764/1 diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index 3d694c3..183e651 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -790,7 +790,7 @@ osmo_timer_del(&lchan->T3109); if (lchan->state == LCHAN_S_REL_ERR) { - LOGP(DRSL, LOGL_NOTICE, "%s is in error state not sending release.\n", + LOGP(DRSL, LOGL_NOTICE, "%s is in error state, not sending release.\n", gsm_lchan_name(lchan)); return -1; } -- To view, visit https://gerrit.osmocom.org/764 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I57c3b7d27d857c96e3fa3dacf7b766bc43100fc3 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Thu Aug 25 04:12:24 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 25 Aug 2016 04:12:24 +0000 Subject: [PATCH] osmo-pcu[master]: EGPRS: PUAN encoding: add test case to show wrong urbb_len i... In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/702 to look at the new patch set (#11). EGPRS: PUAN encoding: add test case to show wrong urbb_len issue This patch adds a test case which expects a current bug with EGPRS PUAN encoding when VQ != VR. The test's expectation is corrected along with the bugfix in a subsequent commit Adds test_tbf_puan_urbb_len to describe the following bug: EGPRS PUAN encoding disregards the urbb_len, leading to identical PUAN messages regardless of the urbb_len. Related: OS#1793 Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 --- M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 3 files changed, 304 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/02/702/11 diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..5b9ff9d 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -618,6 +618,149 @@ &ulreq, tbf->poll_fn); } +static gprs_rlcmac_ul_tbf *puan_urbb_len_issue(BTS *the_bts, + uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, + uint8_t ms_class, uint8_t egprs_ms_class) +{ + GprsMs *ms; + uint32_t rach_fn = *fn - 51; + uint32_t sba_fn = *fn + 52; + uint8_t trx_no = 0; + int tfi = 0, i = 0; + gprs_rlcmac_ul_tbf *ul_tbf; + struct gprs_rlcmac_pdch *pdch; + gprs_rlcmac_bts *bts; + RlcMacUplink_t ulreq = {0}; + struct pcu_l1_meas meas; + struct gprs_rlc_ul_header_egprs_3 *egprs3 = NULL; + GprsCodingScheme cs; + + meas.set_rssi(31); + bts = the_bts->bts_data(); + + /* needed to set last_rts_fn in the PDCH object */ + request_dl_rlc_block(bts, trx_no, ts_no, fn); + + /* + * simulate RACH, this sends an Immediate + * Assignment Uplink on the AGCH + */ + the_bts->rcv_rach(0x73, rach_fn, qta); + + /* get next free TFI */ + tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1); + + /* fake a resource request */ + ulreq.u.MESSAGE_TYPE = MT_PACKET_RESOURCE_REQUEST; + ulreq.u.Packet_Resource_Request.PayloadType = GPRS_RLCMAC_CONTROL_BLOCK; + ulreq.u.Packet_Resource_Request.ID.UnionType = 1; /* != 0 */ + ulreq.u.Packet_Resource_Request.ID.u.TLLI = tlli; + ulreq.u.Packet_Resource_Request.Exist_MS_Radio_Access_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + Count_MS_RA_capability_value = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Exist_Multislot_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + Exist_GPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + GPRS_multislot_class = ms_class; + if (egprs_ms_class) { + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Multislot_capability.Exist_EGPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Multislot_capability.EGPRS_multislot_class = ms_class; + } + + send_ul_mac_block(the_bts, trx_no, ts_no, &ulreq, sba_fn); + + /* check the TBF */ + ul_tbf = the_bts->ul_tbf_by_tfi(tfi, trx_no, ts_no); + OSMO_ASSERT(ul_tbf); + OSMO_ASSERT(ul_tbf->ta() == qta / 4); + + /* send packet uplink assignment */ + *fn = sba_fn; + request_dl_rlc_block(ul_tbf, fn); + + /* send real acknowledgement */ + send_control_ack(ul_tbf); + + check_tbf(ul_tbf); + /* send fake data */ + uint8_t data_msg[42] = { + 0xf << 2, /* GPRS_RLCMAC_DATA_BLOCK << 6, CV = 15 */ + tfi << 1, + 1, /* BSN:7, E:1 */ + }; + + pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no]; + pdch->rcv_block(&data_msg[0], 23, *fn, &meas); + + ms = the_bts->ms_by_tlli(tlli); + OSMO_ASSERT(ms != NULL); + OSMO_ASSERT(ms->ta() == qta/4); + OSMO_ASSERT(ms->ul_tbf() == ul_tbf); + + /* + * TS 44.060, B.8.1 + * first seg received first, later second seg + */ + cs = GprsCodingScheme::MCS3; + egprs3 = (struct gprs_rlc_ul_header_egprs_3 *) data_msg; + egprs3->si = 0; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 1; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 0; + egprs3->pi = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + struct msgb *msg1 = ul_tbf->create_ul_ack(*fn, ts_no); + + OSMO_ASSERT(!strcmp(osmo_hexdump(msg1->data, msg1->data_len), + "40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b " + )); + + egprs3->si = 0; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 4; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + struct msgb *msg2 = ul_tbf->create_ul_ack(*fn, ts_no); + + /* TODO: Need to modify the assert */ + OSMO_ASSERT(!strcmp(osmo_hexdump(msg1->data, msg1->data_len), + "40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b " + )); + + return ul_tbf; +} + static gprs_rlcmac_ul_tbf *establish_ul_tbf_two_phase_spb(BTS *the_bts, uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, uint8_t ms_class, uint8_t egprs_ms_class) @@ -1631,6 +1774,41 @@ gprs_bssgp_destroy(); } +static void test_tbf_puan_urbb_len(void) +{ + BTS the_bts; + int ts_no = 7; + uint32_t fn = 2654218; + uint16_t qta = 31; + uint32_t tlli = 0xf1223344; + const char *imsi = "0011223344"; + uint8_t ms_class = 1; + uint8_t egprs_ms_class = 1; + gprs_rlcmac_ul_tbf *ul_tbf; + GprsMs *ms; + uint8_t test_data[256]; + + printf("=== start %s ===\n", __func__); + + memset(test_data, 1, sizeof(test_data)); + + setup_bts(&the_bts, ts_no, 4); + the_bts.bts_data()->initial_mcs_dl = 9; + the_bts.bts_data()->egprs_enabled = 1; + + ul_tbf = puan_urbb_len_issue(&the_bts, ts_no, tlli, &fn, qta, + ms_class, egprs_ms_class); + + ms = ul_tbf->ms(); + fprintf(stderr, "Got '%s', TA=%d\n", ul_tbf->name(), ul_tbf->ta()); + fprintf(stderr, + "Got MS: TLLI = 0x%08x, TA = %d\n", ms->tlli(), ms->ta()); + + send_dl_data(&the_bts, tlli, imsi, test_data, sizeof(test_data)); + + printf("=== end %s ===\n", __func__); +} + static void test_tbf_egprs_two_phase_spb(void) { BTS the_bts; @@ -2071,6 +2249,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_puan_urbb_len(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..aa8a087 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -5780,3 +5780,126 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654218 block=8 data=47 94 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +MS requests UL TBF on RACH, so we provide one: +MS requests single block allocation +RX: [PCU <- BTS] RACH qbit-ta=31 ra=0x73, Fn=2654167 (17,25,9), SBFn=2654270 +TX: Immediate Assignment Uplink (AGCH) + - TRX=0 (0) TS=7 TA=7 TSC=0 TFI=-1 USF=7 +Sending data request: trx=0 ts=0 sapi=2 arfcn=0 fn=0 block=0 data=2d 06 3f 10 0f 00 00 73 8b 29 07 00 c0 0c 5a 43 2b 2b 2b 2b 2b 2b 2b +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +MS requests UL TBF in packet resource request of single block, so we provide one: +MS supports EGPRS multislot class 1. +********** TBF starts here ********** +Allocating UL TBF: MS_CLASS=1/1 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 1 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 1 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign uplink TS=7 TFI=0 USF=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 00 +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=ASSIGN EGPRS) starting timer 3169. +Modifying MS object, UL TLLI: 0x00000000 -> 0xf1223344, not yet confirmed +Modifying MS object, TLLI = 0xf1223344, TA 0 -> 7 +Change control TS to 7 until assinment is complete. +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS)s start Packet Uplink Assignment (PACCH) ++++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++ +------------------------- TX : Packet Uplink Assignment ------------------------- +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS): Scheduling polling at FN 2654283 TS 7 +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS) changes state from ASSIGN to WAIT ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Scheduled UL Assignment polling on FN=2654283, TS=7 +Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) (TRX=0, TS=7) +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654270 block=8 data=4f 28 5e 24 46 68 90 f8 0a 39 00 00 88 00 08 2b 2b 2b 2b 2b 2b 2b 2b +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Packet Control Ack +TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) changes state from WAIT ASSIGN to FLOW +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=0 .. V(R)=0) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got CS-1 RLC data block: CV=15, BSN=0, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 0 storing in window (0..63) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 1 +- Taking block 0 out, raising V(Q) to 1 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=0 CV=15 +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1d 08 40 c1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=0, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=1) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=1, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 1 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 2 +- Taking block 1 out, raising V(Q) to 2 +- Assembling frames: (len=37) +-- Frame 1 starts at offset 0, length=37, is_complete=0 +- No gaps in received block, last block: BSN=1 CV=7 +Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) + - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 2, BOW, EOW +Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1d 20 40 c1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=0, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=2 .. V(R)=2) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=4, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 4 storing in window (2..65) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 5 +Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) + - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 5, BOW, EOW +Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got 'TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS)', TA=7 +Got MS: TLLI = 0xf1223344, TA = 7 +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=1/1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign downlink TS=7 TFI=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0xf1223344, TBF = TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 80 +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +Modifying MS object, TLLI: 0xf1223344 confirmed +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) [DOWNLINK] START +Modifying MS object, TLLI = 0xf1223344, IMSI '' -> '0011223344' +Send dowlink assignment on PACCH, because TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) exists +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) starting timer 0. +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) append diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..16ac5da 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,5 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_puan_urbb_len === +=== end test_tbf_puan_urbb_len === -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 11 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Thu Aug 25 04:14:05 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 25 Aug 2016 04:14:05 +0000 Subject: osmo-pcu[master]: EGPRS: PUAN encoding: add test case to show wrong urbb_len i... In-Reply-To: References: Message-ID: Patch Set 11: (1 comment) https://gerrit.osmocom.org/#/c/702/11/tests/tbf/TbfTest.cpp File tests/tbf/TbfTest.cpp: Line 757: OSMO_ASSERT(!strcmp(osmo_hexdump(msg1->data, msg1->data_len), fix this. -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 11 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 25 04:14:50 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 25 Aug 2016 04:14:50 +0000 Subject: [PATCH] osmo-pcu[master]: EGPRS: PUAN encoding: add test case to show wrong urbb_len i... In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/702 to look at the new patch set (#12). EGPRS: PUAN encoding: add test case to show wrong urbb_len issue This patch adds a test case which expects a current bug with EGPRS PUAN encoding when VQ != VR. The test's expectation is corrected along with the bugfix in a subsequent commit Adds test_tbf_puan_urbb_len to describe the following bug: EGPRS PUAN encoding disregards the urbb_len, leading to identical PUAN messages regardless of the urbb_len. Related: OS#1793 Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 --- M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 3 files changed, 304 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/02/702/12 diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..8779729 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -618,6 +618,149 @@ &ulreq, tbf->poll_fn); } +static gprs_rlcmac_ul_tbf *puan_urbb_len_issue(BTS *the_bts, + uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, + uint8_t ms_class, uint8_t egprs_ms_class) +{ + GprsMs *ms; + uint32_t rach_fn = *fn - 51; + uint32_t sba_fn = *fn + 52; + uint8_t trx_no = 0; + int tfi = 0, i = 0; + gprs_rlcmac_ul_tbf *ul_tbf; + struct gprs_rlcmac_pdch *pdch; + gprs_rlcmac_bts *bts; + RlcMacUplink_t ulreq = {0}; + struct pcu_l1_meas meas; + struct gprs_rlc_ul_header_egprs_3 *egprs3 = NULL; + GprsCodingScheme cs; + + meas.set_rssi(31); + bts = the_bts->bts_data(); + + /* needed to set last_rts_fn in the PDCH object */ + request_dl_rlc_block(bts, trx_no, ts_no, fn); + + /* + * simulate RACH, this sends an Immediate + * Assignment Uplink on the AGCH + */ + the_bts->rcv_rach(0x73, rach_fn, qta); + + /* get next free TFI */ + tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1); + + /* fake a resource request */ + ulreq.u.MESSAGE_TYPE = MT_PACKET_RESOURCE_REQUEST; + ulreq.u.Packet_Resource_Request.PayloadType = GPRS_RLCMAC_CONTROL_BLOCK; + ulreq.u.Packet_Resource_Request.ID.UnionType = 1; /* != 0 */ + ulreq.u.Packet_Resource_Request.ID.u.TLLI = tlli; + ulreq.u.Packet_Resource_Request.Exist_MS_Radio_Access_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + Count_MS_RA_capability_value = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Exist_Multislot_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + Exist_GPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + GPRS_multislot_class = ms_class; + if (egprs_ms_class) { + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Multislot_capability.Exist_EGPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Multislot_capability.EGPRS_multislot_class = ms_class; + } + + send_ul_mac_block(the_bts, trx_no, ts_no, &ulreq, sba_fn); + + /* check the TBF */ + ul_tbf = the_bts->ul_tbf_by_tfi(tfi, trx_no, ts_no); + OSMO_ASSERT(ul_tbf); + OSMO_ASSERT(ul_tbf->ta() == qta / 4); + + /* send packet uplink assignment */ + *fn = sba_fn; + request_dl_rlc_block(ul_tbf, fn); + + /* send real acknowledgement */ + send_control_ack(ul_tbf); + + check_tbf(ul_tbf); + /* send fake data */ + uint8_t data_msg[42] = { + 0xf << 2, /* GPRS_RLCMAC_DATA_BLOCK << 6, CV = 15 */ + tfi << 1, + 1, /* BSN:7, E:1 */ + }; + + pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no]; + pdch->rcv_block(&data_msg[0], 23, *fn, &meas); + + ms = the_bts->ms_by_tlli(tlli); + OSMO_ASSERT(ms != NULL); + OSMO_ASSERT(ms->ta() == qta/4); + OSMO_ASSERT(ms->ul_tbf() == ul_tbf); + + /* + * TS 44.060, B.8.1 + * first seg received first, later second seg + */ + cs = GprsCodingScheme::MCS3; + egprs3 = (struct gprs_rlc_ul_header_egprs_3 *) data_msg; + egprs3->si = 0; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 1; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 0; + egprs3->pi = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + struct msgb *msg1 = ul_tbf->create_ul_ack(*fn, ts_no); + + OSMO_ASSERT(!strcmp(osmo_hexdump(msg1->data, msg1->data_len), + "40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b " + )); + + egprs3->si = 0; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 4; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + msg1 = ul_tbf->create_ul_ack(*fn, ts_no); + + /* TODO: Need to modify the assert */ + OSMO_ASSERT(!strcmp(osmo_hexdump(msg1->data, msg1->data_len), + "40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b " + )); + + return ul_tbf; +} + static gprs_rlcmac_ul_tbf *establish_ul_tbf_two_phase_spb(BTS *the_bts, uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, uint8_t ms_class, uint8_t egprs_ms_class) @@ -1631,6 +1774,41 @@ gprs_bssgp_destroy(); } +static void test_tbf_puan_urbb_len(void) +{ + BTS the_bts; + int ts_no = 7; + uint32_t fn = 2654218; + uint16_t qta = 31; + uint32_t tlli = 0xf1223344; + const char *imsi = "0011223344"; + uint8_t ms_class = 1; + uint8_t egprs_ms_class = 1; + gprs_rlcmac_ul_tbf *ul_tbf; + GprsMs *ms; + uint8_t test_data[256]; + + printf("=== start %s ===\n", __func__); + + memset(test_data, 1, sizeof(test_data)); + + setup_bts(&the_bts, ts_no, 4); + the_bts.bts_data()->initial_mcs_dl = 9; + the_bts.bts_data()->egprs_enabled = 1; + + ul_tbf = puan_urbb_len_issue(&the_bts, ts_no, tlli, &fn, qta, + ms_class, egprs_ms_class); + + ms = ul_tbf->ms(); + fprintf(stderr, "Got '%s', TA=%d\n", ul_tbf->name(), ul_tbf->ta()); + fprintf(stderr, + "Got MS: TLLI = 0x%08x, TA = %d\n", ms->tlli(), ms->ta()); + + send_dl_data(&the_bts, tlli, imsi, test_data, sizeof(test_data)); + + printf("=== end %s ===\n", __func__); +} + static void test_tbf_egprs_two_phase_spb(void) { BTS the_bts; @@ -2071,6 +2249,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_puan_urbb_len(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..aa8a087 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -5780,3 +5780,126 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654218 block=8 data=47 94 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +MS requests UL TBF on RACH, so we provide one: +MS requests single block allocation +RX: [PCU <- BTS] RACH qbit-ta=31 ra=0x73, Fn=2654167 (17,25,9), SBFn=2654270 +TX: Immediate Assignment Uplink (AGCH) + - TRX=0 (0) TS=7 TA=7 TSC=0 TFI=-1 USF=7 +Sending data request: trx=0 ts=0 sapi=2 arfcn=0 fn=0 block=0 data=2d 06 3f 10 0f 00 00 73 8b 29 07 00 c0 0c 5a 43 2b 2b 2b 2b 2b 2b 2b +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +MS requests UL TBF in packet resource request of single block, so we provide one: +MS supports EGPRS multislot class 1. +********** TBF starts here ********** +Allocating UL TBF: MS_CLASS=1/1 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 1 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 1 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign uplink TS=7 TFI=0 USF=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 00 +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=ASSIGN EGPRS) starting timer 3169. +Modifying MS object, UL TLLI: 0x00000000 -> 0xf1223344, not yet confirmed +Modifying MS object, TLLI = 0xf1223344, TA 0 -> 7 +Change control TS to 7 until assinment is complete. +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS)s start Packet Uplink Assignment (PACCH) ++++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++ +------------------------- TX : Packet Uplink Assignment ------------------------- +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS): Scheduling polling at FN 2654283 TS 7 +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS) changes state from ASSIGN to WAIT ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Scheduled UL Assignment polling on FN=2654283, TS=7 +Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) (TRX=0, TS=7) +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654270 block=8 data=4f 28 5e 24 46 68 90 f8 0a 39 00 00 88 00 08 2b 2b 2b 2b 2b 2b 2b 2b +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Packet Control Ack +TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) changes state from WAIT ASSIGN to FLOW +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=0 .. V(R)=0) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got CS-1 RLC data block: CV=15, BSN=0, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 0 storing in window (0..63) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 1 +- Taking block 0 out, raising V(Q) to 1 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=0 CV=15 +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1d 08 40 c1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=0, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=1) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=1, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 1 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 2 +- Taking block 1 out, raising V(Q) to 2 +- Assembling frames: (len=37) +-- Frame 1 starts at offset 0, length=37, is_complete=0 +- No gaps in received block, last block: BSN=1 CV=7 +Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) + - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 2, BOW, EOW +Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1d 20 40 c1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=0, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=2 .. V(R)=2) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=4, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 4 storing in window (2..65) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 5 +Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) + - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 5, BOW, EOW +Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got 'TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS)', TA=7 +Got MS: TLLI = 0xf1223344, TA = 7 +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=1/1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign downlink TS=7 TFI=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0xf1223344, TBF = TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 80 +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +Modifying MS object, TLLI: 0xf1223344 confirmed +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) [DOWNLINK] START +Modifying MS object, TLLI = 0xf1223344, IMSI '' -> '0011223344' +Send dowlink assignment on PACCH, because TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) exists +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) starting timer 0. +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) append diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..16ac5da 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,5 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_puan_urbb_len === +=== end test_tbf_puan_urbb_len === -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 12 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Thu Aug 25 04:20:16 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 25 Aug 2016 04:20:16 +0000 Subject: osmo-pcu[master]: Fix EGPRS PUAN encoding: use correct urbb_len In-Reply-To: References: Message-ID: Patch Set 4: (1 comment) https://gerrit.osmocom.org/#/c/703/4/tests/tbf/TbfTest.cpp File tests/tbf/TbfTest.cpp: Line 752: OSMO_ASSERT(memcmp(msg2->data, msg1->data, msg1->data_len)); align this file -- To view, visit https://gerrit.osmocom.org/703 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Iba7b1995028bd81749ffb080616b2ad5f2540d57 Gerrit-PatchSet: 4 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 25 04:22:38 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 25 Aug 2016 04:22:38 +0000 Subject: [PATCH] osmo-pcu[master]: Fix EGPRS PUAN encoding: use correct urbb_len In-Reply-To: References: Message-ID: Hello Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/703 to look at the new patch set (#5). Fix EGPRS PUAN encoding: use correct urbb_len Earlier there was an incorrect encoding of PUAN when VQ is not equal VR case for EGPRS UL RLC window. The PCU was encoding the same PUAN message always irrespective of radio condition. This was a bottle neck for performance testing. Which has been fixed in this patch. Related: OS#1793 unit test assertion in the previous commit is fixed in this patch. Change-Id: Iba7b1995028bd81749ffb080616b2ad5f2540d57 --- M src/encoding.cpp M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err 3 files changed, 11 insertions(+), 7 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/03/703/5 diff --git a/src/encoding.cpp b/src/encoding.cpp index 63049ac..41e0d10 100644 --- a/src/encoding.cpp +++ b/src/encoding.cpp @@ -575,7 +575,8 @@ eow = false; urbb_len = rest_bits - 9; /* TODO: use compression (see above) */ - } + } else + urbb_len = num_blocks; if (urbb_len + crbb_len == rest_bits) len = -1; diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 883ef26..8e37b30 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -730,7 +730,9 @@ pdch->rcv_block(data_msg, 42, *fn, &meas); struct msgb *msg1 = ul_tbf->create_ul_ack(*fn, ts_no); - + OSMO_ASSERT(!strcmp(osmo_hexdump(msg1->data, msg1->data_len), + "40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b " + )); egprs3->si = 0; egprs3->r = 1; egprs3->cv = 7; @@ -747,10 +749,11 @@ pdch->rcv_block(data_msg, 42, *fn, &meas); - struct msgb *msg2 = ul_tbf->create_ul_ack(*fn, ts_no); + msg1 = ul_tbf->create_ul_ack(*fn, ts_no); - /* TODO: Need to modify the assert */ - OSMO_ASSERT(!memcmp(msg2->data, msg1->data, msg1->data_len)); + OSMO_ASSERT(!strcmp(osmo_hexdump(msg1->data, msg1->data_len), + "40 24 01 3f 3e 24 46 68 90 88 b0 06 8b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b " + )); return ul_tbf; } diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index aa8a087..fa0927c 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -5875,8 +5875,8 @@ TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - Raising V(R) to 5 Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) - - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 5, BOW, EOW -Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b + - EGPRS URBB, len = 2, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 5, BOW, EOW +Uplink Ack/Nack bit count 100, max 184, message = 40 24 01 3f 3e 24 46 68 90 88 b0 06 8b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b Got 'TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS)', TA=7 Got MS: TLLI = 0xf1223344, TA = 7 ********** TBF starts here ********** -- To view, visit https://gerrit.osmocom.org/703 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Iba7b1995028bd81749ffb080616b2ad5f2540d57 Gerrit-PatchSet: 5 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Thu Aug 25 04:28:20 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 25 Aug 2016 04:28:20 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 22: Hi Neels, Can you please merge this patch series to master. As I have critical fixes needs to be sent for review which are dependent on the same files present in this patch series. Thanks, Aravind Sirsikar -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 22 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 25 04:29:39 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 25 Aug 2016 04:29:39 +0000 Subject: osmo-pcu[master]: EGPRS: PUAN encoding: add test case to show wrong urbb_len i... In-Reply-To: References: Message-ID: Patch Set 12: Hi Neels, I see your point in modifying the test suite. I have modified as per your suggestion. Please have a look. Thanks, Aravind Sirsikar -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 12 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 25 05:14:08 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 25 Aug 2016 05:14:08 +0000 Subject: [PATCH] osmo-pcu[master]: EGPRS: EPDAN decoding: add test case to show no ack_nack len... Message-ID: Review at https://gerrit.osmocom.org/765 EGPRS: EPDAN decoding: add test case to show no ack_nack len issue This patch adds a test case itest_epdan_noack_nack_len_issue which expects a current bug with EGPRS EPDAN decoding Ack/Nack dissector length is not received. The test's expectation is corrected along with the bug fix in a subsequent commit Related: OS#1805 Change-Id: I8da84794748f2e81722c3eca69b46ccc3a21552e --- M tests/rlcmac/RLCMACTest.cpp 1 file changed, 33 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/65/765/1 diff --git a/tests/rlcmac/RLCMACTest.cpp b/tests/rlcmac/RLCMACTest.cpp index 466b89e..4ee99a9 100644 --- a/tests/rlcmac/RLCMACTest.cpp +++ b/tests/rlcmac/RLCMACTest.cpp @@ -25,8 +25,15 @@ #include #include "csn1.h" #include "gsm_rlcmac.h" +#include "pcu_utils.h" +#include "bts.h" +#include "tbf.h" +#include "gprs_debug.h" + extern "C" { +#if 0 extern const struct log_info gprs_log_info; +#endif #include "pcu_vty.h" #include #include @@ -211,6 +218,31 @@ bitvec_free(resultVector); } +void test_epdan_noack_nack_len_issue() +{ + std::string testData_epdan[] = { + "40200bffd161003e0e519ffffffb800000000000000000" //EPDAN No ACKNACK len + }; + + bitvec *vector = bitvec_alloc(23); + + bitvec_unhex(vector, testData_epdan[0].c_str()); + RlcMacUplink_t *data = (RlcMacUplink_t *)malloc(sizeof(RlcMacUplink_t)); + + decode_gsm_rlcmac_uplink(vector, data); + + EGPRS_AckNack_Desc_t *urbb = + &data->u.Egprs_Packet_Downlink_Ack_Nack.EGPRS_AckNack.Desc; + /* + * TODO: URBB len is decoded as 102. so there is total 12 bytes and + * 6 bits in the 13th byte. in 13th byte we expect value + * as 0x00. But we see 0xea. Which is incorrect + */ + OSMO_ASSERT(!strcmp(osmo_hexdump(urbb->URBB, (urbb->URBB_LENGTH + 7)/8), + "7f ff ff ee 00 00 00 00 00 00 00 00 ea " + )); +} + int main(int argc, char *argv[]) { osmo_init_logging(&gprs_log_info); @@ -218,5 +250,5 @@ //printSizeofRLCMAC(); testRlcMacDownlink(); testRlcMacUplink(); - + test_epdan_noack_nack_len_issue(); } -- To view, visit https://gerrit.osmocom.org/765 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I8da84794748f2e81722c3eca69b46ccc3a21552e Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Thu Aug 25 05:14:08 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 25 Aug 2016 05:14:08 +0000 Subject: [PATCH] osmo-pcu[master]: Fix EGPRS EPDAN decoding: no ack nack dissector length Message-ID: Review at https://gerrit.osmocom.org/766 Fix EGPRS EPDAN decoding: no ack nack dissector length Earlier there was an incorrect decoding of URBB fields when EPDAN is received withot ack/Nack dissector length.This was a bottle neck for performance testing. Which has been fixed in this patch. Related: OS#1805 unit test assertion in the previous commit is fixed in this patch. Change-Id: Ieddf96aca82b0b0e917cfcc70aeb978799fb4e95 --- M src/csn1.cpp M tests/rlcmac/RLCMACTest.cpp 2 files changed, 3 insertions(+), 7 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/66/766/1 diff --git a/src/csn1.cpp b/src/csn1.cpp index d51fe83..e9437ed 100644 --- a/src/csn1.cpp +++ b/src/csn1.cpp @@ -1111,7 +1111,7 @@ { /* extract bits */ guint8* pui8 = pui8DATA(data, pDescr->offset); gint16 nB1 = no_of_bits & 0x07;/* no_of_bits Mod 8 */ - + no_of_bits -=nB1; while (no_of_bits > 0) { *pui8 = bitvec_read_field(vector, readIndex, 8); diff --git a/tests/rlcmac/RLCMACTest.cpp b/tests/rlcmac/RLCMACTest.cpp index 4ee99a9..1582ae2 100644 --- a/tests/rlcmac/RLCMACTest.cpp +++ b/tests/rlcmac/RLCMACTest.cpp @@ -233,13 +233,9 @@ EGPRS_AckNack_Desc_t *urbb = &data->u.Egprs_Packet_Downlink_Ack_Nack.EGPRS_AckNack.Desc; - /* - * TODO: URBB len is decoded as 102. so there is total 12 bytes and - * 6 bits in the 13th byte. in 13th byte we expect value - * as 0x00. But we see 0xea. Which is incorrect - */ + OSMO_ASSERT(!strcmp(osmo_hexdump(urbb->URBB, (urbb->URBB_LENGTH + 7)/8), - "7f ff ff ee 00 00 00 00 00 00 00 00 ea " + "7f ff ff ee 00 00 00 00 00 00 00 00 00 " )); } -- To view, visit https://gerrit.osmocom.org/766 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ieddf96aca82b0b0e917cfcc70aeb978799fb4e95 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Thu Aug 25 07:23:20 2016 From: gerrit-no-reply at lists.osmocom.org (pravin) Date: Thu, 25 Aug 2016 07:23:20 +0000 Subject: osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Patch Set 20: > Build Successful > > http://jenkins.osmocom.org/jenkins/job/osmo-pcu-gerrit/259/ : > SUCCESS' --verified 1 --code-review 0 I have tried to address all the comments. please let me know the status. -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 20 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: pravin Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 25 07:36:45 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Thu, 25 Aug 2016 07:36:45 +0000 Subject: [PATCH] openbsc[master]: osmo-nitb: generate backtrace on SIGABRT Message-ID: Review at https://gerrit.osmocom.org/767 osmo-nitb: generate backtrace on SIGABRT As the NITB has an internal SIGABRT handler that prints a talloc report, let's also print a stack backtrace at the same point. Change-Id: Ia63aa5c39b26e27c3ee220d755c17d2c1ef636c5 --- M openbsc/src/osmo-nitb/bsc_hack.c 1 file changed, 1 insertion(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/67/767/1 diff --git a/openbsc/src/osmo-nitb/bsc_hack.c b/openbsc/src/osmo-nitb/bsc_hack.c index e3e8927..976aefa 100644 --- a/openbsc/src/osmo-nitb/bsc_hack.c +++ b/openbsc/src/osmo-nitb/bsc_hack.c @@ -209,6 +209,7 @@ exit(0); break; case SIGABRT: + osmo_generate_backtrace(); /* in case of abort, we want to obtain a talloc report * and then return to the caller, who will abort the process */ case SIGUSR1: -- To view, visit https://gerrit.osmocom.org/767 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ia63aa5c39b26e27c3ee220d755c17d2c1ef636c5 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Harald Welte From gerrit-no-reply at lists.osmocom.org Thu Aug 25 08:47:55 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 25 Aug 2016 08:47:55 +0000 Subject: osmo-pcu[master]: EGPRS: EPDAN decoding: add test case to show no ack_nack len... In-Reply-To: References: Message-ID: Patch Set 1: (1 comment) https://gerrit.osmocom.org/#/c/765/1/tests/rlcmac/RLCMACTest.cpp File tests/rlcmac/RLCMACTest.cpp: Line 34: #if 0 fix this -- To view, visit https://gerrit.osmocom.org/765 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I8da84794748f2e81722c3eca69b46ccc3a21552e Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 25 08:48:35 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 25 Aug 2016 08:48:35 +0000 Subject: [PATCH] osmo-pcu[master]: EGPRS: EPDAN decoding: add test case to show no ack_nack len... In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/765 to look at the new patch set (#2). EGPRS: EPDAN decoding: add test case to show no ack_nack len issue This patch adds a test case itest_epdan_noack_nack_len_issue which expects a current bug with EGPRS EPDAN decoding Ack/Nack dissector length is not received. The test's expectation is corrected along with the bug fix in a subsequent commit Related: OS#1805 Change-Id: I8da84794748f2e81722c3eca69b46ccc3a21552e --- M tests/rlcmac/RLCMACTest.cpp 1 file changed, 31 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/65/765/2 diff --git a/tests/rlcmac/RLCMACTest.cpp b/tests/rlcmac/RLCMACTest.cpp index 466b89e..74a8ad3 100644 --- a/tests/rlcmac/RLCMACTest.cpp +++ b/tests/rlcmac/RLCMACTest.cpp @@ -25,8 +25,12 @@ #include #include "csn1.h" #include "gsm_rlcmac.h" +#include "pcu_utils.h" +#include "bts.h" +#include "tbf.h" +#include "gprs_debug.h" + extern "C" { -extern const struct log_info gprs_log_info; #include "pcu_vty.h" #include #include @@ -211,6 +215,31 @@ bitvec_free(resultVector); } +void test_epdan_noack_nack_len_issue() +{ + std::string testData_epdan[] = { + "40200bffd161003e0e519ffffffb800000000000000000" //EPDAN No ACKNACK len + }; + + bitvec *vector = bitvec_alloc(23); + + bitvec_unhex(vector, testData_epdan[0].c_str()); + RlcMacUplink_t *data = (RlcMacUplink_t *)malloc(sizeof(RlcMacUplink_t)); + + decode_gsm_rlcmac_uplink(vector, data); + + EGPRS_AckNack_Desc_t *urbb = + &data->u.Egprs_Packet_Downlink_Ack_Nack.EGPRS_AckNack.Desc; + /* + * TODO: URBB len is decoded as 102. so there is total 12 bytes and + * 6 bits in the 13th byte. in 13th byte we expect value + * as 0x00. But we see 0xea. Which is incorrect + */ + OSMO_ASSERT(!strcmp(osmo_hexdump(urbb->URBB, (urbb->URBB_LENGTH + 7)/8), + "7f ff ff ee 00 00 00 00 00 00 00 00 ea " + )); +} + int main(int argc, char *argv[]) { osmo_init_logging(&gprs_log_info); @@ -218,5 +247,5 @@ //printSizeofRLCMAC(); testRlcMacDownlink(); testRlcMacUplink(); - + test_epdan_noack_nack_len_issue(); } -- To view, visit https://gerrit.osmocom.org/765 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I8da84794748f2e81722c3eca69b46ccc3a21552e Gerrit-PatchSet: 2 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Thu Aug 25 08:49:32 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 25 Aug 2016 08:49:32 +0000 Subject: osmo-pcu[master]: Fix EGPRS EPDAN decoding: no ack nack dissector length In-Reply-To: References: Message-ID: Patch Set 1: (1 comment) https://gerrit.osmocom.org/#/c/766/1/tests/rlcmac/RLCMACTest.cpp File tests/rlcmac/RLCMACTest.cpp: Line 236: fix this -- To view, visit https://gerrit.osmocom.org/766 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieddf96aca82b0b0e917cfcc70aeb978799fb4e95 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 25 08:49:57 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 25 Aug 2016 08:49:57 +0000 Subject: [PATCH] osmo-pcu[master]: Fix EGPRS EPDAN decoding: no ack nack dissector length In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/766 to look at the new patch set (#2). Fix EGPRS EPDAN decoding: no ack nack dissector length Earlier there was an incorrect decoding of URBB fields when EPDAN is received withot ack/Nack dissector length.This was a bottle neck for performance testing. Which has been fixed in this patch. Related: OS#1805 unit test assertion in the previous commit is fixed in this patch. Change-Id: Ieddf96aca82b0b0e917cfcc70aeb978799fb4e95 --- M src/csn1.cpp M tests/rlcmac/RLCMACTest.cpp 2 files changed, 3 insertions(+), 10 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/66/766/2 diff --git a/src/csn1.cpp b/src/csn1.cpp index d51fe83..e9437ed 100644 --- a/src/csn1.cpp +++ b/src/csn1.cpp @@ -1111,7 +1111,7 @@ { /* extract bits */ guint8* pui8 = pui8DATA(data, pDescr->offset); gint16 nB1 = no_of_bits & 0x07;/* no_of_bits Mod 8 */ - + no_of_bits -=nB1; while (no_of_bits > 0) { *pui8 = bitvec_read_field(vector, readIndex, 8); diff --git a/tests/rlcmac/RLCMACTest.cpp b/tests/rlcmac/RLCMACTest.cpp index 4ee99a9..816c1fa 100644 --- a/tests/rlcmac/RLCMACTest.cpp +++ b/tests/rlcmac/RLCMACTest.cpp @@ -31,9 +31,6 @@ #include "gprs_debug.h" extern "C" { -#if 0 -extern const struct log_info gprs_log_info; -#endif #include "pcu_vty.h" #include #include @@ -233,13 +230,9 @@ EGPRS_AckNack_Desc_t *urbb = &data->u.Egprs_Packet_Downlink_Ack_Nack.EGPRS_AckNack.Desc; - /* - * TODO: URBB len is decoded as 102. so there is total 12 bytes and - * 6 bits in the 13th byte. in 13th byte we expect value - * as 0x00. But we see 0xea. Which is incorrect - */ + OSMO_ASSERT(!strcmp(osmo_hexdump(urbb->URBB, (urbb->URBB_LENGTH + 7)/8), - "7f ff ff ee 00 00 00 00 00 00 00 00 ea " + "7f ff ff ee 00 00 00 00 00 00 00 00 00 " )); } -- To view, visit https://gerrit.osmocom.org/766 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ieddf96aca82b0b0e917cfcc70aeb978799fb4e95 Gerrit-PatchSet: 2 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Thu Aug 25 09:49:54 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 25 Aug 2016 09:49:54 +0000 Subject: openbsc[master]: chan_alloc.c: use ts_subslots() instead of subslots_per_pchan[] In-Reply-To: References: Message-ID: Patch Set 1: > So if a voice call is > established, > there is one call to ts_sublsots() (per MS). Sorry, that's not true -- a bit more often, though still not critical: For each channel allocation lookup, it is called once per time slot. e.g. if we have one TRX and an MS starts a TCH/H: 8 times. -- To view, visit https://gerrit.osmocom.org/668 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Icbea7dbd78abf6144e5291f531a97f96507d8cbf Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 25 09:51:42 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 25 Aug 2016 09:51:42 +0000 Subject: openbsc[master]: dyn TS: bts_chan_load: use correct nr of subslots for dyn ts In-Reply-To: References: Message-ID: Patch Set 1: > * once per paging and lchan Make that: once per paging and *time slot* > * for VTY show commands > * for CTRL commands to fetch the channel load -- To view, visit https://gerrit.osmocom.org/667 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I659acebca82dfb3e305433471be64e9d27439af8 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 25 10:16:28 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 25 Aug 2016 10:16:28 +0000 Subject: osmo-pcu[master]: EGPRS: PUAN encoding: add test case to show wrong urbb_len i... In-Reply-To: References: Message-ID: Patch Set 12: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 12 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 25 10:28:50 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 25 Aug 2016 10:28:50 +0000 Subject: osmo-pcu[master]: Fix EGPRS PUAN encoding: use correct urbb_len In-Reply-To: References: Message-ID: Patch Set 5: (1 comment) https://gerrit.osmocom.org/#/c/703/5/tests/tbf/TbfTest.cpp File tests/tbf/TbfTest.cpp: Line 735: )); This patch is clearly not based on the most recent version of patch 702 that adds the test case... Not sure whether this is gerrit's fault. The easiest to resolve would probably be to submit (i.e. merge to master) 702 and then rebase this onto master; probably resolving a minor merge conflict. I will +2 as soon as this is up-to-date. -- To view, visit https://gerrit.osmocom.org/703 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Iba7b1995028bd81749ffb080616b2ad5f2540d57 Gerrit-PatchSet: 5 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 25 10:34:00 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 25 Aug 2016 10:34:00 +0000 Subject: [MERGED] osmo-pcu[master]: Add data structure to handle SPB for EGPRS DL In-Reply-To: References: Message-ID: arvind.sirsikar has submitted this change and it was merged. Change subject: Add data structure to handle SPB for EGPRS DL ...................................................................... Add data structure to handle SPB for EGPRS DL Modify the header files with necessary data structure to handle Split block for EGPRS DL TBF. The EGPRS resegmentation feature allows PCU to retransmit RLC blocks of HeaderType1, HeaderType2 by segmenting them to 2 HeaderType3 blocks(Example MCS5 will be retransmitted as 2 MCS2 blocks). Table 10.4.8b.2 of 44.060 explains the possible values of SPB in HeadrType3 for DL direction. The PCU decides to retransmit the blocks by resegmenting it based on Table 8.1.1.1 of 44.060. The retransmission MCS is calculated based on current MCS of the Block and demanded MCS by PCU. Section 10.3a.3.3 of 44.060 shows the HeadrType3 with SPB field present in it Change-Id: I57673e53a9da2affa7e8aaa6551ac4b271c3d525 --- M src/bts.h M src/rlc.h 2 files changed, 45 insertions(+), 4 deletions(-) Approvals: Neels Hofmeyr: Looks good to me, but someone else must approve Jenkins Builder: Verified Holger Freyther: Looks good to me, approved diff --git a/src/bts.h b/src/bts.h index 807ce08..38896c8 100644 --- a/src/bts.h +++ b/src/bts.h @@ -186,6 +186,10 @@ uint8_t alpha, gamma; uint8_t egprs_enabled; uint32_t dl_tbf_idle_msec; /* hold time for idle DL TBFs */ + + /* 0 to support resegmentation in DL, 1 for no reseg */ + uint8_t dl_arq_type; + uint32_t ms_idle_sec; uint8_t cs_adj_enabled; uint8_t cs_adj_upper_limit; diff --git a/src/rlc.h b/src/rlc.h index bf2d70a..b1a1fba 100644 --- a/src/rlc.h +++ b/src/rlc.h @@ -84,6 +84,39 @@ }; /* + * EGPRS resegment status information for DL + * When only first segment is sent, bsn state + * will be set to EGPRS_RESEG_FIRST_SEG_SENT and when + * second segment is sent the state will be + * set to EGPRS_RESEG_SECOND_SEG_SENT. + * EGPRS_RESEG_DL_INVALID is set to 8 considering there is a scope for + * 3rd segment according to Table 10.4.8b.2 of 44.060 + * The EGPRS resegmentation feature allows PCU to retransmit + * RLC blocks of HeaderType1, HeaderType2 by segmenting + * them to 2 HeaderType3 blocks(Example MCS5 will be + * retransmitted as 2 MCS2 blocks). Table 10.4.8b.2 of 44.060 + * explains the possible values of SPB in HeadrType3 for DL + * direction.The PCU decides to retransmit the + * blocks by resegmenting it based on Table 8.1.1.1 of 44.060. + * The retransmission MCS is calculated based on current MCS of + * the Block and demanded MCS by PCU. Section 10.3a.3.3 of 44.060 + * shows the HeadrType3 with SPB field present in it + */ +enum egprs_rlc_dl_reseg_bsn_state { + EGPRS_RESEG_DL_DEFAULT = 0, + EGPRS_RESEG_FIRST_SEG_SENT = 0x01, + EGPRS_RESEG_SECOND_SEG_SENT = 0x02, + EGPRS_RESEG_DL_INVALID = 0x08 +}; + +/* Table 10.4.8b.2 of 44.060 */ +enum egprs_rlcmac_dl_spb { + EGPRS_RLCMAC_DL_NO_RETX = 0, + EGPRS_RLCMAC_DL_FIRST_SEG = 2, + EGPRS_RLCMAC_DL_SEC_SEG = 3, +}; + +/* * Valid puncturing scheme values * TS 44.060 10.4.8a.3.1, 10.4.8a.2.1, 10.4.8a.1.1 */ @@ -140,10 +173,7 @@ /* holds the current status of the block w.r.t UL/DL split blocks */ union split_block_status { egprs_rlc_ul_reseg_bsn_state block_status_ul; - /* - * TODO: DL split block status need to be supported - * for EGPRS DL - */ + egprs_rlc_dl_reseg_bsn_state block_status_dl; }; struct gprs_rlc_data { @@ -168,6 +198,13 @@ GprsCodingScheme cs_current_trans; GprsCodingScheme cs_last; + /* + * The MCS of initial transmission of a BSN + * This variable is used for split block + * processing in DL + */ + GprsCodingScheme cs_init; + /* puncturing scheme value to be used for next transmission*/ enum egprs_puncturing_values next_ps; -- To view, visit https://gerrit.osmocom.org/654 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I57673e53a9da2affa7e8aaa6551ac4b271c3d525 Gerrit-PatchSet: 7 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Thu Aug 25 10:34:53 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 25 Aug 2016 10:34:53 +0000 Subject: [PATCH] osmo-pcu[master]: Revert "Add data structure to handle SPB for EGPRS DL" Message-ID: Review at https://gerrit.osmocom.org/768 Revert "Add data structure to handle SPB for EGPRS DL" This reverts commit e6cadb4e3ccd05673fd9d33f8a445dd54be6006b. Change-Id: Id446f4c5dea83152f2465f01884b64ee8e52e07d --- M src/bts.h M src/rlc.h 2 files changed, 4 insertions(+), 45 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/68/768/1 diff --git a/src/bts.h b/src/bts.h index 38896c8..807ce08 100644 --- a/src/bts.h +++ b/src/bts.h @@ -186,10 +186,6 @@ uint8_t alpha, gamma; uint8_t egprs_enabled; uint32_t dl_tbf_idle_msec; /* hold time for idle DL TBFs */ - - /* 0 to support resegmentation in DL, 1 for no reseg */ - uint8_t dl_arq_type; - uint32_t ms_idle_sec; uint8_t cs_adj_enabled; uint8_t cs_adj_upper_limit; diff --git a/src/rlc.h b/src/rlc.h index b1a1fba..bf2d70a 100644 --- a/src/rlc.h +++ b/src/rlc.h @@ -84,39 +84,6 @@ }; /* - * EGPRS resegment status information for DL - * When only first segment is sent, bsn state - * will be set to EGPRS_RESEG_FIRST_SEG_SENT and when - * second segment is sent the state will be - * set to EGPRS_RESEG_SECOND_SEG_SENT. - * EGPRS_RESEG_DL_INVALID is set to 8 considering there is a scope for - * 3rd segment according to Table 10.4.8b.2 of 44.060 - * The EGPRS resegmentation feature allows PCU to retransmit - * RLC blocks of HeaderType1, HeaderType2 by segmenting - * them to 2 HeaderType3 blocks(Example MCS5 will be - * retransmitted as 2 MCS2 blocks). Table 10.4.8b.2 of 44.060 - * explains the possible values of SPB in HeadrType3 for DL - * direction.The PCU decides to retransmit the - * blocks by resegmenting it based on Table 8.1.1.1 of 44.060. - * The retransmission MCS is calculated based on current MCS of - * the Block and demanded MCS by PCU. Section 10.3a.3.3 of 44.060 - * shows the HeadrType3 with SPB field present in it - */ -enum egprs_rlc_dl_reseg_bsn_state { - EGPRS_RESEG_DL_DEFAULT = 0, - EGPRS_RESEG_FIRST_SEG_SENT = 0x01, - EGPRS_RESEG_SECOND_SEG_SENT = 0x02, - EGPRS_RESEG_DL_INVALID = 0x08 -}; - -/* Table 10.4.8b.2 of 44.060 */ -enum egprs_rlcmac_dl_spb { - EGPRS_RLCMAC_DL_NO_RETX = 0, - EGPRS_RLCMAC_DL_FIRST_SEG = 2, - EGPRS_RLCMAC_DL_SEC_SEG = 3, -}; - -/* * Valid puncturing scheme values * TS 44.060 10.4.8a.3.1, 10.4.8a.2.1, 10.4.8a.1.1 */ @@ -173,7 +140,10 @@ /* holds the current status of the block w.r.t UL/DL split blocks */ union split_block_status { egprs_rlc_ul_reseg_bsn_state block_status_ul; - egprs_rlc_dl_reseg_bsn_state block_status_dl; + /* + * TODO: DL split block status need to be supported + * for EGPRS DL + */ }; struct gprs_rlc_data { @@ -197,13 +167,6 @@ */ GprsCodingScheme cs_current_trans; GprsCodingScheme cs_last; - - /* - * The MCS of initial transmission of a BSN - * This variable is used for split block - * processing in DL - */ - GprsCodingScheme cs_init; /* puncturing scheme value to be used for next transmission*/ enum egprs_puncturing_values next_ps; -- To view, visit https://gerrit.osmocom.org/768 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Id446f4c5dea83152f2465f01884b64ee8e52e07d Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Thu Aug 25 10:34:52 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 25 Aug 2016 10:34:52 +0000 Subject: osmo-pcu[master]: Revert "Add data structure to handle SPB for EGPRS DL" In-Reply-To: References: Message-ID: arvind.sirsikar has reverted this change. Change subject: Revert "Add data structure to handle SPB for EGPRS DL" ...................................................................... Uploaded patch set 1. -- To view, visit https://gerrit.osmocom.org/768 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: revert Gerrit-Change-Id: Id446f4c5dea83152f2465f01884b64ee8e52e07d Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Thu Aug 25 10:37:21 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 25 Aug 2016 10:37:21 +0000 Subject: [ABANDON] osmo-pcu[master]: Revert "Add data structure to handle SPB for EGPRS DL" In-Reply-To: References: Message-ID: arvind.sirsikar has abandoned this change. Change subject: Revert "Add data structure to handle SPB for EGPRS DL" ...................................................................... Abandoned -- To view, visit https://gerrit.osmocom.org/768 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: abandon Gerrit-Change-Id: Id446f4c5dea83152f2465f01884b64ee8e52e07d Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Thu Aug 25 10:41:55 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 25 Aug 2016 10:41:55 +0000 Subject: osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: Patch Set 23: Verified+1 -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 23 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 25 10:41:58 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 25 Aug 2016 10:41:58 +0000 Subject: [MERGED] osmo-pcu[master]: Modify EGPRS DL TBF flow to support SPB In-Reply-To: References: Message-ID: arvind.sirsikar has submitted this change and it was merged. Change subject: Modify EGPRS DL TBF flow to support SPB ...................................................................... Modify EGPRS DL TBF flow to support SPB Modify the EGPRS DL TBF flow to support Split block during Retx. This patch will also Upgrade the test suite with test cases to validate the EGPRS Downlink SPB for Retransmission Scenarios like MCS6->MCS3, MCS4->MCS1, MCS5->MCS2, MCS9->MCS3 MCS7->MCS2, MCS8->MCS3 have been simulated and Integration tested in NuRAN 1.0 hardware thoroughly. Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 --- M src/gprs_coding_scheme.h M src/pcu_main.cpp M src/pcu_vty.c M src/rlc.cpp M src/rlc.h M src/tbf.h M src/tbf_dl.cpp M tests/edge/EdgeTest.cpp M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 11 files changed, 958 insertions(+), 80 deletions(-) Approvals: Neels Hofmeyr: Looks good to me, approved arvind.sirsikar: Verified diff --git a/src/gprs_coding_scheme.h b/src/gprs_coding_scheme.h index 60a8e79..3b15372 100644 --- a/src/gprs_coding_scheme.h +++ b/src/gprs_coding_scheme.h @@ -113,7 +113,8 @@ static const char *modeName(Mode mode); static Scheme get_retx_mcs(const GprsCodingScheme mcs, - const GprsCodingScheme retx_mcs); + const GprsCodingScheme retx_mcs, + const unsigned arq_type); static enum Scheme egprs_mcs_retx_tbl[MAX_NUM_ARQ] [MAX_NUM_MCS][MAX_NUM_MCS]; @@ -232,8 +233,9 @@ } inline GprsCodingScheme::Scheme GprsCodingScheme::get_retx_mcs( const GprsCodingScheme mcs, - const GprsCodingScheme demanded_mcs) + const GprsCodingScheme demanded_mcs, + const unsigned arq_type) { - return egprs_mcs_retx_tbl[EGPRS_ARQ2][mcs.to_num() - 1] + return egprs_mcs_retx_tbl[arq_type][mcs.to_num() - 1] [demanded_mcs.to_num() - 1]; } diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2d86cda..e34d534 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -210,6 +210,12 @@ bts->dl_tbf_idle_msec = 2000; bts->llc_idle_ack_csec = 10; + /* + * By default resegmentation is supported in DL + * can also be configured through VTY + */ + bts->dl_arq_type = EGPRS_ARQ1; + msgb_set_talloc_ctx(tall_pcu_ctx); osmo_init_logging(&gprs_log_info); diff --git a/src/pcu_vty.c b/src/pcu_vty.c index ef48027..535d512 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -129,6 +129,10 @@ vty_out(vty, " window-size %d %d%s", bts->ws_base, bts->ws_pdch, VTY_NEWLINE); + if (bts->dl_arq_type) + vty_out(vty, " egprs dl arq-type arq2%s", + VTY_NEWLINE); + if (bts->force_llc_lifetime == 0xffff) vty_out(vty, " queue lifetime infinite%s", VTY_NEWLINE); else if (bts->force_llc_lifetime) @@ -470,6 +474,25 @@ bts->max_mcs_dl = 0; bts->max_mcs_ul = 0; + + return CMD_SUCCESS; +} + +#define DL_STR "downlink specific configuration\n" + +DEFUN(cfg_pcu_dl_arq_type, + cfg_pcu_dl_arq_cmd, + "egprs dl arq-type (spb|arq2)", + EGPRS_STR DL_STR "ARQ options\n" + "enable SPB(ARQ1) support\n" + "enable ARQ2 support") +{ + struct gprs_rlcmac_bts *bts = bts_main_data(); + + if (!strcmp(argv[0], "arq2")) + bts->dl_arq_type = 1; + else + bts->dl_arq_type = 0; return CMD_SUCCESS; } @@ -948,6 +971,7 @@ install_element(PCU_NODE, &cfg_pcu_no_cs_downgrade_thrsh_cmd); install_element(PCU_NODE, &cfg_pcu_cs_lqual_ranges_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_cmd); + install_element(PCU_NODE, &cfg_pcu_dl_arq_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_max_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_max_cmd); diff --git a/src/rlc.cpp b/src/rlc.cpp index 6770043..e69d1fc 100644 --- a/src/rlc.cpp +++ b/src/rlc.cpp @@ -285,7 +285,8 @@ } static void gprs_rlc_data_header_init(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding, unsigned int header_bits) + GprsCodingScheme cs, bool with_padding, unsigned int header_bits, + const unsigned int spb) { unsigned int i; unsigned int padding_bits = with_padding ? cs.optionalPaddingBits() : 0; @@ -300,7 +301,7 @@ for (i = 0; i < rlc->num_data_blocks; i++) { gprs_rlc_data_block_info_init(&rlc->block_info[i], cs, - with_padding); + with_padding, spb); rlc->data_offs_bits[i] = header_bits + padding_bits + @@ -310,21 +311,25 @@ } void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsDL()); + cs.numDataHeaderBitsDL(), spb); } void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding) { + /* + * last parameter is sent as 0 since common function used + * for both DL and UL + */ return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsUL()); + cs.numDataHeaderBitsUL(), 0); } void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { unsigned int data_len = cs.maxDataBlockBytes(); if (with_padding) @@ -336,7 +341,7 @@ rdbi->e = 1; rdbi->cv = 15; rdbi->pi = 0; - rdbi->spb = 0; + rdbi->spb = spb; } unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, @@ -411,8 +416,18 @@ enum egprs_puncturing_values gprs_get_punct_scheme( enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current) + const GprsCodingScheme &cs_current, + const enum egprs_rlcmac_dl_spb spb) { + + /* + * 10.4.8b of TS 44.060 + * If it is second segment of the block + * dont change the puncturing scheme + */ + if (spb == EGPRS_RLCMAC_DL_SEC_SEG) + return punct; + /* TS 44.060 9.3.2.1.1 */ if ((GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS9) && (GprsCodingScheme::Scheme(cs_current) == GprsCodingScheme::MCS6)) { diff --git a/src/rlc.h b/src/rlc.h index b1a1fba..b693418 100644 --- a/src/rlc.h +++ b/src/rlc.h @@ -213,18 +213,19 @@ }; void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding); void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, enum egprs_puncturing_values punct, enum egprs_puncturing_values punct2, int with_padding); void gprs_rlc_mcs_cps_decode(unsigned int cps, GprsCodingScheme cs, int *punct, int *punct2, int *with_padding); enum egprs_puncturing_values gprs_get_punct_scheme(enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current_trans); + const GprsCodingScheme &cs_current_trans, + const enum egprs_rlcmac_dl_spb spb); void gprs_update_punct_scheme(enum egprs_puncturing_values *punct, const GprsCodingScheme &cs); /* diff --git a/src/tbf.h b/src/tbf.h index 1bd7878..2a1bfe8 100644 --- a/src/tbf.h +++ b/src/tbf.h @@ -421,6 +421,11 @@ int analyse_errors(char *show_rbb, uint8_t ssn, ana_result *res); void schedule_next_frame(); + enum egprs_rlc_dl_reseg_bsn_state egprs_dl_get_data + (int bsn, uint8_t **block_data); + unsigned int get_egprs_dl_spb_status(int bsn); + enum egprs_rlcmac_dl_spb get_egprs_dl_spb(int bsn); + struct osmo_timer_list m_llc_timer; }; diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp index 07a747a..a24cc21 100644 --- a/src/tbf_dl.cpp +++ b/src/tbf_dl.cpp @@ -375,21 +375,28 @@ return -1; if (is_egprs_enabled()) { + /* Table 8.1.1.2 and Table 8.1.1.1 of 44.060 */ m_rlc.block(bsn)->cs_current_trans = - GprsCodingScheme::get_retx_mcs( - m_rlc.block(bsn)->cs_last, ms()->current_cs_dl()); + GprsCodingScheme::get_retx_mcs( + m_rlc.block(bsn)->cs_init, + ms()->current_cs_dl(), + bts->bts_data()->dl_arq_type); LOGP(DRLCMACDL, LOGL_DEBUG, - "- current_cs_dl(%d) demanded_mcs(%d) cs_trans(%d)\n", - m_rlc.block(bsn)->cs_last.to_num(), - ms()->current_cs_dl().to_num(), - m_rlc.block(bsn)->cs_current_trans.to_num()); + "- initial_cs_dl(%d) last_mcs(%d)" + " demanded_mcs(%d) cs_trans(%d)" + " arq_type(%d) bsn(%d)\n", + m_rlc.block(bsn)->cs_init.to_num(), + m_rlc.block(bsn)->cs_last.to_num(), + ms()->current_cs_dl().to_num(), + m_rlc.block(bsn)->cs_current_trans.to_num(), + bts->bts_data()->dl_arq_type, bsn); /* TODO: Need to remove this check when MCS-8 -> MCS-6 * transistion is handled. * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 */ - if (m_rlc.block(bsn)->cs_last == GprsCodingScheme::MCS8) + if (m_rlc.block(bsn)->cs_init == GprsCodingScheme::MCS8) m_rlc.block(bsn)->cs_current_trans = GprsCodingScheme::MCS8; } else @@ -523,6 +530,11 @@ data = rlc_data->prepare(block_data_len); rlc_data->cs_last = cs; rlc_data->cs_current_trans = cs; + + /* Initialise the variable related to DL SPB */ + rlc_data->spb_status.block_status_dl = EGPRS_RESEG_DL_DEFAULT; + rlc_data->cs_init = cs; + rlc_data->len = block_data_len; rdbi = &(rlc_data->block_info); @@ -616,7 +628,8 @@ unsigned num_bsns; enum egprs_puncturing_values punct[ARRAY_SIZE(rlc.block_info)]; bool need_padding = false; - + enum egprs_rlcmac_dl_spb spb = EGPRS_RLCMAC_DL_NO_RETX; + unsigned int spb_status = get_egprs_dl_spb_status(index); /* * TODO: This is an experimental work-around to put 2 BSN into * MSC-7 to MCS-9 encoded messages. It just sends the same BSN @@ -626,6 +639,7 @@ * the current limit. */ cs = m_rlc.block(index)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(index)->cs_init; bsns[0] = index; num_bsns = 1; @@ -634,7 +648,17 @@ num_bsns += 1; } - if (num_bsns == 1) { + /* + * if the intial mcs is 8 and retransmission mcs is either 6 or 3 + * we have to include the padding of 6 octets in first segment + */ + if ((GprsCodingScheme::Scheme(cs_init) == GprsCodingScheme::MCS8) && + (GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS6 || + GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS3)) { + if (spb_status == EGPRS_RESEG_DL_DEFAULT || + spb_status == EGPRS_RESEG_SECOND_SEG_SENT) + need_padding = true; + } else if (num_bsns == 1) { /* TODO: remove the conditional when MCS-6 padding isn't * failing to be decoded by MEs anymore */ /* TODO: support of MCS-8 -> MCS-6 transition should be @@ -646,7 +670,14 @@ cs.decToSingleBlock(&need_padding); } - gprs_rlc_data_info_init_dl(&rlc, cs, need_padding); + spb = get_egprs_dl_spb(index); + + LOGP(DRLCMACDL, LOGL_DEBUG, "- need_padding %d spb_status %d spb %d" + "(BSN1 %d BSN2 %d)\n", + need_padding, + spb_status, spb, index, index2); + + gprs_rlc_data_info_init_dl(&rlc, cs, need_padding, spb); rlc.usf = 7; /* will be set at scheduler */ rlc.pr = 0; /* FIXME: power reduction */ @@ -665,10 +696,9 @@ data_block_idx++) { int bsn; - GprsCodingScheme cs_enc; uint8_t *block_data; gprs_rlc_data_block_info *rdbi, *block_info; - enum egprs_puncturing_values punct_scheme; + enum egprs_rlc_dl_reseg_bsn_state reseg_status; /* Check if there are more blocks than BSNs */ if (data_block_idx < num_bsns) @@ -676,38 +706,43 @@ else bsn = bsns[0]; - cs_enc = m_rlc.block(bsn)->cs_current_trans; - /* get data and header from current block */ - block_data = m_rlc.block(bsn)->block; - /* Get current puncturing scheme from block */ - punct_scheme = gprs_get_punct_scheme( + + m_rlc.block(bsn)->next_ps = gprs_get_punct_scheme( m_rlc.block(bsn)->next_ps, - m_rlc.block(bsn)->cs_last, cs); + m_rlc.block(bsn)->cs_last, cs, spb); if (cs.isEgprs()) { - OSMO_ASSERT(punct_scheme >= EGPRS_PS_1); - OSMO_ASSERT(punct_scheme <= EGPRS_PS_3); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps >= EGPRS_PS_1); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps <= EGPRS_PS_3); } - punct[data_block_idx] = punct_scheme; + punct[data_block_idx] = m_rlc.block(bsn)->next_ps; rdbi = &rlc.block_info[data_block_idx]; block_info = &m_rlc.block(bsn)->block_info; - if(rdbi->data_len != m_rlc.block(bsn)->len) { - LOGP(DRLCMACDL, LOGL_ERROR, - "ERROR: Expected len = %d for %s instead of " - "%d in data unit %d (BSN %d, %s)\n", - rdbi->data_len, cs.name(), m_rlc.block(bsn)->len, - data_block_idx, bsn, cs_enc.name()); - OSMO_ASSERT(rdbi->data_len == m_rlc.block(bsn)->len); - } - - /* TODO: Need to handle 2 same bsns - * in header type 1 + /* + * get data and header from current block + * function returns the reseg status */ - gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, - cs); + reseg_status = egprs_dl_get_data(bsn, &block_data); + m_rlc.block(bsn)->spb_status.block_status_dl = reseg_status; + + /* + * If it is first segment of the split block set the state of + * bsn to nacked. If it is the first segment dont update the + * next ps value of bsn. since next segment also needs same cps + */ + if (spb == EGPRS_RLCMAC_DL_FIRST_SEG) + m_window.m_v_b.mark_nacked(bsn); + else { + /* + * TODO: Need to handle 2 same bsns + * in header type 1 + */ + gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, + cs); + } m_rlc.block(bsn)->cs_last = cs; rdbi->e = block_info->e; @@ -1169,3 +1204,118 @@ keep_time_frames = msecs_to_frames(bts_data()->dl_tbf_idle_msec); return frames_since_last_drain(fn) <= keep_time_frames; } + +/* + * This function returns the pointer to data which needs + * to be copied. Also updates the status of the block related to + * Split block handling in the RLC/MAC block. + */ +enum egprs_rlc_dl_reseg_bsn_state + gprs_rlcmac_dl_tbf::egprs_dl_get_data(int bsn, uint8_t **block_data) +{ + gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state *block_status_dl = + &rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + *block_data = &rlc_data->block[0]; + + /* + * Table 10.3a.0.1 of 44.060 + * MCS6,9: second segment starts at 74/2 = 37 + * MCS5,7: second segment starts at 56/2 = 28 + * MCS8: second segment starts at 31 + * MCS4: second segment starts at 44/2 = 22 + */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + if (*block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + switch (GprsCodingScheme::Scheme(cs_init)) { + case GprsCodingScheme::MCS6 : + case GprsCodingScheme::MCS9 : + *block_data = &rlc_data->block[37]; + break; + case GprsCodingScheme::MCS7 : + case GprsCodingScheme::MCS5 : + *block_data = &rlc_data->block[28]; + break; + case GprsCodingScheme::MCS8 : + *block_data = &rlc_data->block[31]; + break; + case GprsCodingScheme::MCS4 : + *block_data = &rlc_data->block[22]; + break; + default: + LOGP(DRLCMACDL, LOGL_ERROR, "Software error: " + "--%s hit invalid condition. headerType(%d) " + " blockstatus(%d) cs(%s) PLEASE FIX!\n", name(), + cs_current_trans.headerTypeData(), + *block_status_dl, cs_init.name()); + break; + + } + return EGPRS_RESEG_SECOND_SEG_SENT; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } + } + return EGPRS_RESEG_DL_DEFAULT; +} + +/* + * This function returns the status of split block + * for RLC/MAC block. + */ +unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_status(const int bsn) +{ + const gprs_rlc_data *rlc_data = m_rlc.block(bsn); + + return rlc_data->spb_status.block_status_dl; +} + +/* + * This function returns the spb value to be sent OTA + * for RLC/MAC block. + */ +enum egprs_rlcmac_dl_spb gprs_rlcmac_dl_tbf::get_egprs_dl_spb(const int bsn) +{ + struct gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state block_status_dl = + rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + + /* Table 10.4.8b.1 of 44.060 */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + /* + * if we are sending the second segment the spb should be 3 + * other wise it should be 2 + */ + if (block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + return EGPRS_RLCMAC_DL_SEC_SEG; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RLCMAC_DL_FIRST_SEG; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RLCMAC_DL_FIRST_SEG; + } + } + /* Non SPB cases 0 is reurned */ + return EGPRS_RLCMAC_DL_NO_RETX; +} diff --git a/tests/edge/EdgeTest.cpp b/tests/edge/EdgeTest.cpp index 807102c..9081d4d 100644 --- a/tests/edge/EdgeTest.cpp +++ b/tests/edge/EdgeTest.cpp @@ -517,7 +517,7 @@ /* TS 44.060, B.1 */ cs = GprsCodingScheme::CS4; - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -570,7 +570,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -592,7 +592,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -630,7 +630,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -669,7 +669,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -694,7 +694,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -719,7 +719,7 @@ cs = GprsCodingScheme::CS1; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -740,7 +740,7 @@ OSMO_ASSERT(data[0] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -777,7 +777,7 @@ cs = GprsCodingScheme::MCS4; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -835,7 +835,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -872,7 +872,7 @@ OSMO_ASSERT(data[1] == 0); /* Block 2 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -923,7 +923,7 @@ OSMO_ASSERT(data[3] == 0); /* Block 3 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -967,7 +967,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -993,7 +993,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1020,7 +1020,7 @@ cs = GprsCodingScheme::MCS2; /* Block 1 */ - gprs_rlc_data_block_info_init(&rdbi, cs, false); + gprs_rlc_data_block_info_init(&rdbi, cs, false, 0); num_chunks = 0; write_offset = 0; memset(data, 0, sizeof(data)); @@ -1074,7 +1074,7 @@ block_idx++) { struct gprs_rlc_data_info rlc; - gprs_rlc_data_info_init_dl(&rlc, cs, false); + gprs_rlc_data_info_init_dl(&rlc, cs, false, 0); memset(bits, pattern, sizeof(bits)); Decoding::rlc_copy_to_aligned_buffer( @@ -1118,12 +1118,14 @@ struct gprs_rlc_data_info rlc; printf("=== start %s ===\n", __func__); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::CS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::CS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 24); OSMO_ASSERT(rlc.block_info[0].data_len == 20); - gprs_rlc_data_info_init_dl(&rlc, GprsCodingScheme(GprsCodingScheme::MCS1), false); + gprs_rlc_data_info_init_dl(&rlc, + GprsCodingScheme(GprsCodingScheme::MCS1), false, 0); OSMO_ASSERT(rlc.num_data_blocks == 1); OSMO_ASSERT(rlc.data_offs_bits[0] == 33); OSMO_ASSERT(rlc.block_info[0].data_len == 22); diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 90253b0..5e45506 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -1814,6 +1814,203 @@ } +static void egprs_spb_to_normal_validation(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + uint16_t bsn1, bsn2, bsn3; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + struct gprs_rlc_dl_header_egprs_2 *egprs2; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + if (!(mcs == 6 && demanded_mcs == 3)) + return; + + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + bsn1 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) + || (egprs2->bsn1_lo); + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(bsn1 == 0); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + bsn2 = (egprs3->bsn1_hi << 9) || (egprs3->bsn1_mid << 1) || + (egprs3->bsn1_lo); + OSMO_ASSERT(bsn2 == bsn1); + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->cps == 3); + + /* Handle (MCS3, MCS3) -> MCS6 case */ + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + mcs)); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + egprs2 = (struct gprs_rlc_dl_header_egprs_2 *) msg->data; + + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs2->cps == 0); + bsn3 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) || + (egprs2->bsn1_lo); + OSMO_ASSERT(bsn3 == bsn2); + + tbf_cleanup(dl_tbf); +} +static void establish_and_use_egprs_dl_tbf_for_spb(BTS *the_bts, + int mcs, int demanded_mcs) +{ + uint32_t fn = 0; + gprs_rlcmac_dl_tbf *dl_tbf; + uint8_t block_nr = 0; + int index1 = 0; + uint8_t bn; + struct msgb *msg; + struct gprs_rlc_dl_header_egprs_3 *egprs3; + + printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs); + + dl_tbf = tbf_init(the_bts, mcs); + + /* + * Table 10.4.8a.3.1 of 44.060. + * (MCS7, MCS9) to (MCS2, MCS3) is not handled since it is same as + * (MCS5, MCS6) to (MCS2, MCS3) transition + */ + /* TODO: Need to support of MCS8 -> MCS6 ->MCS3 transistion + * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 + * dated 2016-02-07 23:45:40 (UTC) + */ + if (!(((mcs == 5) && (demanded_mcs == 2)) || + ((mcs == 6) && (demanded_mcs == 3)) || + ((mcs == 4) && (demanded_mcs == 1)))) + return; + + fn = fn_add_blocks(fn, 1); + /* Send first RLC data block BSN 0 */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == mcs); + + dl_tbf->m_window.m_v_b.mark_nacked(0); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + + dl_tbf->ms()->set_current_cs_dl + (static_cast < GprsCodingScheme::Scheme > + (GprsCodingScheme::CS4 + demanded_mcs)); + + fn = fn_add_blocks(fn, 1); + + /* Send first segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_FIRST_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + OSMO_ASSERT(egprs3->spb == 2); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + + /* Send second segment with demanded_mcs */ + msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts); + OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0)); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num() + == demanded_mcs); + OSMO_ASSERT(dl_tbf->m_rlc.block(0)->spb_status.block_status_dl + == EGPRS_RESEG_SECOND_SEG_SENT); + + egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data; + /* Table 10.4.8a.3.1 of 44.060 */ + OSMO_ASSERT(egprs3->spb == 3); + + /* Table 10.4.8a.3.1 of 44.060 */ + switch (demanded_mcs) { + case 3: + OSMO_ASSERT(egprs3->cps == 3); + break; + case 2: + OSMO_ASSERT(egprs3->cps == 9); + break; + case 1: + OSMO_ASSERT(egprs3->cps == 11); + break; + default: + OSMO_ASSERT(false); + break; + } + tbf_cleanup(dl_tbf); +} + static void establish_and_use_egprs_dl_tbf_for_retx(BTS *the_bts, int mcs, int demanded_mcs) { @@ -1972,6 +2169,9 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; + /* First parameter is current MCS, second one is demanded_mcs */ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 6); @@ -1981,6 +2181,38 @@ establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 9); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 7, 5); establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 9, 6); + + printf("=== end %s ===\n", __func__); +} + +static void test_tbf_egprs_spb_dl(void) +{ + BTS the_bts; + gprs_rlcmac_bts *bts; + uint8_t ts_no = 4; + int i, j; + + printf("=== start %s ===\n", __func__); + + bts = the_bts.bts_data(); + bts->cs_downgrade_threshold = 0; + setup_bts(&the_bts, ts_no); + bts->dl_tbf_idle_msec = 200; + bts->egprs_enabled = 1; + + /* ARQ I resegmentation support */ + bts->dl_arq_type = EGPRS_ARQ1; + + /* + * First parameter is current MCS, second one is demanded_mcs + * currently only MCS5->MCS2, MCS6->3, MCS4->MCS1 is tested in UT + * rest scenarios has been integration tested + */ + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 6, 3); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 5, 2); + establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 4, 1); + /* check MCS6->(MCS3+MCS3)->MCS6 case */ + egprs_spb_to_normal_validation(&the_bts, 6, 3); printf("=== end %s ===\n", __func__); } @@ -1999,6 +2231,8 @@ setup_bts(&the_bts, ts_no); bts->dl_tbf_idle_msec = 200; bts->egprs_enabled = 1; + /* ARQ II */ + bts->dl_arq_type = EGPRS_ARQ2; for (i = 1; i <= 9; i++) establish_and_use_egprs_dl_tbf(&the_bts, i); @@ -2071,6 +2305,7 @@ test_tbf_egprs_two_phase_spb(); test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); + test_tbf_egprs_spb_dl(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 3eebe1a..1ba4189 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -72,6 +72,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -81,6 +82,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -157,6 +159,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -166,6 +169,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -242,6 +246,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=4 block=1 data=07 00 01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 @@ -251,6 +256,7 @@ - Sending new block at BSN 1, CS=CS-1 -- Chunk with length 180 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=8 block=2 data=07 00 03 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 @@ -259,6 +265,7 @@ - Sending new block at BSN 2, CS=CS-1 -- Chunk with length 160 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=13 block=3 data=07 00 05 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b @@ -267,6 +274,7 @@ - Sending new block at BSN 3, CS=CS-1 -- Chunk with length 140 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=17 block=4 data=07 00 07 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @@ -275,6 +283,7 @@ - Sending new block at BSN 4, CS=CS-1 -- Chunk with length 120 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=21 block=5 data=07 00 09 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 @@ -283,6 +292,7 @@ - Sending new block at BSN 5, CS=CS-1 -- Chunk with length 100 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=26 block=6 data=07 00 0b 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 @@ -291,6 +301,7 @@ - Sending new block at BSN 6, CS=CS-1 -- Chunk with length 80 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=30 block=7 data=07 00 0d 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b @@ -299,6 +310,7 @@ - Sending new block at BSN 7, CS=CS-1 -- Chunk with length 60 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=34 block=8 data=07 00 0f 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f @@ -307,6 +319,7 @@ - Sending new block at BSN 8, CS=CS-1 -- Chunk with length 40 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=39 block=9 data=07 00 11 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 @@ -315,6 +328,7 @@ - Sending new block at BSN 9, CS=CS-1 -- Chunk with length 20 would exactly fit into space (20): add length header with LI=0, to make frame extend to next block, and we are done data block (BSN 9, CS-1): 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=43 block=10 data=07 00 12 01 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 @@ -326,6 +340,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) (len=200) -- Chunk with length 200 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=47 block=11 data=07 00 14 07 c7 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 @@ -334,6 +349,7 @@ - Sending new block at BSN 11, CS=CS-1 -- Chunk with length 182 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=52 block=0 data=07 00 17 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 @@ -342,6 +358,7 @@ - Sending new block at BSN 12, CS=CS-1 -- Chunk with length 162 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=56 block=1 data=07 00 19 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 @@ -350,6 +367,7 @@ - Sending new block at BSN 13, CS=CS-1 -- Chunk with length 142 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 13, CS-1): 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=60 block=2 data=07 00 1b 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d @@ -358,6 +376,7 @@ - Sending new block at BSN 14, CS=CS-1 -- Chunk with length 122 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=65 block=3 data=07 00 1d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 @@ -366,6 +385,7 @@ - Sending new block at BSN 15, CS=CS-1 -- Chunk with length 102 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=69 block=4 data=07 00 1f 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 @@ -374,6 +394,7 @@ - Sending new block at BSN 16, CS=CS-1 -- Chunk with length 82 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=73 block=5 data=07 00 21 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 @@ -382,6 +403,7 @@ - Sending new block at BSN 17, CS=CS-1 -- Chunk with length 62 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=78 block=6 data=07 00 23 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d @@ -390,6 +412,7 @@ - Sending new block at BSN 18, CS=CS-1 -- Chunk with length 42 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=82 block=7 data=07 00 25 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 @@ -398,6 +421,7 @@ - Sending new block at BSN 19, CS=CS-1 -- Chunk with length 22 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=86 block=8 data=07 00 27 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 @@ -411,6 +435,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=16 data block (BSN 20, CS-1): 0a 41 c6 c7 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -449,6 +474,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 data block (BSN 21, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) @@ -468,6 +494,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)len=19 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 22, CS-1): 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FINISHED) @@ -1481,6 +1508,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 0, CS-1): 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 MSG = 07 00 00 4d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 @@ -1491,6 +1519,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 - Dequeue next LLC for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) (len=19) data block (BSN 1, CS-1): 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 MSG = 07 00 02 4d 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 @@ -1501,6 +1530,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN)len=19 TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FINISHED data block (BSN 2, CS-1): 4d 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling cannot be scheduled in this TS 7 (first control TS 4) @@ -1784,6 +1814,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=10 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 0, CS-4): 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654292 TS 7 @@ -1797,6 +1828,7 @@ TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) downlink (V(A)==0 .. V(S)==1) - Restarting at BSN 0, because all blocks have been transmitted. - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-4): 07 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 01 00 29 52 41 55 5f 41 43 43 45 50 54 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 @@ -2365,6 +2397,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654279 block=10 data=00 00 00 37 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 4c 4c 43 20 50 41 @@ -2384,6 +2417,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654283 block=11 data=00 00 02 1f 43 4b 45 54 20 30 31 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -2406,6 +2440,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654288 block=0 data=00 00 04 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 4c 4c 43 20 @@ -2425,6 +2460,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654292 block=1 data=00 00 06 27 50 41 43 4b 45 54 20 30 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2447,6 +2483,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654296 block=2 data=00 00 08 0e 37 20 30 35 4c 4c 43 20 50 41 43 4b 45 54 20 30 36 4c 4c @@ -2466,6 +2503,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654301 block=3 data=00 00 0a 2f 43 20 50 41 43 4b 45 54 20 30 37 4c 4c 43 20 50 41 43 4b @@ -2488,6 +2526,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 6, CS-1): 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654305 block=4 data=00 00 0c 16 35 45 54 20 30 38 4c 4c 43 20 50 41 43 4b 45 54 20 30 39 @@ -2507,6 +2546,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654309 block=5 data=00 00 0e 37 4c 4c 43 20 50 41 43 4b 45 54 20 31 30 4c 4c 43 20 50 41 @@ -2526,6 +2566,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654314 block=6 data=00 00 10 1f 43 4b 45 54 20 31 31 4c 4c 43 20 50 41 43 4b 45 54 20 31 @@ -2548,6 +2589,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654318 block=7 data=00 00 12 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 31 33 4c 4c 43 20 @@ -2567,6 +2609,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 10, CS-1): 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) msg block (BSN 10, CS-1): 07 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654322 block=8 data=00 00 14 27 50 41 43 4b 45 54 20 31 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2589,6 +2632,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 11, CS-1): 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) msg block (BSN 11, CS-1): 07 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654327 block=9 data=00 00 16 0e 37 20 31 35 4c 4c 43 20 50 41 43 4b 45 54 20 31 36 4c 4c @@ -2608,6 +2652,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 12, CS-1): 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) msg block (BSN 12, CS-1): 07 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654331 block=10 data=00 00 18 2f 43 20 50 41 43 4b 45 54 20 31 37 4c 4c 43 20 50 41 43 4b @@ -2630,6 +2675,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 13, CS-1): 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) msg block (BSN 13, CS-1): 07 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654335 block=11 data=00 00 1a 16 35 45 54 20 31 38 4c 4c 43 20 50 41 43 4b 45 54 20 31 39 @@ -2649,6 +2695,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 14, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) msg block (BSN 14, CS-1): 07 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654340 block=0 data=00 00 1c 37 4c 4c 43 20 50 41 43 4b 45 54 20 32 30 4c 4c 43 20 50 41 @@ -2668,6 +2715,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 15, CS-1): 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) msg block (BSN 15, CS-1): 07 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654344 block=1 data=00 00 1e 1f 43 4b 45 54 20 32 31 4c 4c 43 20 50 41 43 4b 45 54 20 32 @@ -2690,6 +2738,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 16, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) msg block (BSN 16, CS-1): 07 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654348 block=2 data=00 00 20 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 32 33 4c 4c 43 20 @@ -2709,6 +2758,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 17, CS-1): 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) msg block (BSN 17, CS-1): 07 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654353 block=3 data=00 00 22 27 50 41 43 4b 45 54 20 32 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2731,6 +2781,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 18, CS-1): 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) msg block (BSN 18, CS-1): 07 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654357 block=4 data=00 00 24 0e 37 20 32 35 4c 4c 43 20 50 41 43 4b 45 54 20 32 36 4c 4c @@ -2750,6 +2801,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 19, CS-1): 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) msg block (BSN 19, CS-1): 07 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654361 block=5 data=00 00 26 2f 43 20 50 41 43 4b 45 54 20 32 37 4c 4c 43 20 50 41 43 4b @@ -2772,6 +2824,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) data block (BSN 20, CS-1): 16 35 45 54 20 32 38 4c 4c 43 20 50 41 43 4b 45 54 20 32 39 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because 20 blocks sent. TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW): Scheduling polling at FN 2654379 TS 7 @@ -2795,6 +2848,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 21, CS-1): 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) msg block (BSN 21, CS-1): 07 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654370 block=7 data=00 00 2a 37 4c 4c 43 20 50 41 43 4b 45 54 20 33 30 4c 4c 43 20 50 41 @@ -2814,6 +2868,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 22, CS-1): 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) msg block (BSN 22, CS-1): 07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654374 block=8 data=07 00 2c 1f 43 4b 45 54 20 33 31 4c 4c 43 20 50 41 43 4b 45 54 20 33 @@ -2836,6 +2891,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 23, CS-1): 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) msg block (BSN 23, CS-1): 07 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654379 block=9 data=00 00 2e 06 37 32 4c 4c 43 20 50 41 43 4b 45 54 20 33 33 4c 4c 43 20 @@ -2855,6 +2911,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 24, CS-1): 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) msg block (BSN 24, CS-1): 07 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654383 block=10 data=00 00 30 27 50 41 43 4b 45 54 20 33 34 4c 4c 43 20 50 41 43 4b 45 54 @@ -2877,6 +2934,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 25, CS-1): 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 25 BSN2 -1) - Copying data unit 0 (BSN 25) msg block (BSN 25, CS-1): 07 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654387 block=11 data=00 00 32 0e 37 20 33 35 4c 4c 43 20 50 41 43 4b 45 54 20 33 36 4c 4c @@ -2896,6 +2954,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=13) -- Chunk with length 13 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 26, CS-1): 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 26 BSN2 -1) - Copying data unit 0 (BSN 26) msg block (BSN 26, CS-1): 07 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654392 block=0 data=00 00 34 2f 43 20 50 41 43 4b 45 54 20 33 37 4c 4c 43 20 50 41 43 4b @@ -2918,6 +2977,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=13 TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 27, CS-1): 16 35 45 54 20 33 38 4c 4c 43 20 50 41 43 4b 45 54 20 33 39 +- need_padding 0 spb_status 0 spb 0(BSN1 27 BSN2 -1) - Copying data unit 0 (BSN 27) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=FINISHED) @@ -3028,6 +3088,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (20) left in block: copy only remaining space, and we are done data block (BSN 0, CS-1): 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, CS-1): 07 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654405 block=3 data=00 02 01 4c 4c 43 20 50 41 43 4b 45 54 20 30 30 20 28 54 42 46 20 32 @@ -3047,6 +3108,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (18) left in block: copy only remaining space, and we are done data block (BSN 1, CS-1): 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, CS-1): 07 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654409 block=4 data=00 02 02 07 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 31 20 28 54 42 46 @@ -3066,6 +3128,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (16) left in block: copy only remaining space, and we are done data block (BSN 2, CS-1): 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) msg block (BSN 2, CS-1): 07 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654413 block=5 data=00 02 04 0f 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 32 20 28 54 @@ -3085,6 +3148,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (14) left in block: copy only remaining space, and we are done data block (BSN 3, CS-1): 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) msg block (BSN 3, CS-1): 07 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654418 block=6 data=00 02 06 17 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 33 20 @@ -3104,6 +3168,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (12) left in block: copy only remaining space, and we are done data block (BSN 4, CS-1): 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) msg block (BSN 4, CS-1): 07 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654422 block=7 data=00 02 08 1f 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 20 30 @@ -3123,6 +3188,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (10) left in block: copy only remaining space, and we are done data block (BSN 5, CS-1): 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) msg block (BSN 5, CS-1): 07 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654426 block=8 data=00 02 0a 27 34 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b 45 54 @@ -3142,6 +3208,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (8) left in block: copy only remaining space, and we are done data block (BSN 6, CS-1): 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) msg block (BSN 6, CS-1): 07 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654431 block=9 data=00 02 0c 2f 20 30 35 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 43 4b @@ -3161,6 +3228,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (6) left in block: copy only remaining space, and we are done data block (BSN 7, CS-1): 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) msg block (BSN 7, CS-1): 07 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654435 block=10 data=00 02 0e 37 45 54 20 30 36 20 28 54 42 46 20 32 29 4c 4c 43 20 50 41 @@ -3180,6 +3248,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (4) left in block: copy only remaining space, and we are done data block (BSN 8, CS-1): 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) msg block (BSN 8, CS-1): 07 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654439 block=11 data=00 02 10 3f 43 4b 45 54 20 30 37 20 28 54 42 46 20 32 29 4c 4c 43 20 @@ -3199,6 +3268,7 @@ - Dequeue next LLC for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) (len=21) -- Chunk with length 21 larger than space (2) left in block: copy only remaining space, and we are done data block (BSN 9, CS-1): 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) msg block (BSN 9, CS-1): 07 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654444 block=0 data=00 02 12 47 50 41 43 4b 45 54 20 30 38 20 28 54 42 46 20 32 29 4c 4c @@ -3218,6 +3288,7 @@ Complete DL frame for TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW)len=21 TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FLOW) changes state from FLOW to FINISHED data block (BSN 10, CS-1): 4d 43 20 50 41 43 4b 45 54 20 30 39 20 28 54 42 46 20 32 29 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=1 TLLI=0xf1223344 DIR=DL STATE=FINISHED): Scheduling polling at FN 2654461 TS 7 @@ -3698,6 +3769,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 0, MCS-1): 14 15 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3711,6 +3783,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3721,6 +3794,7 @@ - Sending new block at BSN 2, CS=MCS-1 -- Chunk with length 490 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3731,6 +3805,7 @@ - Sending new block at BSN 3, CS=MCS-1 -- Chunk with length 468 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3741,6 +3816,7 @@ - Sending new block at BSN 4, CS=MCS-1 -- Chunk with length 446 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3751,6 +3827,7 @@ - Sending new block at BSN 5, CS=MCS-1 -- Chunk with length 424 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3761,6 +3838,7 @@ - Sending new block at BSN 6, CS=MCS-1 -- Chunk with length 402 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3771,6 +3849,7 @@ - Sending new block at BSN 7, CS=MCS-1 -- Chunk with length 380 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3781,6 +3860,7 @@ - Sending new block at BSN 8, CS=MCS-1 -- Chunk with length 358 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3791,6 +3871,7 @@ - Sending new block at BSN 9, CS=MCS-1 -- Chunk with length 336 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3801,6 +3882,7 @@ - Sending new block at BSN 10, CS=MCS-1 -- Chunk with length 314 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3811,6 +3893,7 @@ - Sending new block at BSN 11, CS=MCS-1 -- Chunk with length 292 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3821,6 +3904,7 @@ - Sending new block at BSN 12, CS=MCS-1 -- Chunk with length 270 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3831,6 +3915,7 @@ - Sending new block at BSN 13, CS=MCS-1 -- Chunk with length 248 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3841,6 +3926,7 @@ - Sending new block at BSN 14, CS=MCS-1 -- Chunk with length 226 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3851,6 +3937,7 @@ - Sending new block at BSN 15, CS=MCS-1 -- Chunk with length 204 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3861,6 +3948,7 @@ - Sending new block at BSN 16, CS=MCS-1 -- Chunk with length 182 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3871,6 +3959,7 @@ - Sending new block at BSN 17, CS=MCS-1 -- Chunk with length 160 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3881,6 +3970,7 @@ - Sending new block at BSN 18, CS=MCS-1 -- Chunk with length 138 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3891,6 +3981,7 @@ - Sending new block at BSN 19, CS=MCS-1 -- Chunk with length 116 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 19, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3901,6 +3992,7 @@ - Sending new block at BSN 20, CS=MCS-1 -- Chunk with length 94 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 20, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 20 BSN2 -1) - Copying data unit 0 (BSN 20) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3911,6 +4003,7 @@ - Sending new block at BSN 21, CS=MCS-1 -- Chunk with length 72 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 21, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 21 BSN2 -1) - Copying data unit 0 (BSN 21) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3921,6 +4014,7 @@ - Sending new block at BSN 22, CS=MCS-1 -- Chunk with length 50 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 22, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 22 BSN2 -1) - Copying data unit 0 (BSN 22) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3931,6 +4025,7 @@ - Sending new block at BSN 23, CS=MCS-1 -- Chunk with length 28 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 23, MCS-1): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 23 BSN2 -1) - Copying data unit 0 (BSN 23) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -3946,6 +4041,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 24, MCS-1): 0c 1d 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 24 BSN2 -1) - Copying data unit 0 (BSN 24) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4006,6 +4102,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=16 data block (BSN 0, MCS-2): 14 21 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4019,6 +4116,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4029,6 +4127,7 @@ - Sending new block at BSN 2, CS=MCS-2 -- Chunk with length 484 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4039,6 +4138,7 @@ - Sending new block at BSN 3, CS=MCS-2 -- Chunk with length 456 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4049,6 +4149,7 @@ - Sending new block at BSN 4, CS=MCS-2 -- Chunk with length 428 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4059,6 +4160,7 @@ - Sending new block at BSN 5, CS=MCS-2 -- Chunk with length 400 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4069,6 +4171,7 @@ - Sending new block at BSN 6, CS=MCS-2 -- Chunk with length 372 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4079,6 +4182,7 @@ - Sending new block at BSN 7, CS=MCS-2 -- Chunk with length 344 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4089,6 +4193,7 @@ - Sending new block at BSN 8, CS=MCS-2 -- Chunk with length 316 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4099,6 +4204,7 @@ - Sending new block at BSN 9, CS=MCS-2 -- Chunk with length 288 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4109,6 +4215,7 @@ - Sending new block at BSN 10, CS=MCS-2 -- Chunk with length 260 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4119,6 +4226,7 @@ - Sending new block at BSN 11, CS=MCS-2 -- Chunk with length 232 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4129,6 +4237,7 @@ - Sending new block at BSN 12, CS=MCS-2 -- Chunk with length 204 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4139,6 +4248,7 @@ - Sending new block at BSN 13, CS=MCS-2 -- Chunk with length 176 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4149,6 +4259,7 @@ - Sending new block at BSN 14, CS=MCS-2 -- Chunk with length 148 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4159,6 +4270,7 @@ - Sending new block at BSN 15, CS=MCS-2 -- Chunk with length 120 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 15, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4169,6 +4281,7 @@ - Sending new block at BSN 16, CS=MCS-2 -- Chunk with length 92 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 16, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 16 BSN2 -1) - Copying data unit 0 (BSN 16) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4179,6 +4292,7 @@ - Sending new block at BSN 17, CS=MCS-2 -- Chunk with length 64 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 17, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 17 BSN2 -1) - Copying data unit 0 (BSN 17) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4189,6 +4303,7 @@ - Sending new block at BSN 18, CS=MCS-2 -- Chunk with length 36 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 18, MCS-2): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 18 BSN2 -1) - Copying data unit 0 (BSN 18) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4204,6 +4319,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=18 data block (BSN 19, MCS-2): 10 25 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 19 BSN2 -1) - Copying data unit 0 (BSN 19) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4264,6 +4380,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=25 data block (BSN 0, MCS-3): 14 33 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4277,6 +4394,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4287,6 +4405,7 @@ - Sending new block at BSN 2, CS=MCS-3 -- Chunk with length 475 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4297,6 +4416,7 @@ - Sending new block at BSN 3, CS=MCS-3 -- Chunk with length 438 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4307,6 +4427,7 @@ - Sending new block at BSN 4, CS=MCS-3 -- Chunk with length 401 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4317,6 +4438,7 @@ - Sending new block at BSN 5, CS=MCS-3 -- Chunk with length 364 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4327,6 +4449,7 @@ - Sending new block at BSN 6, CS=MCS-3 -- Chunk with length 327 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4337,6 +4460,7 @@ - Sending new block at BSN 7, CS=MCS-3 -- Chunk with length 290 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4347,6 +4471,7 @@ - Sending new block at BSN 8, CS=MCS-3 -- Chunk with length 253 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4357,6 +4482,7 @@ - Sending new block at BSN 9, CS=MCS-3 -- Chunk with length 216 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4367,6 +4493,7 @@ - Sending new block at BSN 10, CS=MCS-3 -- Chunk with length 179 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4377,6 +4504,7 @@ - Sending new block at BSN 11, CS=MCS-3 -- Chunk with length 142 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4387,6 +4515,7 @@ - Sending new block at BSN 12, CS=MCS-3 -- Chunk with length 105 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 12, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4397,6 +4526,7 @@ - Sending new block at BSN 13, CS=MCS-3 -- Chunk with length 68 larger than space (37) left in block: copy only remaining space, and we are done data block (BSN 13, MCS-3): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 13 BSN2 -1) - Copying data unit 0 (BSN 13) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4410,6 +4540,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 14, MCS-3): 3f 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 14 BSN2 -1) - Copying data unit 0 (BSN 14) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4425,6 +4556,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=34 data block (BSN 15, MCS-3): 02 45 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 15 BSN2 -1) - Copying data unit 0 (BSN 15) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4485,6 +4617,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=32 data block (BSN 0, MCS-4): 14 41 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4498,6 +4631,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4508,6 +4642,7 @@ - Sending new block at BSN 2, CS=MCS-4 -- Chunk with length 468 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4518,6 +4653,7 @@ - Sending new block at BSN 3, CS=MCS-4 -- Chunk with length 424 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4528,6 +4664,7 @@ - Sending new block at BSN 4, CS=MCS-4 -- Chunk with length 380 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4538,6 +4675,7 @@ - Sending new block at BSN 5, CS=MCS-4 -- Chunk with length 336 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4548,6 +4686,7 @@ - Sending new block at BSN 6, CS=MCS-4 -- Chunk with length 292 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4558,6 +4697,7 @@ - Sending new block at BSN 7, CS=MCS-4 -- Chunk with length 248 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4568,6 +4708,7 @@ - Sending new block at BSN 8, CS=MCS-4 -- Chunk with length 204 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4578,6 +4719,7 @@ - Sending new block at BSN 9, CS=MCS-4 -- Chunk with length 160 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4588,6 +4730,7 @@ - Sending new block at BSN 10, CS=MCS-4 -- Chunk with length 116 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 10, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4598,6 +4741,7 @@ - Sending new block at BSN 11, CS=MCS-4 -- Chunk with length 72 larger than space (44) left in block: copy only remaining space, and we are done data block (BSN 11, MCS-4): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 11 BSN2 -1) - Copying data unit 0 (BSN 11) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4613,6 +4757,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=14 data block (BSN 12, MCS-4): 38 1d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 12 BSN2 -1) - Copying data unit 0 (BSN 12) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4673,6 +4818,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-5): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4686,6 +4832,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4696,6 +4843,7 @@ - Sending new block at BSN 2, CS=MCS-5 -- Chunk with length 456 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4706,6 +4854,7 @@ - Sending new block at BSN 3, CS=MCS-5 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4716,6 +4865,7 @@ - Sending new block at BSN 4, CS=MCS-5 -- Chunk with length 344 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4726,6 +4876,7 @@ - Sending new block at BSN 5, CS=MCS-5 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4736,6 +4887,7 @@ - Sending new block at BSN 6, CS=MCS-5 -- Chunk with length 232 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4746,6 +4898,7 @@ - Sending new block at BSN 7, CS=MCS-5 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4756,6 +4909,7 @@ - Sending new block at BSN 8, CS=MCS-5 -- Chunk with length 120 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 8, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4766,6 +4920,7 @@ - Sending new block at BSN 9, CS=MCS-5 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-5): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 9 BSN2 -1) - Copying data unit 0 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4781,6 +4936,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-5): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4841,6 +4997,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-6): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4854,6 +5011,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4864,6 +5022,7 @@ - Sending new block at BSN 2, CS=MCS-6 -- Chunk with length 438 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 2, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 -1) - Copying data unit 0 (BSN 2) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4874,6 +5033,7 @@ - Sending new block at BSN 3, CS=MCS-6 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 3 BSN2 -1) - Copying data unit 0 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4884,6 +5044,7 @@ - Sending new block at BSN 4, CS=MCS-6 -- Chunk with length 290 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 4, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 -1) - Copying data unit 0 (BSN 4) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4894,6 +5055,7 @@ - Sending new block at BSN 5, CS=MCS-6 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 5 BSN2 -1) - Copying data unit 0 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4904,6 +5066,7 @@ - Sending new block at BSN 6, CS=MCS-6 -- Chunk with length 142 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 6, MCS-6): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 -1) - Copying data unit 0 (BSN 6) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4917,6 +5080,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-6): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 7 BSN2 -1) - Copying data unit 0 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4932,6 +5096,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-6): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -4993,6 +5158,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=44 data block (BSN 0, MCS-7): 14 59 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5002,12 +5168,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(7) last_mcs(5) demanded_mcs(7) cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-7 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5022,6 +5189,7 @@ - Sending new block at BSN 3, CS=MCS-7 -- Chunk with length 400 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5036,6 +5204,7 @@ - Sending new block at BSN 5, CS=MCS-7 -- Chunk with length 288 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5050,6 +5219,7 @@ - Sending new block at BSN 7, CS=MCS-7 -- Chunk with length 176 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5064,6 +5234,7 @@ - Sending new block at BSN 9, CS=MCS-7 -- Chunk with length 64 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 9, MCS-7): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 9) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 9) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5081,6 +5252,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 10, MCS-7): 10 5d 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 10 BSN2 -1) - Copying data unit 0 (BSN 10) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5142,6 +5314,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=56 data block (BSN 0, MCS-8): 14 71 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5152,12 +5325,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(8) demanded_mcs(8) cs_trans(8) +- initial_cs_dl(8) last_mcs(8) demanded_mcs(8) cs_trans(8) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-8 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5172,6 +5346,7 @@ - Sending new block at BSN 3, CS=MCS-8 -- Chunk with length 376 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5186,6 +5361,7 @@ - Sending new block at BSN 5, CS=MCS-8 -- Chunk with length 240 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5200,6 +5376,7 @@ - Sending new block at BSN 7, CS=MCS-8 -- Chunk with length 104 larger than space (68) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-8): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5217,6 +5394,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=30 data block (BSN 8, MCS-8): 48 3d 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Copying data unit 1 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5279,6 +5457,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=62 data block (BSN 0, MCS-9): 14 7d 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5288,12 +5467,13 @@ Received RTS for PDCH: TRX=0 TS=4 FN=8 block_nr=2 scheduling free USF for polling at FN=13 of TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=3 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(9) last_mcs(6) demanded_mcs(9) cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 - Sending new block at BSN 1, CS=MCS-9 - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=512) -- Chunk with length 512 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 1, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5308,6 +5488,7 @@ - Sending new block at BSN 3, CS=MCS-9 -- Chunk with length 364 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 3, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 2 BSN2 3) - Copying data unit 0 (BSN 2) - Copying data unit 1 (BSN 3) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5322,6 +5503,7 @@ - Sending new block at BSN 5, CS=MCS-9 -- Chunk with length 216 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 5, MCS-9): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 +- need_padding 0 spb_status 0 spb 0(BSN1 4 BSN2 5) - Copying data unit 0 (BSN 4) - Copying data unit 1 (BSN 5) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5339,6 +5521,7 @@ -- Empty chunk, added LLC dummy command of size 6, drained_since=0 -- Chunk with length 6 larger than space (5) left in block: copy only remaining space, and we are done data block (BSN 7, MCS-9): 89 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 43 c0 01 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 6 BSN2 7) - Copying data unit 0 (BSN 6) - Copying data unit 1 (BSN 7) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5356,6 +5539,7 @@ Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=71 data block (BSN 8, MCS-9): 02 8f 2b 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b - Restarting at BSN 0, because all blocks have been transmitted (FLOW). +- need_padding 0 spb_status 0 spb 0(BSN1 8 BSN2 -1) - Copying data unit 0 (BSN 8) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). Polling is already scheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) @@ -5402,11 +5586,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(6) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(6) cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5450,11 +5636,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (22) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-1): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 96 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(1) demanded_mcs(1) cs_trans(1) +- initial_cs_dl(1) last_mcs(1) demanded_mcs(1) cs_trans(1) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-1): 07 00 00 98 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5498,11 +5686,13 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (28) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-2): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 92 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) -- current_cs_dl(2) demanded_mcs(2) cs_trans(2) +- initial_cs_dl(2) last_mcs(2) demanded_mcs(2) cs_trans(2) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-2): 07 00 00 94 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5546,6 +5736,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5557,6 +5748,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-5): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5564,10 +5756,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-5): 0f 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7) cs_trans(7) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(5) demanded_mcs(7) cs_trans(7) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(7) cs_trans(7) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-7): 07 00 00 02 c0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 @@ -5612,6 +5805,7 @@ - Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) -- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) @@ -5623,6 +5817,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-6): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS): Scheduling polling at FN 21 TS 4 @@ -5630,10 +5825,11 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=21, TS=4 msg block (BSN 1, MCS-6): 0f 40 00 00 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9) cs_trans(9) arq_type(1) bsn(0) - Resending BSN 0 -- current_cs_dl(6) demanded_mcs(9) cs_trans(9) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(9) cs_trans(9) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) msg block (BSN 0, MCS-9): 07 00 00 02 28 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 @@ -5686,6 +5882,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=10 data block (BSN 1, MCS-7): 58 15 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5694,13 +5891,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-7): 0f 00 00 02 a0 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc 80 55 81 93 a3 b3 c3 d3 e3 f3 03 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5) cs_trans(5) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(7) demanded_mcs(5) cs_trans(5) +- initial_cs_dl(7) last_mcs(7) demanded_mcs(5) cs_trans(5) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-5): 07 40 00 08 56 05 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 92 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5752,6 +5951,7 @@ -- No space left, so we are done. Complete DL frame for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS)len=46 data block (BSN 1, MCS-9): 34 5d 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 1) - Copying data unit 0 (BSN 0) - Copying data unit 1 (BSN 1) - Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent). @@ -5760,13 +5960,15 @@ TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) Scheduled Ack/Nack polling on FN=17, TS=4 msg block (BSN 0, MCS-9): 0f 00 00 02 00 01 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40 44 48 4c 50 54 58 5c 60 64 68 6c 70 74 78 7c 80 84 88 8c 90 94 98 9c a0 a4 a8 ac b0 b4 b8 bc c0 c4 c8 cc d0 d4 d8 dc e0 e4 e8 ec f0 f4 f8 fc 00 05 09 0d 11 15 19 1d 21 25 41 d3 a5 b4 c4 d4 e4 f4 04 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 05 16 26 36 36 04 1c b0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 02 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6) cs_trans(6) arq_type(1) bsn(0) - Resending BSN 0 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) - Copying data unit 0 (BSN 0) msg block (BSN 0, MCS-6): 07 00 00 12 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==2) -- current_cs_dl(9) demanded_mcs(6) cs_trans(6) +- initial_cs_dl(9) last_mcs(9) demanded_mcs(6) cs_trans(6) arq_type(1) bsn(1) - Resending BSN 1 +- need_padding 0 spb_status 0 spb 0(BSN1 1 BSN2 -1) - Copying data unit 0 (BSN 1) msg block (BSN 1, MCS-6): 07 40 00 02 4d 97 d2 12 53 93 d3 13 54 94 d4 14 55 95 d5 15 56 96 d6 16 57 97 d7 17 58 98 d8 d8 10 70 c0 ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca ca 0a TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge @@ -5780,3 +5982,233 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-5 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (56) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-5): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-5): 07 00 00 18 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(5) demanded_mcs(2) cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 d2 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(5) last_mcs(2) demanded_mcs(2) cs_trans(2) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-2): 07 00 00 f2 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-4 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (44) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-4): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-4): 07 00 00 80 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(4) demanded_mcs(1) cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 d6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(4) last_mcs(1) demanded_mcs(1) cs_trans(1) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-1): 07 00 00 f6 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 4a 4c 4e 50 52 54 56 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Assign downlink TS=4 TFI=0 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to FLOW +The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) append +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==0) +- Sending new block at BSN 0, CS=MCS-6 +- Dequeue next LLC for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) (len=100) +-- Chunk with length 100 larger than space (74) left in block: copy only remaining space, and we are done +data block (BSN 0, MCS-6): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 +- need_padding 0 spb_status 0 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(6) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 0 spb 2(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 c6 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 42 44 46 48 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(3) cs_trans(3) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 1 spb 3(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-3): 07 00 00 e6 4a 4c 4e 50 52 54 56 58 5a 5c 5e 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e 80 82 84 86 88 8a 8c 8e 90 92 00 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink (V(A)==0 .. V(S)==1) +- initial_cs_dl(6) last_mcs(3) demanded_mcs(6) cs_trans(6) arq_type(0) bsn(0) +- Resending BSN 0 +- need_padding 0 spb_status 2 spb 0(BSN1 0 BSN2 -1) +- Copying data unit 0 (BSN 0) +msg block (BSN 0, MCS-6): 07 00 00 10 40 80 c0 00 41 81 c1 01 42 82 c2 02 43 83 c3 03 44 84 c4 04 45 85 c5 05 46 86 c6 06 47 87 c7 07 48 88 c8 08 49 89 c9 09 4a 8a ca 0a 4b 8b cb 0b 4c 8c cc 0c 4d 8d cd 0d 4e 8e ce 0e 4f 8f cf 0f 50 90 d0 10 51 91 d1 11 52 12 +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) downlink acknowledge +- Final ACK received. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW EGPRS) changes state from FLOW to WAIT RELEASE +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) starting timer 3193. +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE EGPRS) changes state from WAIT RELEASE to RELEASING +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) free +TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) stopping timer 3193. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0xffeeddcc +********** TBF ends here ********** diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index 0e2edc4..c38417d 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -54,3 +54,9 @@ Testing retx for MCS 7 - 5 Testing retx for MCS 9 - 6 === end test_tbf_egprs_retx_dl === +=== start test_tbf_egprs_spb_dl === +Testing retx for MCS 6 to reseg_mcs 3 +Testing retx for MCS 5 to reseg_mcs 2 +Testing retx for MCS 4 to reseg_mcs 1 +Testing retx for MCS 6 to reseg_mcs 3 +=== end test_tbf_egprs_spb_dl === -- To view, visit https://gerrit.osmocom.org/655 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516 Gerrit-PatchSet: 23 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Thu Aug 25 11:11:30 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 25 Aug 2016 11:11:30 +0000 Subject: [PATCH] osmo-pcu[master]: EGPRS: PUAN encoding: add test case to show wrong urbb_len i... In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/702 to look at the new patch set (#13). EGPRS: PUAN encoding: add test case to show wrong urbb_len issue This patch adds a test case which expects a current bug with EGPRS PUAN encoding when VQ != VR. The test's expectation is corrected along with the bugfix in a subsequent commit Adds test_tbf_puan_urbb_len to describe the following bug: EGPRS PUAN encoding disregards the urbb_len, leading to identical PUAN messages regardless of the urbb_len. Related: OS#1793 Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 --- M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 3 files changed, 304 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/02/702/13 diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 5e45506..8ec1dcc 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -618,6 +618,149 @@ &ulreq, tbf->poll_fn); } +static gprs_rlcmac_ul_tbf *puan_urbb_len_issue(BTS *the_bts, + uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, + uint8_t ms_class, uint8_t egprs_ms_class) +{ + GprsMs *ms; + uint32_t rach_fn = *fn - 51; + uint32_t sba_fn = *fn + 52; + uint8_t trx_no = 0; + int tfi = 0, i = 0; + gprs_rlcmac_ul_tbf *ul_tbf; + struct gprs_rlcmac_pdch *pdch; + gprs_rlcmac_bts *bts; + RlcMacUplink_t ulreq = {0}; + struct pcu_l1_meas meas; + struct gprs_rlc_ul_header_egprs_3 *egprs3 = NULL; + GprsCodingScheme cs; + + meas.set_rssi(31); + bts = the_bts->bts_data(); + + /* needed to set last_rts_fn in the PDCH object */ + request_dl_rlc_block(bts, trx_no, ts_no, fn); + + /* + * simulate RACH, this sends an Immediate + * Assignment Uplink on the AGCH + */ + the_bts->rcv_rach(0x73, rach_fn, qta); + + /* get next free TFI */ + tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1); + + /* fake a resource request */ + ulreq.u.MESSAGE_TYPE = MT_PACKET_RESOURCE_REQUEST; + ulreq.u.Packet_Resource_Request.PayloadType = GPRS_RLCMAC_CONTROL_BLOCK; + ulreq.u.Packet_Resource_Request.ID.UnionType = 1; /* != 0 */ + ulreq.u.Packet_Resource_Request.ID.u.TLLI = tlli; + ulreq.u.Packet_Resource_Request.Exist_MS_Radio_Access_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + Count_MS_RA_capability_value = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Exist_Multislot_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + Exist_GPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + GPRS_multislot_class = ms_class; + if (egprs_ms_class) { + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Multislot_capability.Exist_EGPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Multislot_capability.EGPRS_multislot_class = ms_class; + } + + send_ul_mac_block(the_bts, trx_no, ts_no, &ulreq, sba_fn); + + /* check the TBF */ + ul_tbf = the_bts->ul_tbf_by_tfi(tfi, trx_no, ts_no); + OSMO_ASSERT(ul_tbf); + OSMO_ASSERT(ul_tbf->ta() == qta / 4); + + /* send packet uplink assignment */ + *fn = sba_fn; + request_dl_rlc_block(ul_tbf, fn); + + /* send real acknowledgement */ + send_control_ack(ul_tbf); + + check_tbf(ul_tbf); + /* send fake data */ + uint8_t data_msg[42] = { + 0xf << 2, /* GPRS_RLCMAC_DATA_BLOCK << 6, CV = 15 */ + tfi << 1, + 1, /* BSN:7, E:1 */ + }; + + pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no]; + pdch->rcv_block(&data_msg[0], 23, *fn, &meas); + + ms = the_bts->ms_by_tlli(tlli); + OSMO_ASSERT(ms != NULL); + OSMO_ASSERT(ms->ta() == qta/4); + OSMO_ASSERT(ms->ul_tbf() == ul_tbf); + + /* + * TS 44.060, B.8.1 + * first seg received first, later second seg + */ + cs = GprsCodingScheme::MCS3; + egprs3 = (struct gprs_rlc_ul_header_egprs_3 *) data_msg; + egprs3->si = 0; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 1; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 0; + egprs3->pi = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + struct msgb *msg1 = ul_tbf->create_ul_ack(*fn, ts_no); + + OSMO_ASSERT(!strcmp(osmo_hexdump(msg1->data, msg1->data_len), + "40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b " + )); + + egprs3->si = 0; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 4; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + msg1 = ul_tbf->create_ul_ack(*fn, ts_no); + + /* TODO: Need to modify the assert */ + OSMO_ASSERT(!strcmp(osmo_hexdump(msg1->data, msg1->data_len), + "40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b " + )); + + return ul_tbf; +} + static gprs_rlcmac_ul_tbf *establish_ul_tbf_two_phase_spb(BTS *the_bts, uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, uint8_t ms_class, uint8_t egprs_ms_class) @@ -1631,6 +1774,41 @@ gprs_bssgp_destroy(); } +static void test_tbf_puan_urbb_len(void) +{ + BTS the_bts; + int ts_no = 7; + uint32_t fn = 2654218; + uint16_t qta = 31; + uint32_t tlli = 0xf1223344; + const char *imsi = "0011223344"; + uint8_t ms_class = 1; + uint8_t egprs_ms_class = 1; + gprs_rlcmac_ul_tbf *ul_tbf; + GprsMs *ms; + uint8_t test_data[256]; + + printf("=== start %s ===\n", __func__); + + memset(test_data, 1, sizeof(test_data)); + + setup_bts(&the_bts, ts_no, 4); + the_bts.bts_data()->initial_mcs_dl = 9; + the_bts.bts_data()->egprs_enabled = 1; + + ul_tbf = puan_urbb_len_issue(&the_bts, ts_no, tlli, &fn, qta, + ms_class, egprs_ms_class); + + ms = ul_tbf->ms(); + fprintf(stderr, "Got '%s', TA=%d\n", ul_tbf->name(), ul_tbf->ta()); + fprintf(stderr, + "Got MS: TLLI = 0x%08x, TA = %d\n", ms->tlli(), ms->ta()); + + send_dl_data(&the_bts, tlli, imsi, test_data, sizeof(test_data)); + + printf("=== end %s ===\n", __func__); +} + static void test_tbf_egprs_two_phase_spb(void) { BTS the_bts; @@ -2306,6 +2484,7 @@ test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); test_tbf_egprs_spb_dl(); + test_tbf_puan_urbb_len(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 1ba4189..c3a7f20 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -6212,3 +6212,126 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654218 block=8 data=47 94 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +MS requests UL TBF on RACH, so we provide one: +MS requests single block allocation +RX: [PCU <- BTS] RACH qbit-ta=31 ra=0x73, Fn=2654167 (17,25,9), SBFn=2654270 +TX: Immediate Assignment Uplink (AGCH) + - TRX=0 (0) TS=7 TA=7 TSC=0 TFI=-1 USF=7 +Sending data request: trx=0 ts=0 sapi=2 arfcn=0 fn=0 block=0 data=2d 06 3f 10 0f 00 00 73 8b 29 07 00 c0 0c 5a 43 2b 2b 2b 2b 2b 2b 2b +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +MS requests UL TBF in packet resource request of single block, so we provide one: +MS supports EGPRS multislot class 1. +********** TBF starts here ********** +Allocating UL TBF: MS_CLASS=1/1 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 1 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 1 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign uplink TS=7 TFI=0 USF=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 00 +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=ASSIGN EGPRS) starting timer 3169. +Modifying MS object, UL TLLI: 0x00000000 -> 0xf1223344, not yet confirmed +Modifying MS object, TLLI = 0xf1223344, TA 0 -> 7 +Change control TS to 7 until assinment is complete. +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS)s start Packet Uplink Assignment (PACCH) ++++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++ +------------------------- TX : Packet Uplink Assignment ------------------------- +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS): Scheduling polling at FN 2654283 TS 7 +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS) changes state from ASSIGN to WAIT ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Scheduled UL Assignment polling on FN=2654283, TS=7 +Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) (TRX=0, TS=7) +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654270 block=8 data=4f 28 5e 24 46 68 90 f8 0a 39 00 00 88 00 08 2b 2b 2b 2b 2b 2b 2b 2b +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Packet Control Ack +TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) changes state from WAIT ASSIGN to FLOW +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=0 .. V(R)=0) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got CS-1 RLC data block: CV=15, BSN=0, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 0 storing in window (0..63) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 1 +- Taking block 0 out, raising V(Q) to 1 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=0 CV=15 +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1d 08 40 c1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=0, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=1) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=1, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 1 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 2 +- Taking block 1 out, raising V(Q) to 2 +- Assembling frames: (len=37) +-- Frame 1 starts at offset 0, length=37, is_complete=0 +- No gaps in received block, last block: BSN=1 CV=7 +Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) + - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 2, BOW, EOW +Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1d 20 40 c1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=0, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=2 .. V(R)=2) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=4, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 4 storing in window (2..65) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 5 +Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) + - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 5, BOW, EOW +Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got 'TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS)', TA=7 +Got MS: TLLI = 0xf1223344, TA = 7 +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=1/1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign downlink TS=7 TFI=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0xf1223344, TBF = TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 80 +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +Modifying MS object, TLLI: 0xf1223344 confirmed +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) [DOWNLINK] START +Modifying MS object, TLLI = 0xf1223344, IMSI '' -> '0011223344' +Send dowlink assignment on PACCH, because TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) exists +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) starting timer 0. +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) append diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index c38417d..dda72ef 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -60,3 +60,5 @@ Testing retx for MCS 4 to reseg_mcs 1 Testing retx for MCS 6 to reseg_mcs 3 === end test_tbf_egprs_spb_dl === +=== start test_tbf_puan_urbb_len === +=== end test_tbf_puan_urbb_len === -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 13 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Thu Aug 25 11:11:30 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 25 Aug 2016 11:11:30 +0000 Subject: [PATCH] osmo-pcu[master]: Fix EGPRS PUAN encoding: use correct urbb_len In-Reply-To: References: Message-ID: Hello Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/703 to look at the new patch set (#6). Fix EGPRS PUAN encoding: use correct urbb_len Earlier there was an incorrect encoding of PUAN when VQ is not equal VR case for EGPRS UL RLC window. The PCU was encoding the same PUAN message always irrespective of radio condition. This was a bottle neck for performance testing. Which has been fixed in this patch. Related: OS#1793 unit test assertion in the previous commit is fixed in this patch. Change-Id: Iba7b1995028bd81749ffb080616b2ad5f2540d57 --- M src/encoding.cpp M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err 3 files changed, 5 insertions(+), 5 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/03/703/6 diff --git a/src/encoding.cpp b/src/encoding.cpp index 63049ac..41e0d10 100644 --- a/src/encoding.cpp +++ b/src/encoding.cpp @@ -575,7 +575,8 @@ eow = false; urbb_len = rest_bits - 9; /* TODO: use compression (see above) */ - } + } else + urbb_len = num_blocks; if (urbb_len + crbb_len == rest_bits) len = -1; diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 8ec1dcc..5e40abc 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -753,9 +753,8 @@ msg1 = ul_tbf->create_ul_ack(*fn, ts_no); - /* TODO: Need to modify the assert */ OSMO_ASSERT(!strcmp(osmo_hexdump(msg1->data, msg1->data_len), - "40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b " + "40 24 01 3f 3e 24 46 68 90 88 b0 06 8b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b " )); return ul_tbf; diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index c3a7f20..452f1c1 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -6307,8 +6307,8 @@ TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - Raising V(R) to 5 Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) - - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 5, BOW, EOW -Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b + - EGPRS URBB, len = 2, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 5, BOW, EOW +Uplink Ack/Nack bit count 100, max 184, message = 40 24 01 3f 3e 24 46 68 90 88 b0 06 8b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b Got 'TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS)', TA=7 Got MS: TLLI = 0xf1223344, TA = 7 ********** TBF starts here ********** -- To view, visit https://gerrit.osmocom.org/703 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Iba7b1995028bd81749ffb080616b2ad5f2540d57 Gerrit-PatchSet: 6 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Thu Aug 25 11:16:13 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 25 Aug 2016 11:16:13 +0000 Subject: osmo-pcu[master]: EGPRS: EPDAN decoding: add test case to show no ack_nack len... In-Reply-To: References: Message-ID: Patch Set 2: (5 comments) https://gerrit.osmocom.org/#/c/765/2/tests/rlcmac/RLCMACTest.cpp File tests/rlcmac/RLCMACTest.cpp: Line 33: extern "C" { Neither removal of gprs_log_info nor addition of these four headers is necessary. Line 37: #include All you need to do for this patch is to add here: #include Line 218: void test_epdan_noack_nack_len_issue() naming: is there a "noack"? >From the rest it looks like "test_epdan_no_acknack_len" would make more sense. All tests are about an issue, so no need to name it "_issue". Line 226: bitvec_unhex(vector, testData_epdan[0].c_str()); It would be easier to pass the string constant as argument directly, like in line 210 above. (Interesting, so far I always used osmo_hexparse() and wasn't aware of bitvec_unhex()... There seems to be no bitvec_hex() though.) Line 227: RlcMacUplink_t *data = (RlcMacUplink_t *)malloc(sizeof(RlcMacUplink_t)); really a malloc? In that case you're missing a free, right? I notice that testRlcMacDownlink() above has a similar leak. Easier would be to have a static struct: RlcMacUplink_t data; And use '&data' / '&data.u.Egprs...' below. -- To view, visit https://gerrit.osmocom.org/765 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I8da84794748f2e81722c3eca69b46ccc3a21552e Gerrit-PatchSet: 2 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 25 11:16:24 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 25 Aug 2016 11:16:24 +0000 Subject: osmo-pcu[master]: Fix EGPRS PUAN encoding: use correct urbb_len In-Reply-To: References: Message-ID: Patch Set 6: Hi Neels, I have re submitted the patches. please have a look. Thanks, Aravind Sirsikar -- To view, visit https://gerrit.osmocom.org/703 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Iba7b1995028bd81749ffb080616b2ad5f2540d57 Gerrit-PatchSet: 6 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 25 11:26:49 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 25 Aug 2016 11:26:49 +0000 Subject: osmo-pcu[master]: Fix EGPRS EPDAN decoding: no ack nack dissector length In-Reply-To: References: Message-ID: Patch Set 2: (1 comment) https://gerrit.osmocom.org/#/c/766/2/tests/rlcmac/RLCMACTest.cpp File tests/rlcmac/RLCMACTest.cpp: Line 33: extern "C" { Like with 703, this is clearly not based on 765. Something in your workflow is causing bogus history in your patch submissions. If you have your patch series on a local branch (or on local master, for that matter), all you need is to be on the last commit and do git push origin HEAD:refs/for/master or if you like to add a topic git push origin HEAD:refs/for/master/my_topic_name This way both commits are pushed to gerrit at the same time, and they are guaranteed to match up. The above is assuming that you have cloned the git repos from the gerrit git, see http://osmocom.org/projects/cellular-infrastructure/wiki/Gerrit#Simplest-new-clone I would be interested to know why this problem is possible. How exactly do you push a patch for review? -- To view, visit https://gerrit.osmocom.org/766 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieddf96aca82b0b0e917cfcc70aeb978799fb4e95 Gerrit-PatchSet: 2 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 25 11:31:49 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 25 Aug 2016 11:31:49 +0000 Subject: osmo-pcu[master]: Fix EGPRS EPDAN decoding: no ack nack dissector length In-Reply-To: References: Message-ID: Patch Set 2: (1 comment) https://gerrit.osmocom.org/#/c/766/2/tests/rlcmac/RLCMACTest.cpp File tests/rlcmac/RLCMACTest.cpp: Line 33: extern "C" { > Like with 703, this is clearly not based on 765. I do git push origin HEAD:refs/for/master while submitting the patches. so that a patch series related to specific topic gets pushed. Since I have tried to modify the patch in Gerrit itself It may have caused the problem. I will push the changes again to rectify the issue. -- To view, visit https://gerrit.osmocom.org/766 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieddf96aca82b0b0e917cfcc70aeb978799fb4e95 Gerrit-PatchSet: 2 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 25 11:39:43 2016 From: gerrit-no-reply at lists.osmocom.org (bhargava_abhyankar) Date: Thu, 25 Aug 2016 11:39:43 +0000 Subject: osmo-pcu[master]: Update the function immediate assignment for EGPRS In-Reply-To: References: Message-ID: Patch Set 4: (1 comment) https://gerrit.osmocom.org/#/c/431/4/src/encoding.h File src/encoding.h: Line 26: > Add this here to be able to use enum ph_burst_type: thanks for the input. I will resubmit it -- To view, visit https://gerrit.osmocom.org/431 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ie5e309156e5dbbb6add74a1b4d257c4ee2332e52 Gerrit-PatchSet: 4 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: bhargava_abhyankar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 25 11:47:46 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 25 Aug 2016 11:47:46 +0000 Subject: osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Patch Set 20: Code-Review-2 (11 comments) https://gerrit.osmocom.org/#/c/416/20/src/decoding.cpp File src/decoding.cpp: Line 660: don't move the 'int rc;' around Line 700: LOGP(DRLCMACDL, LOGL_DEBUG, "Compress bitmap exist," in the log msg, a space is missing after the comma Line 712: * bitmap has stopped here */ Don't change the whitespace, you're actually breaking it, too. https://gerrit.osmocom.org/#/c/416/20/src/egprs_rlc_compression.cpp File src/egprs_rlc_compression.cpp: Line 34: * \param idx[in] Iterate index of the code word table what parameters are you documenting here? You should document 'root' and 'cdwd', not the variables *inside* the function! Line 271: * \clr_code_bit[in] Color code 1 for Ones runlength 0 for Zero runlength '\param' Line 330: ones_list, one_run_len_code_list); no line breaks here please, it fits on one line https://gerrit.osmocom.org/#/c/416/20/src/egprs_rlc_compression.h File src/egprs_rlc_compression.h: Line 11: #include not used, move to cpp file if needed there. In general, move as many #includes as possible to the .cpp files. Line 20: #define MOD8(X) (((X)+8) & (0x07)) Just use one space after '#define', but use tabs and not spaces to align the defined values Line 35: */ /* single line comment */ https://gerrit.osmocom.org/#/c/416/20/tests/Makefile.am File tests/Makefile.am: Line 35: -Wl,-u,bssgp_prim_cb Are you sure you need '-Wl,-u,bssgp_prim_cb'? https://gerrit.osmocom.org/#/c/416/20/tests/bitcomp/BitcompTest File tests/bitcomp/BitcompTest: You still have the binary in the commit. Remove it! -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 20 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: pravin Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 25 11:49:40 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 25 Aug 2016 11:49:40 +0000 Subject: osmo-pcu[master]: EGPRS: PUAN encoding: add test case to show wrong urbb_len i... In-Reply-To: References: Message-ID: Patch Set 13: Hi Neels, I have resent the patches after aligning with latest master. And I see that these patches went to Needs Code-Review state. Please can you help with this? Thanks, Aravind Sirsikar -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 13 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 25 11:53:49 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 25 Aug 2016 11:53:49 +0000 Subject: osmo-pcu[master]: EGPRS: PUAN encoding: add test case to show wrong urbb_len i... In-Reply-To: References: Message-ID: Patch Set 13: Code-Review+2 (1 comment) https://gerrit.osmocom.org/#/c/702/13/tests/tbf/TbfTest.cpp File tests/tbf/TbfTest.cpp: Line 757: OSMO_ASSERT(!strcmp(osmo_hexdump(msg1->data, msg1->data_len), for a moment there I thought you were checking the first message again, but then I noticed that you're reusing msg1 now. Could be called just 'msg' then, but whatever. -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 13 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Thu Aug 25 11:54:26 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 25 Aug 2016 11:54:26 +0000 Subject: [MERGED] osmo-pcu[master]: EGPRS: PUAN encoding: add test case to show wrong urbb_len i... In-Reply-To: References: Message-ID: arvind.sirsikar has submitted this change and it was merged. Change subject: EGPRS: PUAN encoding: add test case to show wrong urbb_len issue ...................................................................... EGPRS: PUAN encoding: add test case to show wrong urbb_len issue This patch adds a test case which expects a current bug with EGPRS PUAN encoding when VQ != VR. The test's expectation is corrected along with the bugfix in a subsequent commit Adds test_tbf_puan_urbb_len to describe the following bug: EGPRS PUAN encoding disregards the urbb_len, leading to identical PUAN messages regardless of the urbb_len. Related: OS#1793 Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 --- M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 3 files changed, 304 insertions(+), 0 deletions(-) Approvals: Neels Hofmeyr: Looks good to me, approved Jenkins Builder: Verified diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 5e45506..8ec1dcc 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -618,6 +618,149 @@ &ulreq, tbf->poll_fn); } +static gprs_rlcmac_ul_tbf *puan_urbb_len_issue(BTS *the_bts, + uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, + uint8_t ms_class, uint8_t egprs_ms_class) +{ + GprsMs *ms; + uint32_t rach_fn = *fn - 51; + uint32_t sba_fn = *fn + 52; + uint8_t trx_no = 0; + int tfi = 0, i = 0; + gprs_rlcmac_ul_tbf *ul_tbf; + struct gprs_rlcmac_pdch *pdch; + gprs_rlcmac_bts *bts; + RlcMacUplink_t ulreq = {0}; + struct pcu_l1_meas meas; + struct gprs_rlc_ul_header_egprs_3 *egprs3 = NULL; + GprsCodingScheme cs; + + meas.set_rssi(31); + bts = the_bts->bts_data(); + + /* needed to set last_rts_fn in the PDCH object */ + request_dl_rlc_block(bts, trx_no, ts_no, fn); + + /* + * simulate RACH, this sends an Immediate + * Assignment Uplink on the AGCH + */ + the_bts->rcv_rach(0x73, rach_fn, qta); + + /* get next free TFI */ + tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1); + + /* fake a resource request */ + ulreq.u.MESSAGE_TYPE = MT_PACKET_RESOURCE_REQUEST; + ulreq.u.Packet_Resource_Request.PayloadType = GPRS_RLCMAC_CONTROL_BLOCK; + ulreq.u.Packet_Resource_Request.ID.UnionType = 1; /* != 0 */ + ulreq.u.Packet_Resource_Request.ID.u.TLLI = tlli; + ulreq.u.Packet_Resource_Request.Exist_MS_Radio_Access_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + Count_MS_RA_capability_value = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Exist_Multislot_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + Exist_GPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + GPRS_multislot_class = ms_class; + if (egprs_ms_class) { + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Multislot_capability.Exist_EGPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Multislot_capability.EGPRS_multislot_class = ms_class; + } + + send_ul_mac_block(the_bts, trx_no, ts_no, &ulreq, sba_fn); + + /* check the TBF */ + ul_tbf = the_bts->ul_tbf_by_tfi(tfi, trx_no, ts_no); + OSMO_ASSERT(ul_tbf); + OSMO_ASSERT(ul_tbf->ta() == qta / 4); + + /* send packet uplink assignment */ + *fn = sba_fn; + request_dl_rlc_block(ul_tbf, fn); + + /* send real acknowledgement */ + send_control_ack(ul_tbf); + + check_tbf(ul_tbf); + /* send fake data */ + uint8_t data_msg[42] = { + 0xf << 2, /* GPRS_RLCMAC_DATA_BLOCK << 6, CV = 15 */ + tfi << 1, + 1, /* BSN:7, E:1 */ + }; + + pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no]; + pdch->rcv_block(&data_msg[0], 23, *fn, &meas); + + ms = the_bts->ms_by_tlli(tlli); + OSMO_ASSERT(ms != NULL); + OSMO_ASSERT(ms->ta() == qta/4); + OSMO_ASSERT(ms->ul_tbf() == ul_tbf); + + /* + * TS 44.060, B.8.1 + * first seg received first, later second seg + */ + cs = GprsCodingScheme::MCS3; + egprs3 = (struct gprs_rlc_ul_header_egprs_3 *) data_msg; + egprs3->si = 0; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 1; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 0; + egprs3->pi = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + struct msgb *msg1 = ul_tbf->create_ul_ack(*fn, ts_no); + + OSMO_ASSERT(!strcmp(osmo_hexdump(msg1->data, msg1->data_len), + "40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b " + )); + + egprs3->si = 0; + egprs3->r = 1; + egprs3->cv = 7; + egprs3->tfi_hi = tfi & 0x03; + egprs3->tfi_lo = (tfi & 0x1c) >> 2; + egprs3->bsn1_hi = 4; + egprs3->bsn1_lo = 0; + egprs3->cps_hi = 1; + data_msg[3] = 0xff; + egprs3->pi = 0; + egprs3->cps_lo = 1; + egprs3->rsb = 0; + egprs3->spb = 0; + + pdch->rcv_block(data_msg, 42, *fn, &meas); + + msg1 = ul_tbf->create_ul_ack(*fn, ts_no); + + /* TODO: Need to modify the assert */ + OSMO_ASSERT(!strcmp(osmo_hexdump(msg1->data, msg1->data_len), + "40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b " + )); + + return ul_tbf; +} + static gprs_rlcmac_ul_tbf *establish_ul_tbf_two_phase_spb(BTS *the_bts, uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, uint8_t ms_class, uint8_t egprs_ms_class) @@ -1631,6 +1774,41 @@ gprs_bssgp_destroy(); } +static void test_tbf_puan_urbb_len(void) +{ + BTS the_bts; + int ts_no = 7; + uint32_t fn = 2654218; + uint16_t qta = 31; + uint32_t tlli = 0xf1223344; + const char *imsi = "0011223344"; + uint8_t ms_class = 1; + uint8_t egprs_ms_class = 1; + gprs_rlcmac_ul_tbf *ul_tbf; + GprsMs *ms; + uint8_t test_data[256]; + + printf("=== start %s ===\n", __func__); + + memset(test_data, 1, sizeof(test_data)); + + setup_bts(&the_bts, ts_no, 4); + the_bts.bts_data()->initial_mcs_dl = 9; + the_bts.bts_data()->egprs_enabled = 1; + + ul_tbf = puan_urbb_len_issue(&the_bts, ts_no, tlli, &fn, qta, + ms_class, egprs_ms_class); + + ms = ul_tbf->ms(); + fprintf(stderr, "Got '%s', TA=%d\n", ul_tbf->name(), ul_tbf->ta()); + fprintf(stderr, + "Got MS: TLLI = 0x%08x, TA = %d\n", ms->tlli(), ms->ta()); + + send_dl_data(&the_bts, tlli, imsi, test_data, sizeof(test_data)); + + printf("=== end %s ===\n", __func__); +} + static void test_tbf_egprs_two_phase_spb(void) { BTS the_bts; @@ -2306,6 +2484,7 @@ test_tbf_egprs_dl(); test_tbf_egprs_retx_dl(); test_tbf_egprs_spb_dl(); + test_tbf_puan_urbb_len(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 1ba4189..c3a7f20 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -6212,3 +6212,126 @@ Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=RELEASING EGPRS) Destroying MS object, TLLI = 0xffeeddcc ********** TBF ends here ********** +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654218 block=8 data=47 94 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +MS requests UL TBF on RACH, so we provide one: +MS requests single block allocation +RX: [PCU <- BTS] RACH qbit-ta=31 ra=0x73, Fn=2654167 (17,25,9), SBFn=2654270 +TX: Immediate Assignment Uplink (AGCH) + - TRX=0 (0) TS=7 TA=7 TSC=0 TFI=-1 USF=7 +Sending data request: trx=0 ts=0 sapi=2 arfcn=0 fn=0 block=0 data=2d 06 3f 10 0f 00 00 73 8b 29 07 00 c0 0c 5a 43 2b 2b 2b 2b 2b 2b 2b +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +MS requests UL TBF in packet resource request of single block, so we provide one: +MS supports EGPRS multislot class 1. +********** TBF starts here ********** +Allocating UL TBF: MS_CLASS=1/1 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 1 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 1 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign uplink TS=7 TFI=0 USF=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 00 +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=ASSIGN EGPRS) starting timer 3169. +Modifying MS object, UL TLLI: 0x00000000 -> 0xf1223344, not yet confirmed +Modifying MS object, TLLI = 0xf1223344, TA 0 -> 7 +Change control TS to 7 until assinment is complete. +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS)s start Packet Uplink Assignment (PACCH) ++++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++ +------------------------- TX : Packet Uplink Assignment ------------------------- +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS): Scheduling polling at FN 2654283 TS 7 +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN EGPRS) changes state from ASSIGN to WAIT ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Scheduled UL Assignment polling on FN=2654283, TS=7 +Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) (TRX=0, TS=7) +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654270 block=8 data=4f 28 5e 24 46 68 90 f8 0a 39 00 00 88 00 08 2b 2b 2b 2b 2b 2b 2b 2b +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) Packet Control Ack +TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN EGPRS) changes state from WAIT ASSIGN to FLOW +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=0 .. V(R)=0) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got CS-1 RLC data block: CV=15, BSN=0, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 0 storing in window (0..63) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 1 +- Taking block 0 out, raising V(Q) to 1 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=0 CV=15 +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1d 08 40 c1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=0, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=1) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=1, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 1 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 2 +- Taking block 1 out, raising V(Q) to 2 +- Assembling frames: (len=37) +-- Frame 1 starts at offset 0, length=37, is_complete=0 +- No gaps in received block, last block: BSN=1 CV=7 +Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) + - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 2, BOW, EOW +Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got RLC block, coding scheme: MCS-3, length: 42 (42)) + UL data: 1d 20 40 c1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got MCS-3 RLC block: R=1, SI=0, TFI=0, CPS=5, RSB=0, rc=329 +UL DATA TFI=0 received (V(Q)=2 .. V(R)=2) +max_cs_ul cannot be derived (current UL CS: UNKNOWN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): Got MCS-3 RLC data block: CV=7, BSN=4, SPB=0, PI=0, E=1, TI=0, bitoffs=33 +- BSN 4 storing in window (2..65) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 5 +Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) + - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 5, BOW, EOW +Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got 'TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS)', TA=7 +Got MS: TLLI = 0xf1223344, TA = 7 +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=1/1 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Slot Allocation (Algorithm A) for class 0 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign downlink TS=7 TFI=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0xf1223344, TBF = TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 80, dl_slots = 80 +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 64 +Modifying MS object, TLLI: 0xf1223344 confirmed +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) [DOWNLINK] START +Modifying MS object, TLLI = 0xf1223344, IMSI '' -> '0011223344' +Send dowlink assignment on PACCH, because TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) exists +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) starting timer 0. +TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) append diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index c38417d..dda72ef 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -60,3 +60,5 @@ Testing retx for MCS 4 to reseg_mcs 1 Testing retx for MCS 6 to reseg_mcs 3 === end test_tbf_egprs_spb_dl === +=== start test_tbf_puan_urbb_len === +=== end test_tbf_puan_urbb_len === -- To view, visit https://gerrit.osmocom.org/702 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8 Gerrit-PatchSet: 13 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Thu Aug 25 11:54:30 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Thu, 25 Aug 2016 11:54:30 +0000 Subject: osmo-pcu[master]: Fix EGPRS PUAN encoding: use correct urbb_len In-Reply-To: References: Message-ID: Patch Set 6: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/703 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Iba7b1995028bd81749ffb080616b2ad5f2540d57 Gerrit-PatchSet: 6 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 25 11:54:34 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 25 Aug 2016 11:54:34 +0000 Subject: [MERGED] osmo-pcu[master]: Fix EGPRS PUAN encoding: use correct urbb_len In-Reply-To: References: Message-ID: arvind.sirsikar has submitted this change and it was merged. Change subject: Fix EGPRS PUAN encoding: use correct urbb_len ...................................................................... Fix EGPRS PUAN encoding: use correct urbb_len Earlier there was an incorrect encoding of PUAN when VQ is not equal VR case for EGPRS UL RLC window. The PCU was encoding the same PUAN message always irrespective of radio condition. This was a bottle neck for performance testing. Which has been fixed in this patch. Related: OS#1793 unit test assertion in the previous commit is fixed in this patch. Change-Id: Iba7b1995028bd81749ffb080616b2ad5f2540d57 --- M src/encoding.cpp M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err 3 files changed, 5 insertions(+), 5 deletions(-) Approvals: Neels Hofmeyr: Looks good to me, approved Jenkins Builder: Verified diff --git a/src/encoding.cpp b/src/encoding.cpp index 63049ac..41e0d10 100644 --- a/src/encoding.cpp +++ b/src/encoding.cpp @@ -575,7 +575,8 @@ eow = false; urbb_len = rest_bits - 9; /* TODO: use compression (see above) */ - } + } else + urbb_len = num_blocks; if (urbb_len + crbb_len == rest_bits) len = -1; diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 8ec1dcc..5e40abc 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -753,9 +753,8 @@ msg1 = ul_tbf->create_ul_ack(*fn, ts_no); - /* TODO: Need to modify the assert */ OSMO_ASSERT(!strcmp(osmo_hexdump(msg1->data, msg1->data_len), - "40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b " + "40 24 01 3f 3e 24 46 68 90 88 b0 06 8b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b " )); return ul_tbf; diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index c3a7f20..452f1c1 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -6307,8 +6307,8 @@ TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS): data_length=37, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - Raising V(R) to 5 Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS) (final=0) - - EGPRS URBB, len = 0, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 5, BOW, EOW -Uplink Ack/Nack bit count 98, max 184, message = 40 24 01 3f 3e 24 46 68 90 87 b0 06 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b + - EGPRS URBB, len = 2, SSN = 3, ESN_CRBB = 2, SNS = 2048, WS = 64, V(Q) = 2, V(R) = 5, BOW, EOW +Uplink Ack/Nack bit count 100, max 184, message = 40 24 01 3f 3e 24 46 68 90 88 b0 06 8b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b Got 'TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW EGPRS)', TA=7 Got MS: TLLI = 0xf1223344, TA = 7 ********** TBF starts here ********** -- To view, visit https://gerrit.osmocom.org/703 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: Iba7b1995028bd81749ffb080616b2ad5f2540d57 Gerrit-PatchSet: 6 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Thu Aug 25 13:38:08 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 25 Aug 2016 13:38:08 +0000 Subject: [PATCH] osmo-pcu[master]: EGPRS: EPDAN decoding: add test case to show no ack_nack len... In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/765 to look at the new patch set (#3). EGPRS: EPDAN decoding: add test case to show no ack_nack len issue This patch adds a test case itest_epdan_noack_nack_len_issue which expects a current bug with EGPRS EPDAN decoding Ack/Nack dissector length is not received. The test's expectation is corrected along with the bug fix in a subsequent commit Related: OS#1805 Change-Id: I8da84794748f2e81722c3eca69b46ccc3a21552e --- M tests/rlcmac/RLCMACTest.cpp 1 file changed, 23 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/65/765/3 diff --git a/tests/rlcmac/RLCMACTest.cpp b/tests/rlcmac/RLCMACTest.cpp index 466b89e..0dbfe3f 100644 --- a/tests/rlcmac/RLCMACTest.cpp +++ b/tests/rlcmac/RLCMACTest.cpp @@ -30,6 +30,7 @@ #include "pcu_vty.h" #include #include +#include #include } using namespace std; @@ -211,6 +212,27 @@ bitvec_free(resultVector); } +void test_epdan_no_ack_nack_len() +{ + bitvec *vector = bitvec_alloc(23); + + bitvec_unhex(vector, "40200bffd161003e0e519ffffffb800000000000000000"); + RlcMacUplink_t data; + + decode_gsm_rlcmac_uplink(vector, &data); + + EGPRS_AckNack_Desc_t *urbb = + &data.u.Egprs_Packet_Downlink_Ack_Nack.EGPRS_AckNack.Desc; + /* + * TODO: URBB len is decoded as 102. so there is total 12 bytes and + * 6 bits in the 13th byte. in 13th byte we expect value + * as 0x00. But we see 0xea. Which is incorrect + */ + OSMO_ASSERT(!strcmp(osmo_hexdump(urbb->URBB, (urbb->URBB_LENGTH + 7)/8), + "7f ff ff ee 00 00 00 00 00 00 00 00 ea " + )); +} + int main(int argc, char *argv[]) { osmo_init_logging(&gprs_log_info); @@ -218,5 +240,5 @@ //printSizeofRLCMAC(); testRlcMacDownlink(); testRlcMacUplink(); - + test_epdan_no_ack_nack_len(); } -- To view, visit https://gerrit.osmocom.org/765 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I8da84794748f2e81722c3eca69b46ccc3a21552e Gerrit-PatchSet: 3 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Thu Aug 25 13:38:08 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 25 Aug 2016 13:38:08 +0000 Subject: [PATCH] osmo-pcu[master]: Fix EGPRS EPDAN decoding: no ack nack dissector length In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/766 to look at the new patch set (#3). Fix EGPRS EPDAN decoding: no ack nack dissector length Earlier there was an incorrect decoding of URBB fields when EPDAN is received withot ack/Nack dissector length.This was a bottle neck for performance testing. Which has been fixed in this patch. Related: OS#1805 unit test assertion in the previous commit is fixed in this patch. Change-Id: Ieddf96aca82b0b0e917cfcc70aeb978799fb4e95 --- M src/csn1.cpp M tests/rlcmac/RLCMACTest.cpp 2 files changed, 3 insertions(+), 6 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/66/766/3 diff --git a/src/csn1.cpp b/src/csn1.cpp index d51fe83..da5fe3b 100644 --- a/src/csn1.cpp +++ b/src/csn1.cpp @@ -1111,6 +1111,7 @@ { /* extract bits */ guint8* pui8 = pui8DATA(data, pDescr->offset); gint16 nB1 = no_of_bits & 0x07;/* no_of_bits Mod 8 */ + no_of_bits -= nB1; while (no_of_bits > 0) { diff --git a/tests/rlcmac/RLCMACTest.cpp b/tests/rlcmac/RLCMACTest.cpp index 0dbfe3f..e82938e 100644 --- a/tests/rlcmac/RLCMACTest.cpp +++ b/tests/rlcmac/RLCMACTest.cpp @@ -223,13 +223,9 @@ EGPRS_AckNack_Desc_t *urbb = &data.u.Egprs_Packet_Downlink_Ack_Nack.EGPRS_AckNack.Desc; - /* - * TODO: URBB len is decoded as 102. so there is total 12 bytes and - * 6 bits in the 13th byte. in 13th byte we expect value - * as 0x00. But we see 0xea. Which is incorrect - */ + OSMO_ASSERT(!strcmp(osmo_hexdump(urbb->URBB, (urbb->URBB_LENGTH + 7)/8), - "7f ff ff ee 00 00 00 00 00 00 00 00 ea " + "7f ff ff ee 00 00 00 00 00 00 00 00 00 " )); } -- To view, visit https://gerrit.osmocom.org/766 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ieddf96aca82b0b0e917cfcc70aeb978799fb4e95 Gerrit-PatchSet: 3 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Thu Aug 25 13:52:00 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Thu, 25 Aug 2016 13:52:00 +0000 Subject: osmo-pcu[master]: EGPRS: EPDAN decoding: add test case to show no ack_nack len... In-Reply-To: References: Message-ID: Patch Set 3: Hi Neels, I have updated the patch as your recommendation. I am able to run the test at my host and it is getting passed. But Gerrit is reporting it as failed. I am not able to understand whether it is a patch issue or something else. Please help. Thanks, Aravind Sirsikar -- To view, visit https://gerrit.osmocom.org/765 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I8da84794748f2e81722c3eca69b46ccc3a21552e Gerrit-PatchSet: 3 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Thu Aug 25 14:12:30 2016 From: gerrit-no-reply at lists.osmocom.org (pravin) Date: Thu, 25 Aug 2016 14:12:30 +0000 Subject: [PATCH] osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Hello Max, Neels Hofmeyr, Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/416 to look at the new patch set (#21). Add decoding of compressed bitmap in EPDAN Implemented tree based algorithm to decode compressed bitmap in EPDAN as described in section 9.1.10 of 3GPP 44.060. This algorithm intends to improve the performance over existing method. New Regression test is added under bitcomp directory. Test case is added to validate decompressed result of the bitmap Present in EPDAN. Test is done for multiple bitmaps of varying length. Invalid inputs are also part of the test vector. Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce --- M src/Makefile.am M src/decoding.cpp A src/egprs_rlc_compression.cpp A src/egprs_rlc_compression.h M tests/Makefile.am A tests/bitcomp/BitcompTest.cpp A tests/bitcomp/BitcompTest.err A tests/bitcomp/BitcompTest.ok M tests/testsuite.at 9 files changed, 743 insertions(+), 15 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/16/416/21 diff --git a/src/Makefile.am b/src/Makefile.am index 9bdec2f..9b047e7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -62,7 +62,8 @@ rlc.cpp \ osmobts_sock.cpp \ gprs_codel.c \ - gprs_coding_scheme.cpp + gprs_coding_scheme.cpp \ + egprs_rlc_compression.cpp bin_PROGRAMS = \ osmo-pcu @@ -94,7 +95,8 @@ pcu_utils.h \ cxx_linuxlist.h \ gprs_codel.h \ - gprs_coding_scheme.h + gprs_coding_scheme.h \ + egprs_rlc_compression.h osmo_pcu_SOURCES = pcu_main.cpp diff --git a/src/decoding.cpp b/src/decoding.cpp index 7c00ff7..60ebc0d 100644 --- a/src/decoding.cpp +++ b/src/decoding.cpp @@ -20,6 +20,7 @@ #include #include #include +#include extern "C" { #include @@ -695,21 +696,17 @@ if (crbb_len > 0) { int old_len = bits->cur_bit; - struct bitvec crbb; - crbb.data = (uint8_t *)desc->CRBB; - crbb.data_len = sizeof(desc->CRBB); - crbb.cur_bit = desc->CRBB_LENGTH; - - rc = osmo_t4_decode(&crbb, desc->CRBB_STARTING_COLOR_CODE, - bits); - + LOGP(DRLCMACDL, LOGL_DEBUG, "Compress bitmap exist, " + "CRBB LEN =%d and Starting color code =%d", + desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE); + rc = decompress_crbb(desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE, + desc->CRBB, bits); if (rc < 0) { LOGP(DRLCMACUL, LOGL_NOTICE, - "Failed to decode CRBB: " - "length %d, data '%s'\n", - desc->CRBB_LENGTH, - osmo_hexdump(crbb.data, crbb.data_len)); + "Failed to decode CRBB: length %d, data '%s'\n", + desc->CRBB_LENGTH, osmo_hexdump( + desc->CRBB, (desc->CRBB_LENGTH + 7)/8)); /* We don't know the SSN offset for the URBB, * return what we have so far and assume the * bitmap has stopped here */ diff --git a/src/egprs_rlc_compression.cpp b/src/egprs_rlc_compression.cpp new file mode 100644 index 0000000..bd43c7d --- /dev/null +++ b/src/egprs_rlc_compression.cpp @@ -0,0 +1,334 @@ +/* egprs_rlc_compression.h +* Routines for EGPRS RLC bitmap compression handling +*/ +#include +#include +#include +#include +#include +#include +#include + +extern "C" { +#include +#include +#include +} + +extern void *tall_pcu_ctx; + +egprs_compress *egprs_compress::s_instance = 0; + +/* Function to create tree node */ +Node *egprs_compress::create_tree_node(void *parent) +{ + Node *new_node; + + new_node = talloc_zero(parent, Node); + new_node->left = NULL; + new_node->right = NULL; + new_node->run_length = -1; + return new_node; +} + +/* Function to build the codeword tree + * \param root[in] Root of Ones or Zeros tree + * \param cdwd[in] Code word + */ +void egprs_compress::build_codeword(Node *root, const char *cdwd[]) +{ + Node *iter; + int len; + int i; + int idx; + + for (idx = 0; idx < MAX_CDWDTBL_LEN; idx++) { + len = strlen((const char *)cdwd[idx]); + iter = root; + for (i = 0; i < len; i++) { + if (cdwd[idx][i] == '0') { + if (!iter->left) + iter->left = create_tree_node(root); + iter = iter->left; + } else if (cdwd[idx][i] == '1') { + if (!iter->right) + iter->right = create_tree_node(root); + iter = iter->right; + } + } + if (iter) { + if (idx < 64) + (iter->run_length) = idx; + else + (iter->run_length) = (idx - 63) * 64; + } + } +} + +const char *one_run_len_code_list[MAX_CDWDTBL_LEN] = { + "00110101", + "000111", + "0111", + "1000", + "1011", + "1100", + "1110", + "1111", + "10011", + "10100", + "00111", + "01000", + "001000", + "000011", + "110100", + "110101", + "101010", + "101011", + "0100111", + "0001100", + "0001000", + "0010111", + "0000011", + "0000100", + "0101000", + "0101011", + "0010011", + "0100100", + "0011000", + "00000010", + "00000011", + "00011010", + "00011011", + "00010010", + "00010011", + "00010100", + "00010101", + "00010110", + "00010111", + "00101000", + "00101001", + "00101010", + "00101011", + "00101100", + "00101101", + "00000100", + "00000101", + "00001010", + "00001011", + "01010010", + "01010011", + "01010100", + "01010101", + "00100100", + "00100101", + "01011000", + "01011001", + "01011010", + "01011011", + "01001010", + "01001011", + "00110010", + "00110011", + "00110100", + "11011", + "10010", + "010111", + "0110111", + "00110110", + "00110111", + "01100100", + "01100101", + "01101000", + "01100111", + "011001100", + "011001101", + "011010010", + "011010011", + "011010100" +}; + +const char *zero_run_len_code_list[MAX_CDWDTBL_LEN] = { + "0000110111", + "10", + "11", + "010", + "011", + "0011", + "0010", + "00011", + "000101", + "000100", + "0000100", + "0000101", + "0000111", + "00000100", + "00000111", + "000011000", + "0000010111", + "0000011000", + "0000001000", + "00001100111", + "00001101000", + "00001101100", + "00000110111", + "00000101000", + "00000010111", + "00000011000", + "000011001010", + "000011001011", + "000011001100", + "000011001101", + "000001101000", + "000001101001", + "000001101010", + "000001101011", + "000011010010", + "000011010011", + "000011010100", + "000011010101", + "000011010110", + "000011010111", + "000001101100", + "000001101101", + "000011011010", + "000011011011", + "000001010100", + "000001010101", + "000001010110", + "000001010111", + "000001100100", + "000001100101", + "000001010010", + "000001010011", + "000000100100", + "000000110111", + "000000111000", + "000000100111", + "000000101000", + "000001011000", + "000001011001", + "000000101011", + "000000101100", + "000001011010", + "000001100110", + "000001100111", + "0000001111", + "000011001000", + "000011001001", + "000001011011", + "000000110011", + "000000110100", + "000000110101", + "0000001101100", + "0000001101101", + "0000001001010", + "0000001001011", + "0000001001100", + "0000001001101", + "0000001110010", + "0000001110011" +}; + +/* search_runlen function will return the runlength for the codeword + * \param root[in] Root of Ones or Zeros tree + * \param bmbuf[in] Recevied compressed bitmap buf + * \param bit_pos[in] The start bit pos to read codeword + * \param len_codewd[in] Length of code word + * \param rlen[out] Run length value + */ +static int search_runlen( + Node *root, + const uint8_t *bmbuf, + uint8_t bit_pos, + uint8_t *len_codewd, + uint16_t *rlen) +{ + Node *iter; + uint8_t dir; + + iter = root; + *len_codewd = 0; + + while (iter->run_length == -1) { + if ((!iter->left) && (!iter->right)) + return -1; + /* get the bit value at the bitpos and put it in right most of dir */ + dir = ((bmbuf[BITS_TO_BYTES(bit_pos)-1] + >>(7-(MOD8(bit_pos)))) & 0x01); + (bit_pos)++; + (*len_codewd)++; + if (((dir&0x01) == 0) && (iter->left != NULL)) + iter = iter->left; + else if (((dir&0x01) == 1) && (iter->right != NULL)) + iter = iter->right; + else + return -1; + } + (*rlen) = (iter->run_length); + return 1; +} + +/* Function to decompress crbb + * \param compress_bmap_len[in] Compressed bitmap length + * \param clr_code_bit[in] Color code 1 for Ones runlength 0 for Zero runlength + * \param orig_crbb_buf[in] Received block crbb bitmap + * \param dest[out] Uncompressed bitvector + */ +int decompress_crbb( + int8_t compress_bmap_len, + uint8_t clr_code_bit, + const uint8_t *orig_crbb_buf, + bitvec *dest) +{ + + uint8_t bit_pos = 0; + uint8_t data = 0x0; + node *list = NULL; + uint8_t nbits = 0; /* number of bits of codeword */ + uint16_t run_length = 0; + uint16_t cbmaplen = 0; /* compressed bitmap part after decompression */ + unsigned wp = dest->cur_bit; + int rc = 0; + egprs_compress *compress = egprs_compress::instance(); + + while (compress_bmap_len > 0) { + if (clr_code_bit == 1) { + data = 0xff; + list = compress->ones_list; + } else { + data = 0x00; + list = compress->zeros_list; + } + rc = search_runlen(list, orig_crbb_buf, + bit_pos, &nbits, &run_length); + if (rc == -1) + return -1; + /* If run length > 64, need makeup and terminating code */ + if (run_length < 64) + clr_code_bit ? clr_code_bit = 0 : clr_code_bit = 1; + cbmaplen = cbmaplen + run_length; + /* put run length of Ones in uncompressed bitmap */ + while (run_length != 0) { + if (run_length > 8) { + bitvec_write_field(dest, wp, data, 8); + run_length = run_length - 8; + } else { + bitvec_write_field(dest, wp, data, run_length); + run_length = 0; + } + } + bit_pos = bit_pos + nbits; + compress_bmap_len = compress_bmap_len - nbits; + } + return 0; +} + +/* init function to build codeword */ +int egprs_compress::decode_tree_init() +{ + ones_list = create_tree_node(tall_pcu_ctx); + zeros_list = create_tree_node(tall_pcu_ctx); + build_codeword(ones_list, one_run_len_code_list); + build_codeword(zeros_list, zero_run_len_code_list); + return 0; +} diff --git a/src/egprs_rlc_compression.h b/src/egprs_rlc_compression.h new file mode 100644 index 0000000..4361e66 --- /dev/null +++ b/src/egprs_rlc_compression.h @@ -0,0 +1,51 @@ +/* egprs_rlc_compression.h + * Routines for EGPRS RLC bitmap compression handling + */ + +#pragma once + +#define MAX_CDWDTBL_LEN 79 /* total number of codewords */ +#define BITS_TO_BYTES(X) ((X ? (X/8):0)+1) +#define MOD8(X) (((X)+8) & (0x07)) + +typedef struct node { + struct node *left; + struct node *right; + int run_length; +} Node; + +extern const char *one_run_len_code_list[MAX_CDWDTBL_LEN]; +extern const char *zero_run_len_code_list[MAX_CDWDTBL_LEN]; + +int decompress_crbb(int8_t compress_bmap_len, uint8_t clr_code_bit, + const uint8_t *orig_buf, bitvec *dest); + +/* Creating singleton class*/ +class egprs_compress +{ + static egprs_compress *s_instance; + + egprs_compress() + { + if (decode_tree_init() < 0) { + fprintf(stderr, "Error initializing tree\n"); + exit(1); + } + } + Node *create_tree_node(void *); + void build_codeword(Node *root, const char *cdwd[]); + ~egprs_compress(); +public: + Node *ones_list; + Node *zeros_list; + + int decode_tree_init(void); + + static egprs_compress *instance() + { + if (!s_instance) + s_instance = new egprs_compress; + + return s_instance; + } +}; diff --git a/tests/Makefile.am b/tests/Makefile.am index 2a3415e..a24f4ea 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,7 +1,7 @@ AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGB_CFLAGS) $(LIBOSMOGSM_CFLAGS) -I$(top_srcdir)/src/ AM_LDFLAGS = -lrt -check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest llc/LlcTest codel/codel_test edge/EdgeTest +check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest llc/LlcTest codel/codel_test edge/EdgeTest bitcomp/BitcompTest noinst_PROGRAMS = emu/pcu_emu rlcmac_RLCMACTest_SOURCES = rlcmac/RLCMACTest.cpp @@ -23,6 +23,11 @@ $(top_builddir)/src/libgprs.la \ $(LIBOSMOGB_LIBS) \ $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(COMMON_LA) + +bitcomp_BitcompTest_SOURCES = bitcomp/BitcompTest.cpp ../src/egprs_rlc_compression.cpp +bitcomp_BitcompTest_LDADD = \ $(LIBOSMOCORE_LIBS) \ $(COMMON_LA) @@ -108,6 +113,7 @@ rlcmac/RLCMACTest.ok rlcmac/RLCMACTest.err \ alloc/AllocTest.ok alloc/AllocTest.err \ tbf/TbfTest.ok tbf/TbfTest.err \ + bitcomp/BitcompTest.ok bitcomp/BitcompTest.err \ types/TypesTest.ok types/TypesTest.err \ ms/MsTest.ok ms/MsTest.err \ llc/LlcTest.ok llc/LlcTest.err \ diff --git a/tests/bitcomp/BitcompTest.cpp b/tests/bitcomp/BitcompTest.cpp new file mode 100644 index 0000000..edcd4c0 --- /dev/null +++ b/tests/bitcomp/BitcompTest.cpp @@ -0,0 +1,236 @@ +#include +#include + +#include "rlc.h" +#include "gprs_debug.h" +#include +#include "egprs_rlc_compression.h" + +extern "C" { +#include +#include +#include +#include +} + +#define NEW 1 +#define MASK(n) (0xFF << (8-n)) +#define MAX_CRBB_LEN 23 +#define MAX_URBB_LEN 40 + +void *tall_pcu_ctx; + +struct test_data { + int8_t crbb_len; + uint8_t cc; + uint8_t crbb_data[MAX_CRBB_LEN]; /* compressed data */ + uint8_t ucmp_data[MAX_URBB_LEN]; /* uncompressed data */ + int ucmp_len; + int verify; +} test[] = { + { .crbb_len = 67, .cc = 1, + .crbb_data = { + 0x02, 0x0c, 0xa0, 0x30, 0xcb, 0x1a, 0x0c, 0xe3, 0x6c + }, + .ucmp_data = { + 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x01, 0xff, 0xff, + 0xff, 0xf8, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, + 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xdb + }, + .ucmp_len = 194, .verify = 1 + }, + { .crbb_len = 40, .cc = 1, + .crbb_data = { + 0x53, 0x06, 0xc5, 0x40, 0x6d + }, + .ucmp_data = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x03 + }, + .ucmp_len = 182, .verify = 1 + }, + { .crbb_len = 8, .cc = 1, + .crbb_data = {0x02}, + .ucmp_data = {0xff, 0xff, 0xff, 0xf8}, + .ucmp_len = 29, .verify = 1 + }, + { .crbb_len = 103, .cc = 1, + .crbb_data = { + 0x02, 0x0c, 0xe0, 0x41, 0xa0, 0x0c, 0x36, 0x0d, 0x03, + 0x71, 0xb0, 0x6e, 0x24 + }, + .ucmp_data = { + 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xf8, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, + 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff + }, + .ucmp_len = 288, .verify = 1 + }, + /* Test vector from libosmocore test */ + { .crbb_len = 35, .cc = 0, + .crbb_data = {0xde, 0x88, 0x75, 0x65, 0x80}, + .ucmp_data = {0x37, 0x47, 0x81, 0xf0}, + .ucmp_len = 28, .verify = 1 + }, + { .crbb_len = 18, .cc = 1, + .crbb_data = {0xdd, 0x41, 0x00}, + .ucmp_data = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00 + }, + .ucmp_len = 90, .verify = 1 + }, + /*Invalid inputs*/ + { .crbb_len = 18, .cc = 1, + .crbb_data = {0x1E, 0x70, 0xc0}, + .ucmp_data = {0x0}, + .ucmp_len = 0, .verify = 0 + }, + { .crbb_len = 14, .cc = 1, + .crbb_data = {0x00, 0x1E, 0x7c}, + .ucmp_data = {0x0}, + .ucmp_len = 0, .verify = 0 + }, + { .crbb_len = 24, .cc = 0, + .crbb_data = {0x00, 0x00, 0x00}, + .ucmp_data = {0x0}, + .ucmp_len = 0, .verify = 0 + } + }; + +static const struct log_info_cat default_categories[] = { + {"DCSN1", "\033[1;31m", "Concrete Syntax Notation One (CSN1)", LOGL_INFO, 0}, + {"DL1IF", "\033[1;32m", "GPRS PCU L1 interface (L1IF)", LOGL_DEBUG, 1}, + {"DRLCMAC", "\033[0;33m", "GPRS RLC/MAC layer (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACDATA", "\033[0;33m", "GPRS RLC/MAC layer Data (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACDL", "\033[1;33m", "GPRS RLC/MAC layer Downlink (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACUL", "\033[1;36m", "GPRS RLC/MAC layer Uplink (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACSCHED", "\033[0;36m", "GPRS RLC/MAC layer Scheduling (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACMEAS", "\033[1;31m", "GPRS RLC/MAC layer Measurements (RLCMAC)", LOGL_INFO, 1}, + {"DNS", "\033[1;34m", "GPRS Network Service Protocol (NS)", LOGL_INFO, 1}, + {"DBSSGP", "\033[1;34m", "GPRS BSS Gateway Protocol (BSSGP)", LOGL_INFO, 1}, + {"DPCU", "\033[1;35m", "GPRS Packet Control Unit (PCU)", LOGL_NOTICE, 1}, +}; + +static int filter_fn(const struct log_context *ctx, + struct log_target *tar) +{ + return 1; +} + +/* To verify the result with expected result */ +int check_result(bitvec bits, uint8_t *exp_data, int exp_len) +{ + if (bits.cur_bit != exp_len) + return 0; + size_t n = (exp_len / 8); + int rem = (exp_len % 8); + + if (memcmp(exp_data, bits.data, n) == 0) { + if (rem == 0) + return 1; + if ((bits.data[n] & MASK(rem)) == ((*(exp_data + n)) & MASK(rem))) + return 1; + else + return 0; + } else + return 0; +} + +/* To test decoding of compressed bitmap by Tree based method + * and to verify the result with expected result + * for invalid input verfication is suppressed + */ +static void test_EPDAN_decode_tree(void) +{ + bitvec dest; + int init_flag = 1; + int itr; + int rc; + uint8_t bits_data[RLC_EGPRS_MAX_WS/8]; + + printf("=== start %s ===\n", __func__); + + for (itr = 0 ; itr < (sizeof(test) / sizeof(test_data)) ; itr++) { + dest.data = bits_data; + dest.data_len = sizeof(bits_data); + dest.cur_bit = 0; + memset(dest.data, 0, sizeof(bits_data)); + LOGP(DRLCMACDL, LOGL_DEBUG, "\nTest:%d\nTree based decoding:" + "\nuncompressed data = %s\nlen = %d\n", itr + 1, + osmo_hexdump(test[itr].crbb_data, + (test[itr].crbb_len + 7)/8), test[itr].crbb_len + ); + rc = decompress_crbb(test[itr].crbb_len, test[itr].cc, + test[itr].crbb_data, &dest + ); + if (rc < 0) { + LOGP(DRLCMACUL, LOGL_NOTICE, + "\nFailed to decode CRBB: length %d, data %s", + test[itr].crbb_len, osmo_hexdump( + test[itr].crbb_data, (test[itr].crbb_len + 7)/8)); + } + if (init_flag) + init_flag = 0; + if (test[itr].verify) { + if (check_result(dest, test[itr].ucmp_data, + test[itr].ucmp_len) == 0) { + LOGP(DRLCMACDL, LOGL_DEBUG, "\nTree based decoding" + ":Error\nexpected data = %s\nexpected" + " len = %d\ndecoded data = %s\n" + "decoded len = %d\n", + osmo_hexdump(test[itr].ucmp_data, + (test[itr].ucmp_len + 7)/8), + test[itr].ucmp_len, osmo_hexdump(dest.data, + (dest.cur_bit + 7)/8), dest.cur_bit + ); + OSMO_ASSERT(0); + } + } + LOGP(DRLCMACDL, LOGL_DEBUG, "\nexpected data = %s\nexpected len = %d" + "\ndecoded data = %s\ndecoded len = %d\n", + osmo_hexdump(test[itr].ucmp_data, + (test[itr].ucmp_len + 7)/8), + test[itr].ucmp_len, osmo_hexdump(dest.data, + (dest.cur_bit + 7)/8), dest.cur_bit + ); + } + + printf("=== end %s ===\n", __func__); +} + +const struct log_info debug_log_info = { + filter_fn, + (struct log_info_cat *)default_categories, + ARRAY_SIZE(default_categories), +}; + +int main(int argc, char **argv) +{ + osmo_init_logging(&debug_log_info); + log_set_use_color(osmo_stderr_target, 0); + log_set_print_filename(osmo_stderr_target, 0); + + tall_pcu_ctx = talloc_named_const(NULL, 1, "moiji-mobile TbfTest context"); + if (!tall_pcu_ctx) + abort(); + + test_EPDAN_decode_tree(); + + if (getenv("TALLOC_REPORT_FULL")) + talloc_report_full(tall_pcu_ctx, stderr); + talloc_free(tall_pcu_ctx); + return EXIT_SUCCESS; +} +/* + * stubs that should not be reached + */ +extern "C" { +void l1if_pdch_req() { abort(); } +void l1if_connect_pdch() { abort(); } +void l1if_close_pdch() { abort(); } +void l1if_open_pdch() { abort(); } +} + diff --git a/tests/bitcomp/BitcompTest.err b/tests/bitcomp/BitcompTest.err new file mode 100644 index 0000000..a9078d0 --- /dev/null +++ b/tests/bitcomp/BitcompTest.err @@ -0,0 +1,92 @@ + +Test:1 +Tree based decoding: +uncompressed data = 02 0c a0 30 cb 1a 0c e3 6c +len = 67 + +expected data = ff ff ff f8 00 00 01 ff ff ff f8 00 00 00 ff ff ff fe 00 00 3f ff ff ff db +expected len = 194 +decoded data = ff ff ff f8 00 00 01 ff ff ff f8 00 00 00 ff ff ff fe 00 00 3f ff ff ff db +decoded len = 194 + +Test:2 +Tree based decoding: +uncompressed data = 53 06 c5 40 6d +len = 40 + +expected data = ff ff ff ff ff ff c0 00 00 00 00 3f ff ff ff ff ff f8 00 00 00 00 03 +expected len = 182 +decoded data = ff ff ff ff ff ff c0 00 00 00 00 3f ff ff ff ff ff f8 00 00 00 00 03 +decoded len = 182 + +Test:3 +Tree based decoding: +uncompressed data = 02 +len = 8 + +expected data = ff ff ff f8 +expected len = 29 +decoded data = ff ff ff f8 +decoded len = 29 + +Test:4 +Tree based decoding: +uncompressed data = 02 0c e0 41 a0 0c 36 0d 03 71 b0 6e 24 +len = 103 + +expected data = ff ff ff f8 00 00 ff ff ff f8 00 00 7f ff ff fe 00 00 0f ff ff ff e0 00 00 7f ff ff ff 80 00 01 ff ff ff ff +expected len = 288 +decoded data = ff ff ff f8 00 00 ff ff ff f8 00 00 7f ff ff fe 00 00 0f ff ff ff e0 00 00 7f ff ff ff 80 00 01 ff ff ff ff +decoded len = 288 + +Test:5 +Tree based decoding: +uncompressed data = de 88 75 65 80 +len = 35 + +expected data = 37 47 81 f0 +expected len = 28 +decoded data = 37 47 81 f0 +decoded len = 28 + +Test:6 +Tree based decoding: +uncompressed data = dd 41 00 +len = 18 + +expected data = ff ff ff ff ff ff ff ff ff ff 00 00 +expected len = 90 +decoded data = ff ff ff ff ff ff ff ff ff ff 00 00 +decoded len = 90 + +Test:7 +Tree based decoding: +uncompressed data = 1e 70 c0 +len = 18 + +expected data = +expected len = 0 +decoded data = +decoded len = 19 + +Test:8 +Tree based decoding: +uncompressed data = 00 1e +len = 14 + +Failed to decode CRBB: length 14, data 00 1e +expected data = +expected len = 0 +decoded data = +decoded len = 0 + +Test:9 +Tree based decoding: +uncompressed data = 00 00 00 +len = 24 + +Failed to decode CRBB: length 24, data 00 00 00 +expected data = +expected len = 0 +decoded data = +decoded len = 0 diff --git a/tests/bitcomp/BitcompTest.ok b/tests/bitcomp/BitcompTest.ok new file mode 100644 index 0000000..f7720fc --- /dev/null +++ b/tests/bitcomp/BitcompTest.ok @@ -0,0 +1,2 @@ +=== start test_EPDAN_decode_tree === +=== end test_EPDAN_decode_tree === diff --git a/tests/testsuite.at b/tests/testsuite.at index 1049b31..3ab39cc 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -23,6 +23,14 @@ AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/tbf/TbfTest], [0], [expout], [experr]) AT_CLEANUP + +AT_SETUP([bitcomp]) +AT_KEYWORDS([bitcomp]) +cat $abs_srcdir/bitcomp/BitcompTest.ok > expout +cat $abs_srcdir/bitcomp/BitcompTest.err > experr +AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/bitcomp/BitcompTest], [0], [expout], [experr]) +AT_CLEANUP + AT_SETUP([edge]) AT_KEYWORDS([edge]) cat $abs_srcdir/edge/EdgeTest.ok > expout -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 21 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: pravin From gerrit-no-reply at lists.osmocom.org Thu Aug 25 15:29:17 2016 From: gerrit-no-reply at lists.osmocom.org (bhargava_abhyankar) Date: Thu, 25 Aug 2016 15:29:17 +0000 Subject: [PATCH] osmo-pcu[master]: Update the function immediate assignment for EGPRS In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Harald Welte, Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/431 to look at the new patch set (#5). Update the function immediate assignment for EGPRS Encode the EGPRS fields of immediate assignment message in uplink when EGPRS PACKET CHANNEL REQUEST (11 bit RACH) is received. The series of patches for 11 bit RACH are dependent on libosmocore and osmo-bts patches for 11 bit RACH. Change-Id: Ie5e309156e5dbbb6add74a1b4d257c4ee2332e52 --- M src/bts.cpp M src/encoding.cpp M src/encoding.h M tests/edge/EdgeTest.cpp M tests/tbf/TbfTest.cpp 5 files changed, 88 insertions(+), 13 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/31/431/5 diff --git a/src/bts.cpp b/src/bts.cpp index 63ef1f6..e90f97d 100644 --- a/src/bts.cpp +++ b/src/bts.cpp @@ -555,7 +555,7 @@ plen = Encoding::write_immediate_assignment( tbf, immediate_assignment, 0, ra, Fn, ta, m_bts.trx[trx_no].arfcn, ts_no, tsc, usf, 0, sb_fn, - m_bts.alpha, m_bts.gamma, -1); + m_bts.alpha, m_bts.gamma, -1, burst_type, sb); if (plen >= 0) { pcu_l1if_tx_agch(immediate_assignment, plen); diff --git a/src/encoding.cpp b/src/encoding.cpp index 41e0d10..7d3fa14 100644 --- a/src/encoding.cpp +++ b/src/encoding.cpp @@ -147,11 +147,71 @@ gprs_rlcmac_ul_tbf *tbf, bitvec * dest, unsigned& wp, uint8_t usf, uint32_t fn, - uint8_t alpha, uint8_t gamma, int8_t ta_idx) + uint8_t alpha, uint8_t gamma, int8_t ta_idx, + enum ph_burst_type burst_type, uint16_t ra) { - LOGP(DRLCMACUL, LOGL_ERROR, - "EGPRS Packet Uplink Assignment is not yet implemented\n"); - return -EINVAL; + unsigned int ws_enc = 0; + uint8_t extended_ra = 0; + + extended_ra = (ra & 0x1F); + + bitvec_write_field(dest, wp, 1, 2); /* LH */ + bitvec_write_field(dest, wp, 0, 2); /* 0 EGPRS Uplink Assignment */ + bitvec_write_field(dest, wp, extended_ra, 5); /* Extended RA */ + bitvec_write_field(dest, wp, 0, 1); /* Access technology Request */ + + if (tbf == NULL) { + + bitvec_write_field(dest, wp, 0, 1); /* multiblock allocation */ + + if (alpha) { + bitvec_write_field(dest, wp, 0x1, 1); /* ALPHA =yes */ + bitvec_write_field(dest, wp, alpha, 4); /* ALPHA */ + } else { + bitvec_write_field(dest, wp, 0x0, 1); /* ALPHA = no */ + } + + bitvec_write_field(dest, wp, gamma, 5); /* GAMMA power contrl */ + bitvec_write_field(dest, wp, (fn / (26 * 51)) % 32, 5);/* T1' */ + bitvec_write_field(dest, wp, fn % 51, 6); /* T3 */ + bitvec_write_field(dest, wp, fn % 26, 5); /* T2 */ + bitvec_write_field(dest, wp, 0, 2); /* Radio block allocation */ + + bitvec_write_field(dest, wp, 0, 1); + + } else { + + ws_enc = (tbf->m_window.ws() - 64) / 32; + + bitvec_write_field(dest, wp, 1, 1); /* single block alloc */ + bitvec_write_field(dest, wp, tbf->tfi(), 5);/* TFI assignment */ + bitvec_write_field(dest, wp, 0, 1); /* polling bit */ + bitvec_write_field(dest, wp, 0, 1); /* constant */ + bitvec_write_field(dest, wp, usf, 3); /* USF bit */ + bitvec_write_field(dest, wp, 0, 1); /* USF granularity */ + bitvec_write_field(dest, wp, 0, 1); /* P0 */ + /* MCS */ + bitvec_write_field(dest, wp, tbf->current_cs().to_num()-1, 4); + /* tlli channel block */ + bitvec_write_field(dest, wp, tbf->tlli(), 1); + bitvec_write_field(dest, wp, 0, 1); /* BEP period present */ + bitvec_write_field(dest, wp, 0, 1); /* resegmentation */ + bitvec_write_field(dest, wp, ws_enc, 5);/* egprs window_size */ + + if (alpha) { + bitvec_write_field(dest, wp, 0x1, 1); /* ALPHA =yes */ + bitvec_write_field(dest, wp, alpha, 4); /* ALPHA */ + } else { + bitvec_write_field(dest, wp, 0x0, 1); /* ALPHA = no */ + } + + bitvec_write_field(dest, wp, gamma, 5); /* GAMMA power contrl */ + bitvec_write_field(dest, wp, 0, 1); /* TIMING_ADVANCE_INDEX */ + bitvec_write_field(dest, wp, 0, 1); /* TBF_STARTING_TIME_FLAG */ + bitvec_write_field(dest, wp, 0, 1); /* NULL */ + } + + return 0; } /* @@ -160,10 +220,10 @@ */ int Encoding::write_immediate_assignment( struct gprs_rlcmac_tbf *tbf, - bitvec * dest, uint8_t downlink, uint8_t ra, + bitvec * dest, uint8_t downlink, uint16_t ra, uint32_t ref_fn, uint8_t ta, uint16_t arfcn, uint8_t ts, uint8_t tsc, uint8_t usf, uint8_t polling, uint32_t fn, uint8_t alpha, - uint8_t gamma, int8_t ta_idx) + uint8_t gamma, int8_t ta_idx, enum ph_burst_type burst_type, uint8_t sb) { unsigned wp = 0; int plen; @@ -189,7 +249,13 @@ bitvec_write_field(dest, wp,arfcn,10); // ARFCN //10.5.2.30 Request Reference - bitvec_write_field(dest, wp,ra,8); // RA + if (((burst_type == GSM_L1_BURST_TYPE_ACCESS_1) || + (burst_type == GSM_L1_BURST_TYPE_ACCESS_2))) { + bitvec_write_field(dest, wp, 0x7f, 8); /* RACH value */ + } else { + bitvec_write_field(dest, wp, ra, 8); /* RACH value */ + } + bitvec_write_field(dest, wp,(ref_fn / (26 * 51)) % 32,5); // T1' bitvec_write_field(dest, wp,ref_fn % 51,6); // T3 bitvec_write_field(dest, wp,ref_fn % 26,5); // T2 @@ -213,10 +279,11 @@ rc = write_ia_rest_downlink(as_dl_tbf(tbf), dest, wp, polling, gsm48_ta_is_valid(ta), fn, alpha, gamma, ta_idx); - else if (as_ul_tbf(tbf) && as_ul_tbf(tbf)->is_egprs_enabled()) + else if (((burst_type == GSM_L1_BURST_TYPE_ACCESS_1) || + (burst_type == GSM_L1_BURST_TYPE_ACCESS_2))) rc = write_ia_rest_egprs_uplink(as_ul_tbf(tbf), dest, wp, usf, fn, - alpha, gamma, ta_idx); + alpha, gamma, ta_idx, burst_type, ra); else rc = write_ia_rest_uplink(as_ul_tbf(tbf), dest, wp, usf, fn, diff --git a/src/encoding.h b/src/encoding.h index 710de78..10fc7c2 100644 --- a/src/encoding.h +++ b/src/encoding.h @@ -24,6 +24,10 @@ #include #include +extern "C" { +#include +} + struct gprs_rlcmac_bts; struct gprs_rlcmac_tbf; struct bitvec; @@ -40,11 +44,14 @@ public: static int write_immediate_assignment( struct gprs_rlcmac_tbf *tbf, - bitvec * dest, uint8_t downlink, uint8_t ra, + bitvec * dest, uint8_t downlink, uint16_t ra, uint32_t ref_fn, uint8_t ta, uint16_t arfcn, uint8_t ts, uint8_t tsc, uint8_t usf, uint8_t polling, uint32_t fn, uint8_t alpha, uint8_t gamma, - int8_t ta_idx); + int8_t ta_idx, + enum ph_burst_type burst_type = + GSM_L1_BURST_TYPE_ACCESS_0, + uint8_t sb = 1); static void write_packet_uplink_assignment( struct gprs_rlcmac_bts *bts, diff --git a/tests/edge/EdgeTest.cpp b/tests/edge/EdgeTest.cpp index 9081d4d..0e7378e 100644 --- a/tests/edge/EdgeTest.cpp +++ b/tests/edge/EdgeTest.cpp @@ -36,6 +36,7 @@ #include #include #include +#include } #include diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 7bfe4ca..a4de6c9 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -788,7 +788,7 @@ * simulate RACH, this sends an Immediate * Assignment Uplink on the AGCH */ - the_bts->rcv_rach(0x73, rach_fn, qta); + the_bts->rcv_rach(0x73, rach_fn, qta, 0, GSM_L1_BURST_TYPE_ACCESS_0); /* get next free TFI */ tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1); -- To view, visit https://gerrit.osmocom.org/431 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ie5e309156e5dbbb6add74a1b4d257c4ee2332e52 Gerrit-PatchSet: 5 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: bhargava_abhyankar From gerrit-no-reply at lists.osmocom.org Thu Aug 25 21:15:11 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Thu, 25 Aug 2016 21:15:11 +0000 Subject: openbsc[master]: lchan: Release channel in case of late activation ack In-Reply-To: References: Message-ID: Patch Set 2: > (1 comment) * So set the pchan type to none? Which dynts method to call? * Yes happens if activation got delayed (the lchan user in OpenBSC is gone and all we can do is try to release the channel) -- To view, visit https://gerrit.osmocom.org/713 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I63dc0deaf15ba7c21e20b1e0c7b85f0437e183ed Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Holger Freyther Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Fri Aug 26 10:34:35 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Fri, 26 Aug 2016 10:34:35 +0000 Subject: [PATCH] openbsc[master]: Adding SNDCP-XID encoder / decoder and unit test In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/641 to look at the new patch set (#13). Adding SNDCP-XID encoder / decoder and unit test The SNDCP-XID (or layer-3 xid) is used to exchange layer-3 parameters such as compression. The encoder encodes a bytestream that is then sent as regular XID field from LLC. We will need the SNDCP-XID to negotiate the parameters for our upcomming GPRS data and header compression features Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e --- M openbsc/.gitignore M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_sndcp_xid.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_sndcp_xid.c M openbsc/tests/Makefile.am M openbsc/tests/sgsn/Makefile.am A openbsc/tests/sndcp_xid/Makefile.am A openbsc/tests/sndcp_xid/sndcp_xid_test.c A openbsc/tests/sndcp_xid/sndcp_xid_test.ok M openbsc/tests/testsuite.at 12 files changed, 2,347 insertions(+), 5 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/41/641/13 diff --git a/openbsc/.gitignore b/openbsc/.gitignore index 518a960..8ce3b70 100644 --- a/openbsc/.gitignore +++ b/openbsc/.gitignore @@ -82,6 +82,7 @@ tests/gtphub/gtphub_test tests/mm_auth/mm_auth_test tests/xid/xid_test +tests/sndcp_xid/sndcp_xid_test tests/atconfig tests/atlocal diff --git a/openbsc/configure.ac b/openbsc/configure.ac index fbf2930..53072bd 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -230,6 +230,7 @@ tests/gtphub/Makefile tests/mm_auth/Makefile tests/xid/Makefile + tests/sndcp_xid/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index ce5f768..e200b05 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,7 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_llc_xid.h gprs_sndcp.h + gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_sndcp_xid.h b/openbsc/include/openbsc/gprs_sndcp_xid.h new file mode 100644 index 0000000..02904a7 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_xid.h @@ -0,0 +1,216 @@ +/* GPRS SNDCP XID field encoding/decoding as per 3GPP TS 44.065 */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include + +#define CURRENT_SNDCP_VERSION 0 /* See 3GPP TS 44.065, clause 8 */ +#define MAX_ENTITIES 32 /* 3GPP TS 44.065 reserves 5 bit + * for compression enitity number */ + +#define MAX_COMP 16 /* Maximum number of possible pcomp/dcomp values */ +#define MAX_NSAPI 11 /* Maximum number usable NSAPIs */ +#define MAX_ROHC 16 /* Maximum number of ROHC compression profiles */ + +/* According to: 3GPP TS 44.065, 6.5.1.1 Format of the protocol control + * information compression field (Figure 7) and 3GPP TS 44.065, + * 6.6.1.1 Format of the data compression field (Figure 9) */ +struct gprs_sndcp_comp_field { + struct llist_head list; + + /* Propose bit (P), see also: 6.5.1.1.2 and 6.6.1.1.2 */ + unsigned int p; + + /* Entity number, see also: 6.5.1.1.3 and 6.6.1.1.3 */ + unsigned int entity; + + /* Algorithm identifier, see also: 6.5.1.1.4 and 6.6.1.1.4 */ + int algo; + + /* Number of contained PCOMP / DCOMP values */ + uint8_t comp_len; + + /* PCOMP / DCOMP values, see also: 6.5.1.1.5 and 6.6.1.1.5 */ + uint8_t comp[MAX_COMP]; + + /* Note: Only one of the following struct pointers may, + be used. Unused pointers must be set to NULL! */ + struct gprs_sndcp_pcomp_rfc1144_params *rfc1144_params; + struct gprs_sndcp_pcomp_rfc2507_params *rfc2507_params; + struct gprs_sndcp_pcomp_rohc_params *rohc_params; + struct gprs_sndcp_dcomp_v42bis_params *v42bis_params; + struct gprs_sndcp_dcomp_v44_params *v44_params; +}; + +/* According to: 3GPP TS 44.065, 6.5.1.1.4 Algorithm identifier */ +enum gprs_sndcp_hdr_comp_algo { + RFC_1144, /* TCP/IP header compression, see also 6.5.2 */ + RFC_2507, /* TCP/UDP/IP header compression, see also: 6.5.3 */ + ROHC /* Robust Header Compression, see also 6.5.4 */ +}; + +/* According to: 3GPP TS 44.065, 6.5.1.1.4 Algorithm identifier */ +enum gprs_sndcp_data_comp_algo { + V42BIS, /* V.42bis data compression, see also 6.6.2 */ + V44 /* V44 data compression, see also: 6.6.3 */ +}; + +/* According to: 3GPP TS 44.065, 8 SNDCP XID parameters */ +enum gprs_sndcp_xid_param_types { + SNDCP_XID_VERSION_NUMBER, + SNDCP_XID_DATA_COMPRESSION, /* See also: subclause 6.6.1 */ + SNDCP_XID_PROTOCOL_COMPRESSION, /* See also: subclause 6.5.1 */ +}; + +/* According to: 3GPP TS 44.065, 6.5.2.1 Parameters (Table 5) */ +struct gprs_sndcp_pcomp_rfc1144_params { + uint8_t nsapi_len; /* Number of applicable NSAPIs + * (default 0) */ + uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */ + int s01; /* (default 15) */ +}; + +/* According to: 3GPP TS 44.065, 6.5.2.2 Assignment of PCOMP values */ +enum gprs_sndcp_pcomp_rfc1144_pcomp { + RFC1144_PCOMP1, /* Uncompressed TCP */ + RFC1144_PCOMP2, /* Compressed TCP */ + RFC1144_PCOMP_NUM /* Number of pcomp values */ +}; + +/* According to: 3GPP TS 44.065, 6.5.3.1 Parameters (Table 6) */ +struct gprs_sndcp_pcomp_rfc2507_params { + uint8_t nsapi_len; /* Number of applicable NSAPIs + * (default 0) */ + uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */ + int f_max_period; /* (default 256) */ + int f_max_time; /* (default 5) */ + int max_header; /* (default 168) */ + int tcp_space; /* (default 15) */ + int non_tcp_space; /* (default 15) */ +}; + +/* According to: 3GPP TS 44.065, 6.5.3.2 Assignment of PCOMP values for RFC2507 */ +enum gprs_sndcp_pcomp_rfc2507_pcomp { + RFC2507_PCOMP1, /* Full Header */ + RFC2507_PCOMP2, /* Compressed TCP */ + RFC2507_PCOMP3, /* Compressed TCP non delta */ + RFC2507_PCOMP4, /* Compressed non TCP */ + RFC2507_PCOMP5, /* Context state */ + RFC2507_PCOMP_NUM /* Number of pcomp values */ +}; + +/* According to: 3GPP TS 44.065, 6.5.4.1 Parameter (Table 10) */ +struct gprs_sndcp_pcomp_rohc_params { + uint8_t nsapi_len; /* Number of applicable NSAPIs + * (default 0) */ + uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */ + int max_cid; /* (default 15) */ + int max_header; /* (default 168) */ + uint8_t profile_len; /* (default 1) */ + uint16_t profile[MAX_ROHC]; /* (default 0, ROHC uncompressed) */ +}; + +/* According to: 3GPP TS 44.065, 6.5.4.2 Assignment of PCOMP values for ROHC */ +enum gprs_sndcp_pcomp_rohc_pcomp { + ROHC_PCOMP1, /* ROHC small CIDs */ + ROHC_PCOMP2, /* ROHC large CIDs */ + ROHC_PCOMP_NUM /* Number of pcomp values */ +}; + +/* ROHC compression profiles, see also: + http://www.iana.org/assignments/rohc-pro-ids/rohc-pro-ids.xhtml */ +enum gprs_sndcp_xid_rohc_profiles { + ROHC_UNCOMPRESSED = 0x0000, /* ROHC uncompressed [RFC5795] */ + ROHC_RTP = 0x0001, /* ROHC RTP [RFC3095] */ + ROHCV2_RTP = 0x0101, /* ROHCv2 RTP [RFC5225] */ + ROHC_UDP = 0x0002, /* ROHC UDP [RFC3095] */ + ROHCv2_UDP = 0x0102, /* ROHCv2 UDP [RFC5225] */ + ROHC_ESP = 0x0003, /* ROHC ESP [RFC3095] */ + ROHCV2_ESP = 0x0103, /* ROHCv2 ESP [RFC5225] */ + ROHC_IP = 0x0004, /* ROHC IP [RFC3843] */ + ROHCV2_IP = 0x0104, /* ROHCv2 IP [RFC5225] */ + ROHC_LLA = 0x0005, /* ROHC LLA [RFC4362] */ + ROHC_LLA_WITH_R_MODE = 0x0105, /* ROHC LLA with R-mode [RFC3408] */ + ROHC_TCP = 0x0006, /* ROHC TCP [RFC6846] */ + ROHC_RTP_UDP_LITE = 0x0007, /* ROHC RTP/UDP-Lite [RFC4019] */ + ROHCV2_RTP_UDP_LITE = 0x0107, /* ROHCv2 RTP/UDP-Lite [RFC5225] */ + ROHC_UDP_LITE = 0x0008, /* ROHC UDP-Lite [RFC4019] */ + ROHCV2_UDP_LITE = 0x0108, /* ROHCv2 UDP-Lite [RFC5225] */ +}; + +/* According to: 3GPP TS 44.065, 6.6.2.1 Parameters (Table 7a) */ +struct gprs_sndcp_dcomp_v42bis_params { + uint8_t nsapi_len; /* Number of applicable NSAPIs + * (default 0) */ + uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */ + int p0; /* (default 3) */ + int p1; /* (default 2048) */ + int p2; /* (default 20) */ + +}; + +/* According to: 3GPP TS 44.065, 6.6.2.2 Assignment of DCOMP values */ +enum gprs_sndcp_dcomp_v42bis_dcomp { + V42BIS_DCOMP1, /* V.42bis enabled */ + V42BIS_DCOMP_NUM /* Number of dcomp values */ +}; + +/* According to: 3GPP TS 44.065, 6.6.3.1 Parameters (Table 7c) */ +struct gprs_sndcp_dcomp_v44_params { + uint8_t nsapi_len; /* Number of applicable NSAPIs + * (default 0) */ + uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */ + int c0; /* (default 10000000) */ + int p0; /* (default 3) */ + int p1t; /* Refer to subclause 6.6.3.1.4 */ + int p1r; /* Refer to subclause 6.6.3.1.5 */ + int p3t; /* (default 3 x p1t) */ + int p3r; /* (default 3 x p1r) */ +}; + +/* According to: 3GPP TS 44.065, 6.6.3.2 Assignment of DCOMP values */ +enum gprs_sndcp_dcomp_v44_dcomp { + V44_DCOMP1, /* Packet method compressed */ + V44_DCOMP2, /* Multi packet method compressed */ + V44_DCOMP_NUM /* Number of dcomp values */ +}; + +/* Transform a list with compression fields into an SNDCP-XID message (dst) */ +int gprs_sndcp_compile_xid(uint8_t *dst, unsigned int dst_maxlen, + const struct llist_head *comp_fields); + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +struct llist_head *gprs_sndcp_parse_xid(const void *ctx, + const uint8_t * src, + unsigned int src_len, + const struct llist_head *comp_fields_req); + +/* Find out to which compression class the specified comp-field belongs + * (header compression or data compression?) */ +int gprs_sndcp_get_compression_class( + const struct gprs_sndcp_comp_field *comp_field); + +/* Dump a list with SNDCP-XID fields (Debug) */ +void gprs_sndcp_dump_comp_fields(const struct llist_head *comp_fields, + unsigned int logl); + diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 1b6de46..fa4a3dd 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -26,11 +26,11 @@ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ - oap.c oap_messages.c gprs_llc_xid.c + oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ - $(LIBCRYPTO_LIBS) -lrt + $(LIBCRYPTO_LIBS) -lrt -lm osmo_gtphub_SOURCES = gtphub_main.c gtphub.c gtphub_sock.c gtphub_ares.c \ gtphub_vty.c sgsn_ares.c gprs_utils.c diff --git a/openbsc/src/gprs/gprs_sndcp_xid.c b/openbsc/src/gprs/gprs_sndcp_xid.c new file mode 100644 index 0000000..270bdee --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_xid.c @@ -0,0 +1,1803 @@ +/* GPRS SNDCP XID field encoding/decoding as per 3GPP TS 44.065 */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* When the propose bit in an SNDCP-XID compression field is set to zero, + * the algorithm identifier is stripped. The algoritm parameters are specific + * for each algorithms. The following struct is used to pass the information + * about the referenced algorithm to the parser. */ +struct entity_algo_table { + unsigned int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + unsigned int algo; /* see also: 6.5.1.1.4 and 6.6.1.1.4 */ + unsigned int compclass; /* Can be either SNDCP_XID_DATA_COMPRESSION or + SNDCP_XID_PROTOCOL_COMPRESSION */ +}; + +/* FUNCTIONS RELATED TO SNDCP-XID ENCODING */ + +/* Encode applicable sapis (works the same in all three compression schemes) */ +static int encode_pcomp_applicable_sapis(uint8_t *dst, + const uint8_t *nsapis, + uint8_t nsapis_len) +{ + /* NOTE: Buffer *dst needs offer at 2 bytes + * of space to store the generation results */ + + uint16_t blob; + uint8_t nsapi; + int i; + + /* Bail if number of possible nsapis exceeds valid range + * (Only 11 nsapis possible for PDP-Contexts) */ + OSMO_ASSERT(nsapis_len <= 11); + + /* Encode applicable SAPIs */ + blob = 0; + for (i = 0; i < nsapis_len; i++) { + nsapi = nsapis[i]; + /* Only NSAPI 5 to 15 are applicable for user traffic (PDP- + * contexts). Only for these NSAPIs SNDCP-XID parameters + * can apply. See also 3GPP TS 44.065, 5.1 Service primitives */ + OSMO_ASSERT(nsapi >= 5 && nsapi <= 15); + blob |= (1 << nsapi); + } + + /* Store result */ + *dst = (blob >> 8) & 0xFF; + dst++; + *dst = blob & 0xFF; + + return 2; +} + +/* Encode rfc1144 parameter field + * (see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */ +static int encode_pcomp_rfc1144_params(uint8_t *dst, unsigned int dst_maxlen, + const struct + gprs_sndcp_pcomp_rfc1144_params *params) +{ + /* NOTE: Buffer *dst should offer at least 3 bytes + * of space to store the generation results */ + + int dst_counter = 0; + int rc; + + OSMO_ASSERT(dst_maxlen >= 3); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode s01 (see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */ + OSMO_ASSERT(params->s01 >= 0); + OSMO_ASSERT(params->s01 <= 255); + *dst = params->s01; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + +/* + * Encode rfc2507 parameter field + * (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) + */ +static int encode_pcomp_rfc2507_params(uint8_t *dst, unsigned int dst_maxlen, + const struct + gprs_sndcp_pcomp_rfc2507_params *params) +{ + /* NOTE: Buffer *dst should offer at least 3 bytes + * of space to store the generation results */ + + int dst_counter = 0; + int rc; + + OSMO_ASSERT(dst_maxlen >= 9); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode F_MAX_PERIOD (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->f_max_period >= 1); + OSMO_ASSERT(params->f_max_period <= 65535); + *dst = (params->f_max_period >> 8) & 0xFF; + dst++; + dst_counter++; + *dst = (params->f_max_period) & 0xFF; + dst++; + dst_counter++; + + /* Encode F_MAX_TIME (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->f_max_time >= 1); + OSMO_ASSERT(params->f_max_time <= 255); + *dst = params->f_max_time; + dst++; + dst_counter++; + + /* Encode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->max_header >= 60); + OSMO_ASSERT(params->max_header <= 255); + *dst = params->max_header; + dst++; + dst_counter++; + + /* Encode TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->tcp_space >= 3); + OSMO_ASSERT(params->tcp_space <= 255); + *dst = params->tcp_space; + dst++; + dst_counter++; + + /* Encode NON_TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->non_tcp_space >= 3); + OSMO_ASSERT(params->non_tcp_space <= 65535); + *dst = (params->non_tcp_space >> 8) & 0xFF; + dst++; + dst_counter++; + *dst = (params->non_tcp_space) & 0xFF; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + +/* Encode ROHC parameter field + * (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ +static int encode_pcomp_rohc_params(uint8_t *dst, unsigned int dst_maxlen, + const struct gprs_sndcp_pcomp_rohc_params + *params) +{ + /* NOTE: Buffer *dst should offer at least 36 + * (2 * 16 Profiles + 2 * 3 Parameter) bytes + * of memory space to store generation results */ + + int i; + int dst_counter = 0; + int rc; + + OSMO_ASSERT(dst_maxlen >= 38); + + /* Bail if number of ROHC profiles exceeds limit + * (ROHC supports only a maximum of 16 different profiles) */ + OSMO_ASSERT(params->profile_len >= 0); + OSMO_ASSERT(params->profile_len <= 16); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode MAX_CID (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + OSMO_ASSERT(params->max_cid >= 0); + OSMO_ASSERT(params->max_cid <= 16383); + *dst = (params->max_cid >> 8) & 0xFF; + dst++; + *dst = params->max_cid & 0xFF; + dst++; + dst_counter += 2; + + /* Encode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + OSMO_ASSERT(params->max_header >= 60); + OSMO_ASSERT(params->max_header <= 255); + *dst = (params->max_header >> 8) & 0xFF; + dst++; + *dst = params->max_header & 0xFF; + dst++; + dst_counter += 2; + + /* Encode ROHC Profiles (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + for (i = 0; i < params->profile_len; i++) { + *dst = (params->profile[i] >> 8) & 0xFF; + dst++; + *dst = params->profile[i] & 0xFF; + dst++; + dst_counter += 2; + } + + /* Return generated length */ + return dst_counter; +} + +/* Encode V.42bis parameter field + * (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ +static int encode_dcomp_v42bis_params(uint8_t *dst, unsigned int dst_maxlen, + const struct + gprs_sndcp_dcomp_v42bis_params *params) +{ + /* NOTE: Buffer *dst should offer at least 6 bytes + * of space to store the generation results */ + + int dst_counter = 0; + int rc; + + OSMO_ASSERT(dst_maxlen >= 6); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode P0 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + OSMO_ASSERT(params->p0 >= 0); + OSMO_ASSERT(params->p0 <= 3); + *dst = params->p0 & 0x03; + dst++; + dst_counter++; + + /* Encode P1 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + OSMO_ASSERT(params->p1 >= 512); + OSMO_ASSERT(params->p1 <= 65535); + *dst = (params->p1 >> 8) & 0xFF; + dst++; + *dst = params->p1 & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P2 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + OSMO_ASSERT(params->p2 >= 6); + OSMO_ASSERT(params->p2 <= 250); + *dst = params->p2; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + +/* Encode V44 parameter field + * (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ +static int encode_dcomp_v44_params(uint8_t *dst, unsigned int dst_maxlen, + const struct gprs_sndcp_dcomp_v44_params + *params) +{ + /* NOTE: Buffer *dst should offer at least 12 bytes + * of space to store the generation results */ + + int dst_counter = 0; + int rc; + + OSMO_ASSERT(dst_maxlen >= 12); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode C0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->c0 == 0x80 || params->c0 == 0xC0); + *dst = params->c0 & 0xC0; + dst++; + dst_counter++; + + /* Encode P0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p0 >= 0); + OSMO_ASSERT(params->p0 <= 3); + *dst = params->p0 & 0x03; + dst++; + dst_counter++; + + /* Encode P1T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p1t >= 256); + OSMO_ASSERT(params->p1t <= 65535); + *dst = (params->p1t >> 8) & 0xFF; + dst++; + *dst = params->p1t & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P1R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p1r >= 256); + OSMO_ASSERT(params->p1r <= 65535); + *dst = (params->p1r >> 8) & 0xFF; + dst++; + *dst = params->p1r & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P3T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p3t >= 0); + OSMO_ASSERT(params->p3t <= 65535); + OSMO_ASSERT(params->p3t >= 2 * params->p1t); + *dst = (params->p3t >> 8) & 0xFF; + dst++; + *dst = params->p3t & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P3R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p3r >= 0); + OSMO_ASSERT(params->p3r <= 65535); + OSMO_ASSERT(params->p3r >= 2 * params->p1r); + *dst = (params->p3r >> 8) & 0xFF; + dst++; + *dst = params->p3r & 0xFF; + dst++; + dst_counter += 2; + + /* Return generated length */ + return dst_counter; +} + +/* Encode data or protocol control information compression field + * (see also: 3GPP TS 44.065, 6.6.1.1, Figure 9 and + * 3GPP TS 44.065, 6.5.1.1, Figure 7) */ +static int encode_comp_field(uint8_t *dst, unsigned int dst_maxlen, + const struct gprs_sndcp_comp_field *comp_field) +{ + int dst_counter = 0; + int len; + int expected_length; + int i; + + uint8_t payload_bytes[256]; + int payload_bytes_len = -1; + + /* If possible, try do encode payload bytes first */ + if (comp_field->rfc1144_params) { + payload_bytes_len = + encode_pcomp_rfc1144_params(payload_bytes, + sizeof(payload_bytes), + comp_field->rfc1144_params); + } else if (comp_field->rfc2507_params) { + payload_bytes_len = + encode_pcomp_rfc2507_params(payload_bytes, + sizeof(payload_bytes), + comp_field->rfc2507_params); + } else if (comp_field->rohc_params) { + payload_bytes_len = + encode_pcomp_rohc_params(payload_bytes, + sizeof(payload_bytes), + comp_field->rohc_params); + } else if (comp_field->v42bis_params) { + payload_bytes_len = + encode_dcomp_v42bis_params(payload_bytes, + sizeof(payload_bytes), + comp_field->v42bis_params); + } else if (comp_field->v44_params) { + payload_bytes_len = + encode_dcomp_v44_params(payload_bytes, + sizeof(payload_bytes), + comp_field->v44_params); + } else + OSMO_ASSERT(false); + + /* Bail immediately if payload byte generation failed */ + OSMO_ASSERT(payload_bytes_len >= 0); + + /* Bail if comp_len is out of bounds */ + OSMO_ASSERT(comp_field->comp_len <= sizeof(comp_field->comp)); + + /* Calculate length field of the data block */ + if (comp_field->p) { + len = + payload_bytes_len + + ceil((double)(comp_field->comp_len) / 2.0); + expected_length = len + 3; + } else { + len = payload_bytes_len; + expected_length = len + 2; + } + + /* Bail immediately if no sufficient memory space is supplied */ + OSMO_ASSERT(dst_maxlen >= expected_length); + + /* Check if the entity number is within bounds */ + OSMO_ASSERT(comp_field->entity <= 0x1f); + + /* Check if the algorithm number is within bounds */ + OSMO_ASSERT(comp_field->algo >= 0 || comp_field->algo <= 0x1f); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode Propose bit */ + if (comp_field->p) + *dst |= (1 << 7); + + /* Encode entity number */ + *dst |= comp_field->entity & 0x1F; + dst++; + dst_counter++; + + /* Encode algorithm number */ + if (comp_field->p) { + *dst |= comp_field->algo & 0x1F; + dst++; + dst_counter++; + } + + /* Encode length field */ + *dst |= len & 0xFF; + dst++; + dst_counter++; + + /* Encode PCOMP/DCOMP values */ + if (comp_field->p) { + for (i = 0; i < comp_field->comp_len; i++) { + /* Check if submitted PCOMP/DCOMP + values are within bounds */ + if ((comp_field->comp[i] < 0) + || (comp_field->comp[i] > 0x0F)) + return -EINVAL; + + if (i & 1) { + *dst |= comp_field->comp[i] & 0x0F; + dst++; + dst_counter++; + } else + *dst |= (comp_field->comp[i] << 4) & 0xF0; + } + + if (i & 1) { + dst++; + dst_counter++; + } + } + + /* Append payload bytes */ + memcpy(dst, payload_bytes, payload_bytes_len); + dst_counter += payload_bytes_len; + + /* Return generated length */ + return dst_counter; +} + +/* Find out to which compression class the specified comp-field belongs + * (header compression or data compression?) */ +int gprs_sndcp_get_compression_class(const struct gprs_sndcp_comp_field + *comp_field) +{ + OSMO_ASSERT(comp_field); + + if (comp_field->rfc1144_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->rfc2507_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->rohc_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->v42bis_params) + return SNDCP_XID_DATA_COMPRESSION; + else if (comp_field->v44_params) + return SNDCP_XID_DATA_COMPRESSION; + else + return -EINVAL; +} + +/* Convert all compression fields to bytstreams */ +static int gprs_sndcp_pack_fields(const struct llist_head *comp_fields, + uint8_t *dst, + unsigned int dst_maxlen, int class) +{ + struct gprs_sndcp_comp_field *comp_field; + int byte_counter = 0; + int rc; + + llist_for_each_entry_reverse(comp_field, comp_fields, list) { + if (class == gprs_sndcp_get_compression_class(comp_field)) { + rc = encode_comp_field(dst + byte_counter, + dst_maxlen - byte_counter, + comp_field); + + /* When input data is correct, there is + * no reason for the encoder to fail! */ + OSMO_ASSERT(rc >= 0); + + byte_counter += rc; + } + } + + /* Return generated length */ + return byte_counter; +} + +/* Transform a list with compression fields into an SNDCP-XID message (dst) */ +int gprs_sndcp_compile_xid(uint8_t *dst, unsigned int dst_maxlen, + const struct llist_head *comp_fields) +{ + int rc; + int byte_counter = 0; + uint8_t comp_bytes[512]; + uint8_t xid_version_number[1] = { CURRENT_SNDCP_VERSION }; + + OSMO_ASSERT(comp_fields); + OSMO_ASSERT(dst); + OSMO_ASSERT(dst_maxlen >= 2 + sizeof(xid_version_number)); + + /* Bail if there is no input */ + if (llist_empty(comp_fields)) + return -EINVAL; + + /* Prepend header */ + dst = + tlv_put(dst, SNDCP_XID_VERSION_NUMBER, + sizeof(xid_version_number), xid_version_number); + byte_counter += (sizeof(xid_version_number) + 2); + + /* Add data compression fields */ + rc = gprs_sndcp_pack_fields(comp_fields, comp_bytes, + sizeof(comp_bytes), + SNDCP_XID_DATA_COMPRESSION); + OSMO_ASSERT(rc >= 0); + + if (rc > 0) { + dst = tlv_put(dst, SNDCP_XID_DATA_COMPRESSION, rc, comp_bytes); + byte_counter += rc + 2; + } + + /* Add header compression fields */ + rc = gprs_sndcp_pack_fields(comp_fields, comp_bytes, + sizeof(comp_bytes), + SNDCP_XID_PROTOCOL_COMPRESSION); + OSMO_ASSERT(rc >= 0); + + if (rc > 0) { + dst = tlv_put(dst, SNDCP_XID_PROTOCOL_COMPRESSION, rc, + comp_bytes); + byte_counter += rc + 2; + } + + /* Return generated length */ + return byte_counter; +} + +/* FUNCTIONS RELATED TO SNDCP-XID DECODING */ + +/* Decode applicable sapis (works the same in all three compression schemes) */ +static int decode_pcomp_applicable_sapis(uint8_t *nsapis, + uint8_t *nsapis_len, + const uint8_t *src, + unsigned int src_len) +{ + uint16_t blob; + int i; + int nsapi_len = 0; + + /* Exit immediately if no result can be stored */ + if (!nsapis) + return -EINVAL; + + /* Exit immediately if not enough input data is available */ + if (src_len < 2) + return -EINVAL; + + /* Read bitmask */ + blob = *src; + blob = (blob << 8) & 0xFF00; + src++; + blob |= (*src) & 0xFF; + blob = (blob >> 5); + + /* Decode applicable SAPIs */ + for (i = 0; i < 15; i++) { + if ((blob >> i) & 1) { + nsapis[nsapi_len] = i + 5; + nsapi_len++; + } + } + + /* Return consumed length */ + *nsapis_len = nsapi_len; + return 2; +} + +/* Decode 16 bit field */ +static int decode_pcomp_16_bit_field(int *value_int, uint16_t * value_uint16, + const uint8_t *src, + unsigned int src_len, + int value_min, int value_max) +{ + uint16_t blob; + + /* Reset values to zero (just to be sure) */ + if (value_int) + *value_int = -1; + if (value_uint16) + *value_uint16 = 0; + + /* Exit if not enough src are available */ + if (src_len < 2) + return -EINVAL; + + /* Decode bit value */ + blob = *src; + blob = (blob << 8) & 0xFF00; + src++; + blob |= *src; + + /* Check if parsed value is within bounds */ + if (blob < value_min) + return -EINVAL; + if (blob > value_max) + return -EINVAL; + + /* Hand back results to the caller */ + if (value_int) + *value_int = blob; + if (value_uint16) + *value_uint16 = blob; + + /* Return consumed length */ + return 2; +} + +/* Decode 8 bit field */ +static int decode_pcomp_8_bit_field(int *value_int, uint8_t *value_uint8, + const uint8_t *src, + unsigned int src_len, + int value_min, int value_max) +{ + uint8_t blob; + + /* Reset values to invalid (just to be sure) */ + if (value_int) + *value_int = -1; + if (value_uint8) + *value_uint8 = 0; + + /* Exit if not enough src are available */ + if (src_len < 1) + return -EINVAL; + + /* Decode bit value */ + blob = *src; + + /* Check if parsed value is within bounds */ + if (blob < value_min) + return -EINVAL; + if (blob > value_max) + return -EINVAL; + + /* Hand back results to the caller */ + if (value_int) + *value_int = blob; + if (value_uint8) + *value_uint8 = blob; + + /* Return consumed length */ + return 1; +} + +/* Decode rfc1144 parameter field see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */ +static int decode_pcomp_rfc1144_params(struct gprs_sndcp_pcomp_rfc1144_params + *params, const uint8_t *src, + unsigned int src_len) +{ + int rc; + int byte_counter = 0; + + /* Mark all optional parameters invalid by default */ + params->s01 = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode parameter S0 -1 + * (see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */ + rc = decode_pcomp_8_bit_field(¶ms->s01, NULL, src, + src_len - byte_counter, 0, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Decode rfc2507 parameter field + * (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ +static int decode_pcomp_rfc2507_params(struct gprs_sndcp_pcomp_rfc2507_params + *params, const uint8_t *src, + unsigned int src_len) +{ + int rc; + int byte_counter = 0; + + /* Mark all optional parameters invalid by default */ + params->f_max_period = -1; + params->f_max_time = -1; + params->max_header = -1; + params->tcp_space = -1; + params->non_tcp_space = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode F_MAX_PERIOD (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_16_bit_field(¶ms->f_max_period, NULL, src, + src_len - byte_counter, 1, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode F_MAX_TIME (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_8_bit_field(¶ms->f_max_time, NULL, src, + src_len - byte_counter, 1, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_8_bit_field(¶ms->max_header, NULL, src, + src_len - byte_counter, 60, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_8_bit_field(¶ms->tcp_space, NULL, src, + src_len - byte_counter, 3, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode NON_TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_16_bit_field(¶ms->non_tcp_space, NULL, src, + src_len - byte_counter, 3, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Decode ROHC parameter field (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ +static int decode_pcomp_rohc_params(struct gprs_sndcp_pcomp_rohc_params *params, + const uint8_t *src, unsigned int src_len) +{ + int rc; + int byte_counter = 0; + int i; + + /* Mark all optional parameters invalid by default */ + params->max_cid = -1; + params->max_header = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_CID (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + rc = decode_pcomp_16_bit_field(¶ms->max_cid, NULL, src, + src_len - byte_counter, 0, 16383); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + rc = decode_pcomp_16_bit_field(¶ms->max_header, NULL, src, + src_len - byte_counter, 60, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode Profiles (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + for (i = 0; i < 16; i++) { + params->profile_len = 0; + rc = decode_pcomp_16_bit_field(NULL, ¶ms->profile[i], src, + src_len - byte_counter, 0, + 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + params->profile_len = i + 1; + } + + /* Return consumed length */ + return byte_counter; +} + +/* Decode V.42bis parameter field + * (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ +static int decode_dcomp_v42bis_params(struct gprs_sndcp_dcomp_v42bis_params + *params, const uint8_t *src, + unsigned int src_len) +{ + int rc; + int byte_counter = 0; + + /* Mark all optional parameters invalid by default */ + params->p0 = -1; + params->p1 = -1; + params->p2 = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode P0 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + rc = decode_pcomp_8_bit_field(¶ms->p0, NULL, src, + src_len - byte_counter, 0, 3); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + rc = decode_pcomp_16_bit_field(¶ms->p1, NULL, src, + src_len - byte_counter, 512, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P2 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + rc = decode_pcomp_8_bit_field(¶ms->p2, NULL, src, + src_len - byte_counter, 6, 250); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Decode V44 parameter field (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ +static int decode_dcomp_v44_params(struct gprs_sndcp_dcomp_v44_params *params, + const uint8_t *src, unsigned int src_len) +{ + int rc; + int byte_counter = 0; + + /* Mark all optional parameters invalid by default */ + params->c0 = -1; + params->p0 = -1; + params->p1t = -1; + params->p1r = -1; + params->p3t = -1; + params->p3r = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode C0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_8_bit_field(¶ms->c0, NULL, src, + src_len - byte_counter, 0, 255); + if (rc <= 0) + return byte_counter; + if ((params->c0 != 0x80) && (params->c0 != 0xC0)) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Decode P0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_8_bit_field(¶ms->p0, NULL, src, + src_len - byte_counter, 0, 3); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_16_bit_field(¶ms->p1t, NULL, src, + src_len - byte_counter, 265, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_16_bit_field(¶ms->p1r, NULL, src, + src_len - byte_counter, 265, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P3T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_16_bit_field(¶ms->p3t, NULL, src, + src_len - byte_counter, 265, 65535); + if (rc <= 0) + return byte_counter; + if (params->p3t < 2 * params->p1t) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Decode P3R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_16_bit_field(¶ms->p3r, NULL, src, + src_len - byte_counter, 265, 65535); + if (rc <= 0) + return byte_counter; + if (params->p3r < 2 * params->p1r) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Lookup algorithm identfier by entity ID */ +static int lookup_algorithm_identifier(int entity, const struct + entity_algo_table + *lt, unsigned int lt_len, int compclass) +{ + int i; + + if (!lt) + return -1; + + for (i = 0; i < lt_len; i++) { + if ((lt[i].entity == entity) + && (lt[i].compclass == compclass)) + return lt[i].algo; + } + + return -1; +} + +/* Helper function for decode_comp_field(), decodes + * numeric pcomp/dcomp values */ +static int decode_comp_values(struct gprs_sndcp_comp_field *comp_field, + const uint8_t *src, int compclass) +{ + int src_counter = 0; + int i; + + if (comp_field->p) { + /* Determine the number of expected PCOMP/DCOMP values */ + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + /* For protocol compression */ + switch (comp_field->algo) { + case RFC_1144: + comp_field->comp_len = RFC1144_PCOMP_NUM; + break; + case RFC_2507: + comp_field->comp_len = RFC2507_PCOMP_NUM; + break; + case ROHC: + comp_field->comp_len = ROHC_PCOMP_NUM; + break; + + /* Exit if the algorithem type encodes + something unknown / unspecified */ + default: + return -EINVAL; + } + } else { + /* For data compression */ + switch (comp_field->algo) { + case V42BIS: + comp_field->comp_len = V42BIS_DCOMP_NUM; + break; + case V44: + comp_field->comp_len = V44_DCOMP_NUM; + break; + + /* Exit if the algorithem type encodes + something unknown / unspecified */ + default: + return -EINVAL; + } + } + + for (i = 0; i < comp_field->comp_len; i++) { + if (i & 1) { + comp_field->comp[i] = (*src) & 0x0F; + src++; + src_counter++; + } else + comp_field->comp[i] = ((*src) >> 4) & 0x0F; + } + + if (i & 1) { + src++; + src_counter++; + } + } + + return src_counter; +} + +/* Helper function for decode_comp_field(), decodes the parameters + * which are protocol compression specific */ +static int decode_pcomp_params(struct gprs_sndcp_comp_field *comp_field, + const uint8_t *src, int src_len) +{ + int rc; + + switch (comp_field->algo) { + case RFC_1144: + comp_field->rfc1144_params = talloc_zero(comp_field, struct + gprs_sndcp_pcomp_rfc1144_params); + rc = decode_pcomp_rfc1144_params(comp_field->rfc1144_params, + src, src_len); + if (rc < 0) + talloc_free(comp_field->rfc1144_params); + break; + case RFC_2507: + comp_field->rfc2507_params = talloc_zero(comp_field, struct + gprs_sndcp_pcomp_rfc2507_params); + rc = decode_pcomp_rfc2507_params(comp_field->rfc2507_params, + src, src_len); + if (rc < 0) + talloc_free(comp_field->rfc1144_params); + break; + case ROHC: + comp_field->rohc_params = talloc_zero(comp_field, struct + gprs_sndcp_pcomp_rohc_params); + rc = decode_pcomp_rohc_params(comp_field->rohc_params, src, + src_len); + if (rc < 0) + talloc_free(comp_field->rohc_params); + break; + + /* If no suitable decoder is detected, + leave the remaining bytes undecoded */ + default: + rc = src_len; + } + + if (rc < 0) { + comp_field->rfc1144_params = NULL; + comp_field->rfc2507_params = NULL; + comp_field->rohc_params = NULL; + } + + return rc; +} + +/* Helper function for decode_comp_field(), decodes the parameters + * which are data compression specific */ +static int decode_dcomp_params(struct gprs_sndcp_comp_field *comp_field, + const uint8_t *src, int src_len) +{ + int rc; + + switch (comp_field->algo) { + case V42BIS: + comp_field->v42bis_params = talloc_zero(comp_field, struct + gprs_sndcp_dcomp_v42bis_params); + rc = decode_dcomp_v42bis_params(comp_field->v42bis_params, src, + src_len); + if (rc < 0) + talloc_free(comp_field->v42bis_params); + break; + case V44: + comp_field->v44_params = talloc_zero(comp_field, struct + gprs_sndcp_dcomp_v44_params); + rc = decode_dcomp_v44_params(comp_field->v44_params, src, + src_len); + if (rc < 0) + talloc_free(comp_field->v44_params); + break; + + /* If no suitable decoder is detected, + * leave the remaining bytes undecoded */ + default: + rc = src_len; + } + + if (rc < 0) { + comp_field->v42bis_params = NULL; + comp_field->v44_params = NULL; + } + + return rc; +} + +/* Decode data or protocol control information compression field + * (see also: 3GPP TS 44.065, 6.6.1.1, Figure 9 and + * 3GPP TS 44.065, 6.5.1.1, Figure 7) */ +static int decode_comp_field(struct gprs_sndcp_comp_field *comp_field, + const uint8_t *src, unsigned int src_len, + const struct entity_algo_table *lt, + unsigned int lt_len, int compclass) +{ + int src_counter = 0; + unsigned int len; + int rc; + + OSMO_ASSERT(comp_field); + + /* Exit immediately if it is clear that no + parseable data is present */ + if (src_len < 1 || !src) + return -EINVAL; + + /* Zero out target struct */ + memset(comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + + /* Decode Propose bit and Entity number */ + if ((*src) & 0x80) + comp_field->p = 1; + comp_field->entity = (*src) & 0x1F; + src_counter++; + src++; + + /* Decode algorithm number (if present) */ + if (comp_field->p) { + comp_field->algo = (*src) & 0x1F; + src_counter++; + src++; + } + /* Alternatively take the information from the lookup table */ + else + comp_field->algo = + lookup_algorithm_identifier(comp_field->entity, lt, + lt_len, compclass); + + /* Decode length field */ + len = *src; + src_counter++; + src++; + + /* Decode PCOMP/DCOMP values */ + rc = decode_comp_values(comp_field, src, compclass); + if (rc < 0) + return -EINVAL; + src_counter += rc; + src += rc; + len -= rc; + + /* Decode algorithm specific payload data */ + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + rc = decode_pcomp_params(comp_field, src, len); + else if (compclass == SNDCP_XID_DATA_COMPRESSION) + rc = decode_dcomp_params(comp_field, src, len); + else + return -EINVAL; + + if (rc >= 0) + src_counter += rc; + else + return -EINVAL; + + /* Return consumed length */ + return src_counter; +} + +/* Helper function for gprs_sndcp_decode_xid() to decode XID blocks */ +static int decode_xid_block(struct llist_head *comp_fields, uint8_t tag, + uint16_t tag_len, const uint8_t *val, + const struct entity_algo_table *lt, + unsigned int lt_len) +{ + struct gprs_sndcp_comp_field *comp_field; + int byte_counter = 0; + int comp_field_count = 0; + int rc; + + byte_counter = 0; + do { + /* Bail if more than the maximum number of + comp_fields is generated */ + if (comp_field_count > MAX_ENTITIES * 2) { + return -EINVAL; + } + + /* Parse and add comp_field */ + comp_field = + talloc_zero(comp_fields, struct gprs_sndcp_comp_field); + + rc = decode_comp_field(comp_field, val + byte_counter, + tag_len - byte_counter, lt, lt_len, tag); + + if (rc < 0) { + talloc_free(comp_field); + return -EINVAL; + } + + byte_counter += rc; + llist_add(&comp_field->list, comp_fields); + comp_field_count++; + } + while (tag_len - byte_counter > 0); + + return byte_counter; +} + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +static int gprs_sndcp_decode_xid(struct llist_head *comp_fields, + const uint8_t *src, unsigned int src_len, + const struct + entity_algo_table + *lt, unsigned int lt_len) +{ + int src_pos = 0; + uint8_t tag; + uint16_t tag_len; + const uint8_t *val; + int byte_counter = 0; + int rc; + int tlv_count = 0; + + /* Valid TLV-Tag and types */ + static const struct tlv_definition sndcp_xid_def = { + .def = { + [SNDCP_XID_VERSION_NUMBER] = {TLV_TYPE_TLV,}, + [SNDCP_XID_DATA_COMPRESSION] = {TLV_TYPE_TLV,}, + [SNDCP_XID_PROTOCOL_COMPRESSION] = {TLV_TYPE_TLV,}, + }, + }; + + /* Parse TLV-Encoded SNDCP-XID message and defer payload + to the apporpiate sub-parser functions */ + while (1) { + + /* Bail if an the maximum number of TLV fields + * have been parsed */ + if (tlv_count >= 3) { + talloc_free(comp_fields); + return -EINVAL; + } + + /* Parse TLV field */ + rc = tlv_parse_one(&tag, &tag_len, &val, &sndcp_xid_def, + src + src_pos, src_len - src_pos); + if (rc > 0) + src_pos += rc; + else { + talloc_free(comp_fields); + return -EINVAL; + } + + /* Decode compression parameters */ + if ((tag == SNDCP_XID_PROTOCOL_COMPRESSION) + || (tag == SNDCP_XID_DATA_COMPRESSION)) { + rc = decode_xid_block(comp_fields, tag, tag_len, val, + lt, lt_len); + + if (rc < 0) { + talloc_free(comp_fields); + return -EINVAL; + } else + byte_counter += rc; + } + + /* Stop when no further TLV elements can be expected */ + if (src_len - src_pos <= 2) + break; + + tlv_count++; + } + + return 0; +} + +/* Fill up lookutable from a list with comression entitiy fields */ +static int gprs_sndcp_fill_table(struct + entity_algo_table *lt, + unsigned int lt_len, + const struct llist_head *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field; + int i = 0; + + if (!comp_fields) + return -EINVAL; + if (!lt) + return -EINVAL; + + memset(lt, 0, lt_len * sizeof(lt)); + + llist_for_each_entry(comp_field, comp_fields, list) { + + lt[i].entity = comp_field->entity; + lt[i].algo = comp_field->algo; + lt[i].compclass = gprs_sndcp_get_compression_class(comp_field); + + if (lt[i].compclass < 0) { + memset(lt, 0, lt_len * sizeof(lt)); + return -EINVAL; + } + + i++; + } + + return i; +} + +/* Complete comp field params + * (if a param (dst) is not valid, it will be copied from source (src) */ +static int complete_comp_field_params(struct gprs_sndcp_comp_field + *comp_field_dst, const struct + gprs_sndcp_comp_field *comp_field_src) +{ + if (comp_field_dst->algo < 0) + return -EINVAL; + + if (comp_field_dst->rfc1144_params && comp_field_src->rfc1144_params) { + if (comp_field_dst->rfc1144_params->s01 < 0) { + comp_field_dst->rfc1144_params->s01 = + comp_field_src->rfc1144_params->s01; + } + return 0; + } + + if (comp_field_dst->rfc2507_params && comp_field_src->rfc2507_params) { + + if (comp_field_dst->rfc2507_params->f_max_period < 0) { + comp_field_dst->rfc2507_params->f_max_period = + comp_field_src->rfc2507_params->f_max_period; + } + if (comp_field_dst->rfc2507_params->f_max_time < 0) { + comp_field_dst->rfc2507_params->f_max_time = + comp_field_src->rfc2507_params->f_max_time; + } + if (comp_field_dst->rfc2507_params->max_header < 0) { + comp_field_dst->rfc2507_params->max_header = + comp_field_src->rfc2507_params->max_header; + } + if (comp_field_dst->rfc2507_params->tcp_space < 0) { + comp_field_dst->rfc2507_params->tcp_space = + comp_field_src->rfc2507_params->tcp_space; + } + if (comp_field_dst->rfc2507_params->non_tcp_space < 0) { + comp_field_dst->rfc2507_params->non_tcp_space = + comp_field_src->rfc2507_params->non_tcp_space; + } + return 0; + } + + if (comp_field_dst->rohc_params && comp_field_src->rohc_params) { + if (comp_field_dst->rohc_params->max_cid < 0) { + comp_field_dst->rohc_params->max_cid = + comp_field_src->rohc_params->max_cid; + } + if (comp_field_dst->rohc_params->max_header < 0) { + comp_field_dst->rohc_params->max_header = + comp_field_src->rohc_params->max_header; + } + if (comp_field_dst->rohc_params->profile_len > 0) { + memcpy(comp_field_dst->rohc_params->profile, + comp_field_src->rohc_params->profile, + sizeof(comp_field_dst->rohc_params->profile)); + comp_field_dst->rohc_params->profile_len = + comp_field_src->rohc_params->profile_len; + } + + return 0; + } + + if (comp_field_dst->v42bis_params && comp_field_src->v42bis_params) { + if (comp_field_dst->v42bis_params->p0 < 0) { + comp_field_dst->v42bis_params->p0 = + comp_field_src->v42bis_params->p0; + } + if (comp_field_dst->v42bis_params->p1 < 0) { + comp_field_dst->v42bis_params->p1 = + comp_field_src->v42bis_params->p1; + } + if (comp_field_dst->v42bis_params->p2 < 0) { + comp_field_dst->v42bis_params->p2 = + comp_field_src->v42bis_params->p2; + } + return 0; + } + + if (comp_field_dst->v44_params && comp_field_src->v44_params) { + if (comp_field_dst->v44_params->c0 < 0) { + comp_field_dst->v44_params->c0 = + comp_field_src->v44_params->c0; + } + if (comp_field_dst->v44_params->p0 < 0) { + comp_field_dst->v44_params->p0 = + comp_field_src->v44_params->p0; + } + if (comp_field_dst->v44_params->p1t < 0) { + comp_field_dst->v44_params->p1t = + comp_field_src->v44_params->p1t; + } + if (comp_field_dst->v44_params->p1r < 0) { + comp_field_dst->v44_params->p1r = + comp_field_src->v44_params->p1r; + } + if (comp_field_dst->v44_params->p3t < 0) { + comp_field_dst->v44_params->p3t = + comp_field_src->v44_params->p3t; + } + if (comp_field_dst->v44_params->p3r < 0) { + comp_field_dst->v44_params->p3r = + comp_field_src->v44_params->p3r; + } + return 0; + } + + /* There should be at least exist one param set + * in the destination struct, otherwise something + * must be wrong! */ + return -EINVAL; +} + +/* Complete missing parameters in a comp_field */ +static int gprs_sndcp_complete_comp_field(struct gprs_sndcp_comp_field + *comp_field, const struct llist_head + *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field_src; + int rc = 0; + + llist_for_each_entry(comp_field_src, comp_fields, list) { + if (comp_field_src->entity == comp_field->entity) { + + /* Complete header fields */ + if (comp_field_src->comp_len > 0) { + memcpy(comp_field->comp, + comp_field_src->comp, + sizeof(comp_field_src->comp)); + comp_field->comp_len = comp_field_src->comp_len; + } + + /* Complete parameter fields */ + rc = complete_comp_field_params(comp_field, + comp_field_src); + } + } + + return rc; +} + +/* Complete missing parameters of all comp_field in a list */ +static int gprs_sndcp_complete_comp_fields(struct llist_head + *comp_fields_incomplete, + const struct llist_head *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field_incomplete; + int rc; + + llist_for_each_entry(comp_field_incomplete, comp_fields_incomplete, + list) { + + rc = gprs_sndcp_complete_comp_field(comp_field_incomplete, + comp_fields); + if (rc < 0) + return -EINVAL; + + } + + return 0; +} + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +struct llist_head *gprs_sndcp_parse_xid(const void *ctx, + const uint8_t *src, + unsigned int src_len, + const struct llist_head + *comp_fields_req) +{ + int rc; + int lt_len; + struct llist_head *comp_fields; + struct entity_algo_table lt[MAX_ENTITIES * 2]; + + OSMO_ASSERT(src); + + comp_fields = talloc_zero(ctx, struct llist_head); + INIT_LLIST_HEAD(comp_fields); + + if (comp_fields_req) { + /* Generate lookup table */ + lt_len = + gprs_sndcp_fill_table(lt, MAX_ENTITIES * 2, + comp_fields_req); + if (lt_len < 0) { + talloc_free(comp_fields); + return NULL; + } + + /* Parse SNDCP-CID XID-Field */ + rc = gprs_sndcp_decode_xid(comp_fields, src, src_len, lt, + lt_len); + if (rc < 0) { + talloc_free(comp_fields); + return NULL; + } + + rc = gprs_sndcp_complete_comp_fields(comp_fields, + comp_fields_req); + if (rc < 0) { + talloc_free(comp_fields); + return NULL; + } + + } else { + /* Parse SNDCP-CID XID-Field */ + rc = gprs_sndcp_decode_xid(comp_fields, src, src_len, NULL, 0); + if (rc < 0) { + talloc_free(comp_fields); + return NULL; + } + } + + return comp_fields; +} + +/* Helper for gprs_sndcp_dump_comp_fields(), + * dumps protocol compression parameters */ +static void dump_pcomp_params(const struct gprs_sndcp_comp_field + *comp_field, unsigned int logl) +{ + int i; + + switch (comp_field->algo) { + case RFC_1144: + if (comp_field->rfc1144_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_pcomp_rfc1144_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_pcomp_rfc1144_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%d;\n", + comp_field->rfc1144_params->nsapi_len); + if (comp_field->rfc1144_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rfc1144_params->nsapi_len; i++) { + LOGP(DSNDCP, logl, + " nsapi[%d]=%d;\n", i, + comp_field->rfc1144_params->nsapi[i]); + } + LOGP(DSNDCP, logl, " s01=%d;\n", + comp_field->rfc1144_params->s01); + LOGP(DSNDCP, logl, " }\n"); + break; + case RFC_2507: + if (comp_field->rfc2507_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_pcomp_rfc2507_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_pcomp_rfc2507_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%d;\n", + comp_field->rfc2507_params->nsapi_len); + if (comp_field->rfc2507_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rfc2507_params->nsapi_len; i++) { + LOGP(DSNDCP, logl, + " nsapi[%d]=%d;\n", i, + comp_field->rfc2507_params->nsapi[i]); + } + LOGP(DSNDCP, logl, + " f_max_period=%d;\n", + comp_field->rfc2507_params->f_max_period); + LOGP(DSNDCP, logl, + " f_max_time=%d;\n", + comp_field->rfc2507_params->f_max_time); + LOGP(DSNDCP, logl, + " max_header=%d;\n", + comp_field->rfc2507_params->max_header); + LOGP(DSNDCP, logl, + " tcp_space=%d;\n", + comp_field->rfc2507_params->tcp_space); + LOGP(DSNDCP, logl, + " non_tcp_space=%d;\n", + comp_field->rfc2507_params->non_tcp_space); + LOGP(DSNDCP, logl, " }\n"); + break; + case ROHC: + if (comp_field->rohc_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_pcomp_rohc_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_pcomp_rohc_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%d;\n", + comp_field->rohc_params->nsapi_len); + if (comp_field->rohc_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rohc_params->nsapi_len; i++) { + LOGP(DSNDCP, logl, + " nsapi[%d]=%d;\n", i, + comp_field->rohc_params->nsapi[i]); + } + LOGP(DSNDCP, logl, + " max_cid=%d;\n", comp_field->rohc_params->max_cid); + LOGP(DSNDCP, logl, + " max_header=%d;\n", + comp_field->rohc_params->max_header); + LOGP(DSNDCP, logl, + " profile_len=%d;\n", + comp_field->rohc_params->profile_len); + if (comp_field->rohc_params->profile_len == 0) + LOGP(DSNDCP, logl, " profile[] = NULL;\n"); + for (i = 0; i < comp_field->rohc_params->profile_len; i++) + LOGP(DSNDCP, logl, + " profile[%d]=%04x;\n", + i, comp_field->rohc_params->profile[i]); + LOGP(DSNDCP, logl, " }\n"); + break; + } + +} + +/* Helper for gprs_sndcp_dump_comp_fields(), + * data protocol compression parameters */ +static void dump_dcomp_params(const struct gprs_sndcp_comp_field + *comp_field, unsigned int logl) +{ + int i; + + switch (comp_field->algo) { + case V42BIS: + if (comp_field->v42bis_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_dcomp_v42bis_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_dcomp_v42bis_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%d;\n", + comp_field->v42bis_params->nsapi_len); + if (comp_field->v42bis_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->v42bis_params->nsapi_len; i++) + LOGP(DSNDCP, logl, + " nsapi[%d]=%d;\n", i, + comp_field->v42bis_params->nsapi[i]); + LOGP(DSNDCP, logl, " p0=%d;\n", + comp_field->v42bis_params->p0); + LOGP(DSNDCP, logl, " p1=%d;\n", + comp_field->v42bis_params->p1); + LOGP(DSNDCP, logl, " p2=%d;\n", + comp_field->v42bis_params->p2); + LOGP(DSNDCP, logl, " }\n"); + break; + case V44: + if (comp_field->v44_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_dcomp_v44_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_dcomp_v44_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%d;\n", + comp_field->v44_params->nsapi_len); + if (comp_field->v44_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->v44_params->nsapi_len; i++) { + LOGP(DSNDCP, logl, + " nsapi[%d]=%d;\n", i, + comp_field->v44_params->nsapi[i]); + } + LOGP(DSNDCP, logl, " c0=%d;\n", + comp_field->v44_params->c0); + LOGP(DSNDCP, logl, " p0=%d;\n", + comp_field->v44_params->p0); + LOGP(DSNDCP, logl, " p1t=%d;\n", + comp_field->v44_params->p1t); + LOGP(DSNDCP, logl, " p1r=%d;\n", + comp_field->v44_params->p1r); + LOGP(DSNDCP, logl, " p3t=%d;\n", + comp_field->v44_params->p3t); + LOGP(DSNDCP, logl, " p3r=%d;\n", + comp_field->v44_params->p3r); + LOGP(DSNDCP, logl, " }\n"); + break; + } +} + +/* Dump a list with SNDCP-XID fields (Debug) */ +void gprs_sndcp_dump_comp_fields(const struct llist_head *comp_fields, + unsigned int logl) +{ + struct gprs_sndcp_comp_field *comp_field; + int i; + int compclass; + + OSMO_ASSERT(comp_fields); + + llist_for_each_entry(comp_field, comp_fields, list) { + LOGP(DSNDCP, logl, "SNDCP-XID:\n"); + LOGP(DSNDCP, logl, "struct gprs_sndcp_comp_field {\n"); + LOGP(DSNDCP, logl, " entity=%d;\n", comp_field->entity); + LOGP(DSNDCP, logl, " algo=%d;\n", comp_field->algo); + LOGP(DSNDCP, logl, " comp_len=%d;\n", comp_field->comp_len); + if (comp_field->comp_len == 0) + LOGP(DSNDCP, logl, " comp[] = NULL;\n"); + for (i = 0; i < comp_field->comp_len; i++) { + LOGP(DSNDCP, logl, " comp[%d]=%d;\n", i, + comp_field->comp[i]); + } + + compclass = gprs_sndcp_get_compression_class(comp_field); + + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + dump_pcomp_params(comp_field, logl); + } else if (compclass == SNDCP_XID_DATA_COMPRESSION) { + dump_dcomp_params(comp_field, logl); + } + + LOGP(DSNDCP, logl, "}\n"); + } + +} diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index ba5ca28..1debb2d 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 74af159..45d1780 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -31,6 +31,7 @@ $(top_builddir)/src/gprs/oap.o \ $(top_builddir)/src/gprs/oap_messages.o \ $(top_builddir)/src/gprs/gprs_llc_xid.o \ + $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ @@ -38,5 +39,5 @@ $(LIBOSMOGB_LIBS) \ $(LIBCARES_LIBS) \ $(LIBCRYPTO_LIBS) \ - -lgtp -lrt + -lgtp -lrt -lm diff --git a/openbsc/tests/sndcp_xid/Makefile.am b/openbsc/tests/sndcp_xid/Makefile.am new file mode 100644 index 0000000..99b9d1a --- /dev/null +++ b/openbsc/tests/sndcp_xid/Makefile.am @@ -0,0 +1,20 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) + +EXTRA_DIST = sndcp_xid_test.ok + +noinst_PROGRAMS = sndcp_xid_test + +sndcp_xid_test_SOURCES = sndcp_xid_test.c + +sndcp_xid_test_LDADD = \ + $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOGB_LIBS) \ + $(LIBCARES_LIBS) \ + $(LIBCRYPTO_LIBS) \ + -lgtp -lrt -lm + + diff --git a/openbsc/tests/sndcp_xid/sndcp_xid_test.c b/openbsc/tests/sndcp_xid/sndcp_xid_test.c new file mode 100644 index 0000000..3a33619 --- /dev/null +++ b/openbsc/tests/sndcp_xid/sndcp_xid_test.c @@ -0,0 +1,282 @@ +/* Test SNDCP-XID Encoding/Decoding */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include +#include + +#include + +#include +#include + +/* Test SNDCP-XID decoding with a real world sample */ +static void test_xid_decode_realworld(const void *ctx) +{ + struct llist_head *comp_fields; + int rc; + printf("Testing SNDCP XID-Decoder/Encoder (real world data)\n"); + + /* Example of a real world SNDCP-XID message */ + uint8_t xid[] = + { 0x00, 0x01, 0x00, 0x02, 0x31, 0x82, 0x02, 0x27, 0x89, 0xff, 0xe0, + 0x00, 0x0f, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, + 0x01, 0x02, 0x00, 0x03, 0x01, 0x03, 0x00, 0x04, 0x01, 0x04, 0x00, 0x05, + 0x01, 0x05, 0x00, 0x06, 0x00, 0x07, 0x01, 0x07, 0x00, 0x08, 0x01, 0x08, + 0x80, 0x00, 0x04, 0x12, 0x00, 0x40, 0x07 }; + uint8_t xid_r[512]; + + /* Parse and show contained comp fields */ + comp_fields = gprs_sndcp_parse_xid(ctx, xid, sizeof(xid), NULL); + OSMO_ASSERT(comp_fields); + printf("Decoded:\n"); + gprs_sndcp_dump_comp_fields(comp_fields, DSNDCP); + + /* Encode comp-fields again */ + rc = gprs_sndcp_compile_xid(xid_r,sizeof(xid_r), comp_fields); + printf("Result length=%i\n",rc); + printf("Encoded: %s\n", osmo_hexdump_nospc(xid, sizeof(xid))); + printf("Rencoded: %s\n", osmo_hexdump_nospc(xid_r, rc)); + + OSMO_ASSERT(rc == 54); + OSMO_ASSERT(memcmp(xid, xid_r, sizeof(xid)) == 0); + + /* Free comp fields */ + talloc_free(comp_fields); + + printf("\n"); +} + +/* Encode and decode test with artificial test data */ +static void test_xid_encode_decode(const void *ctx) +{ + printf("Testing SNDCP XID-Encoder/Decoder\n"); + + LLIST_HEAD(comp_fields); + struct gprs_sndcp_pcomp_rfc1144_params rfc1144_params; + struct gprs_sndcp_comp_field rfc1144_comp_field; + struct gprs_sndcp_pcomp_rfc2507_params rfc2507_params; + struct gprs_sndcp_comp_field rfc2507_comp_field; + struct gprs_sndcp_pcomp_rohc_params rohc_params; + struct gprs_sndcp_comp_field rohc_comp_field; + struct gprs_sndcp_dcomp_v42bis_params v42bis_params; + struct gprs_sndcp_comp_field v42bis_comp_field; + struct gprs_sndcp_dcomp_v44_params v44_params; + struct gprs_sndcp_comp_field v44_comp_field; + struct llist_head *comp_fields_dec; + + uint8_t xid[512]; + unsigned int xid_len = sizeof(xid); + int rc; + + memset(&rfc1144_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + memset(&rfc2507_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + memset(&rohc_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + memset(&v42bis_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + memset(&v44_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + + /* Setup which NSAPIs shall make use of rfc1144 */ + rfc1144_params.nsapi[0] = 5; + rfc1144_params.nsapi_len = 1; + + /* Setup rfc1144 operating parameters */ + rfc1144_params.s01 = 7; + + /* Setup rfc1144 compression field */ + rfc1144_comp_field.p = 1; + rfc1144_comp_field.entity = 0; + rfc1144_comp_field.algo = RFC_1144; + rfc1144_comp_field.comp[RFC1144_PCOMP1] = 1; + rfc1144_comp_field.comp[RFC1144_PCOMP2] = 2; + rfc1144_comp_field.comp_len = RFC1144_PCOMP_NUM; + rfc1144_comp_field.rfc1144_params = &rfc1144_params; + + /* Setup which NSAPIs shall make use of rfc1144 */ + rfc2507_params.nsapi[0] = 6; + rfc2507_params.nsapi_len = 1; + + /* Setup rfc2507 operating parameters */ + rfc2507_params.f_max_period = 256; + rfc2507_params.f_max_time = 5; + rfc2507_params.max_header = 168; + rfc2507_params.tcp_space = 15; + rfc2507_params.non_tcp_space = 15; + + /* Setup rfc2507 compression field */ + rfc2507_comp_field.p = 1; + rfc2507_comp_field.entity = 1; + rfc2507_comp_field.algo = RFC_2507; + rfc2507_comp_field.comp[RFC2507_PCOMP1] = 3; + rfc2507_comp_field.comp[RFC2507_PCOMP2] = 4; + rfc2507_comp_field.comp[RFC2507_PCOMP3] = 5; + rfc2507_comp_field.comp[RFC2507_PCOMP4] = 6; + rfc2507_comp_field.comp[RFC2507_PCOMP5] = 7; + rfc2507_comp_field.comp_len = RFC2507_PCOMP_NUM; + rfc2507_comp_field.rfc2507_params = &rfc2507_params; + + /* Setup which NSAPIs shall make use of ROHC */ + rohc_params.nsapi[0] = 5; + rohc_params.nsapi[1] = 6; + rohc_params.nsapi[2] = 7; + rohc_params.nsapi[3] = 8; + rohc_params.nsapi[4] = 9; + rohc_params.nsapi[5] = 10; + rohc_params.nsapi[6] = 11; + rohc_params.nsapi[7] = 12; + rohc_params.nsapi[8] = 13; + rohc_params.nsapi[9] = 14; + rohc_params.nsapi[10] = 15; + rohc_params.nsapi_len = 11; + + /* Setup ROHC operating parameters */ + rohc_params.max_cid = 15; /* default */ + rohc_params.max_header = 168; /* default */ + rohc_params.profile[0] = ROHC_UNCOMPRESSED; + rohc_params.profile[1] = ROHC_RTP; + rohc_params.profile[2] = ROHCV2_RTP; + rohc_params.profile[3] = ROHC_UDP; + rohc_params.profile[4] = ROHCv2_UDP; + rohc_params.profile[5] = ROHC_ESP; + rohc_params.profile[6] = ROHCV2_ESP; + rohc_params.profile[7] = ROHC_IP; + rohc_params.profile[8] = ROHCV2_IP; + rohc_params.profile[9] = ROHC_LLA; + rohc_params.profile[10] = ROHC_LLA_WITH_R_MODE; + rohc_params.profile[11] = ROHC_TCP; + rohc_params.profile[12] = ROHC_RTP_UDP_LITE; + rohc_params.profile[13] = ROHCV2_RTP_UDP_LITE; + rohc_params.profile[14] = ROHC_UDP_LITE; + rohc_params.profile[15] = ROHCV2_UDP_LITE; + rohc_params.profile_len = 16; + + /* Setup ROHC compression field */ + rohc_comp_field.p = 1; + rohc_comp_field.entity = 2; + rohc_comp_field.algo = ROHC; + rohc_comp_field.comp[ROHC_PCOMP1] = 8; + rohc_comp_field.comp[ROHC_PCOMP2] = 9; + rohc_comp_field.comp_len = ROHC_PCOMP_NUM; + rohc_comp_field.rohc_params = &rohc_params; + + /* Setup which NSAPIs shall make use of v42bis */ + v42bis_params.nsapi[0] = 5; + v42bis_params.nsapi_len = 1; + + /* Setup v42bis operating parameters */ + v42bis_params.p0 = 3; + v42bis_params.p1 = 2048; + v42bis_params.p2 = 20; + + /* Setup v42bis compression field */ + v42bis_comp_field.p = 1; + v42bis_comp_field.entity = 3; + v42bis_comp_field.algo = V42BIS; + v42bis_comp_field.comp[V42BIS_DCOMP1] = 10; + v42bis_comp_field.comp_len = V42BIS_DCOMP_NUM; + v42bis_comp_field.v42bis_params = &v42bis_params; + + /* Setup which NSAPIs shall make use of v44 */ + v44_params.nsapi[0] = 5; + v44_params.nsapi_len = 1; + + /* Setup v44 operating parameters */ + v44_params.c0 = 0x80; + v44_params.p0 = 3; + v44_params.p1t = 300; + v44_params.p1r = 300; + v44_params.p3t = 600; + v44_params.p3r = 600; + + /* Setup v44 compression field */ + v44_comp_field.p = 1; + v44_comp_field.entity = 3; + v44_comp_field.algo = V44; + v44_comp_field.comp[V44_DCOMP1] = 10; + v44_comp_field.comp[V44_DCOMP2] = 11; + v44_comp_field.comp_len = V44_DCOMP_NUM; + v44_comp_field.v44_params = &v44_params; + + /* Add compression field(s) to list */ + llist_add(&v44_comp_field.list, &comp_fields); + llist_add(&v42bis_comp_field.list, &comp_fields); + llist_add(&rfc1144_comp_field.list, &comp_fields); + llist_add(&rfc2507_comp_field.list, &comp_fields); + llist_add(&rohc_comp_field.list, &comp_fields); + printf("Test input data:\n"); + gprs_sndcp_dump_comp_fields(&comp_fields, DSNDCP); + + /* Encode SNDCP-XID fields */ + rc = gprs_sndcp_compile_xid(xid, xid_len, &comp_fields); + OSMO_ASSERT(rc > 0); + + printf("Encoded: %s (%i bytes)\n", osmo_hexdump_nospc(xid, rc), rc); + + /* Parse and show contained comp fields */ + comp_fields_dec = gprs_sndcp_parse_xid(ctx, xid, rc, NULL); + OSMO_ASSERT(comp_fields_dec); + + printf("Decoded:\n"); + gprs_sndcp_dump_comp_fields(comp_fields_dec, DSNDCP); + + /* Free comp fields */ + talloc_free(comp_fields_dec); +} + +static struct log_info_cat gprs_categories[] = { + [DSNDCP] = { + .name = "DSNDCP", + .description = + "GPRS Sub-Network Dependent Control Protocol (SNDCP)", + .enabled = 1,.loglevel = LOGL_DEBUG, + } +}; + +static struct log_info info = { + .cat = gprs_categories, + .num_cat = ARRAY_SIZE(gprs_categories), +}; + +int main(int argc, char **argv) +{ + void *xid_ctx; + + osmo_init_logging(&info); + + xid_ctx = talloc_named_const(NULL, 0, "xid_ctx"); + + test_xid_decode_realworld(xid_ctx); + test_xid_encode_decode(xid_ctx); + + printf("Done\n"); + + talloc_report_full(xid_ctx, stderr); + OSMO_ASSERT(talloc_total_blocks(xid_ctx) == 1); + return 0; +} + +/* stubs */ +struct osmo_prim_hdr; +int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) +{ + abort(); +} diff --git a/openbsc/tests/sndcp_xid/sndcp_xid_test.ok b/openbsc/tests/sndcp_xid/sndcp_xid_test.ok new file mode 100644 index 0000000..f357282 --- /dev/null +++ b/openbsc/tests/sndcp_xid/sndcp_xid_test.ok @@ -0,0 +1,11 @@ +Testing SNDCP XID-Decoder/Encoder (real world data) +Decoded: +Result length=54 +Encoded: 000100023182022789ffe0000f00a8000000010101000201020003010300040104000501050006000701070008010880000412004007 +Rencoded: 000100023182022789ffe0000f00a8000000010101000201020003010300040104000501050006000701070008010880000412004007 + +Testing SNDCP XID-Encoder/Decoder +Test input data: +Encoded: 000100011a83010dab00208003012c012c02580258830007a000200308001402408000041200200781010c3456700040010005a80f000f82022789ffe0000f00a80000000101010002010200030103000401040005010500060007010700080108 (97 bytes) +Decoded: +Done diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index 6470ab9..85a81d6 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -129,3 +129,10 @@ cat $abs_srcdir/xid/xid_test.ok > expout AT_CHECK([$abs_top_builddir/tests/xid/xid_test], [], [expout], [ignore]) AT_CLEANUP + +AT_SETUP([sndcp_xid]) +AT_KEYWORDS([sndcp_xid]) +cat $abs_srcdir/sndcp_xid/sndcp_xid_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/sndcp_xid/sndcp_xid_test], [], [expout], [ignore]) +AT_CLEANUP + -- To view, visit https://gerrit.osmocom.org/641 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e Gerrit-PatchSet: 13 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Fri Aug 26 10:34:35 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Fri, 26 Aug 2016 10:34:35 +0000 Subject: [PATCH] openbsc[master]: V42BIS integration and unit test In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/644 to look at the new patch set (#30). V42BIS integration and unit test The previously committed SPANDSP v42bis implementation has been edited to function outside the SPANDSP library. Debug printf statements were changed into DEBUGP statements. Als removed the assembely code in top_bit(). Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d --- M openbsc/.gitignore M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/debug.h M openbsc/include/openbsc/v42bis.h R openbsc/include/openbsc/v42bis_private.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/sgsn_main.c M openbsc/src/gprs/v42bis.c M openbsc/tests/Makefile.am M openbsc/tests/testsuite.at A openbsc/tests/v42bis/Makefile.am A openbsc/tests/v42bis/v42bis_test.c A openbsc/tests/v42bis/v42bis_test.ok 14 files changed, 569 insertions(+), 28 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/44/644/30 diff --git a/openbsc/.gitignore b/openbsc/.gitignore index e75b9eb..6fbd463 100644 --- a/openbsc/.gitignore +++ b/openbsc/.gitignore @@ -84,6 +84,7 @@ tests/xid/xid_test tests/sndcp_xid/sndcp_xid_test tests/slhc/slhc_test +tests/v42bis/v42bis_test tests/atconfig tests/atlocal diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 18980b0..1df14fe 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -232,6 +232,7 @@ tests/xid/Makefile tests/sndcp_xid/Makefile tests/slhc/Makefile + tests/v42bis/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 88a7e2c..b3403dd 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,8 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ - slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h + slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h v42bis.h \ + v42bis_private.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 90ddca5..ca3d4ad 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -37,6 +37,7 @@ DGTPHUB, DRANAP, DSUA, + DV42BIS, Debug_LastEntry, }; diff --git a/openbsc/include/openbsc/v42bis.h b/openbsc/include/openbsc/v42bis.h index f13e5c5..0b97603 100644 --- a/openbsc/include/openbsc/v42bis.h +++ b/openbsc/include/openbsc/v42bis.h @@ -33,8 +33,12 @@ \section v42bis_page_sec_2 How does it work? */ +#include + #if !defined(_SPANDSP_V42BIS_H_) #define _SPANDSP_V42BIS_H_ + +#define SPAN_DECLARE(x) x #define V42BIS_MAX_BITS 12 #define V42BIS_MAX_CODEWORDS 4096 /* 2^V42BIS_MAX_BITS */ @@ -114,7 +118,8 @@ \param data_user_data An opaque pointer passed to the data callback handler. \param max_data_len The maximum length that should be passed to the data handler. \return The V.42bis context. */ -SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, +SPAN_DECLARE(v42bis_state_t *) v42bis_init(const void *ctx, + v42bis_state_t *s, int negotiated_p0, int negotiated_p1, int negotiated_p2, diff --git a/openbsc/include/openbsc/private_v42bis.h b/openbsc/include/openbsc/v42bis_private.h similarity index 100% rename from openbsc/include/openbsc/private_v42bis.h rename to openbsc/include/openbsc/v42bis_private.h diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 2910c02..f479d56 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -27,7 +27,7 @@ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ - slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c + slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c v42bis.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c index 894ce84..f01798b 100644 --- a/openbsc/src/gprs/sgsn_main.c +++ b/openbsc/src/gprs/sgsn_main.c @@ -297,6 +297,11 @@ .description = "RFC1144 TCP/IP Header compression (SLHC)", .enabled = 1, .loglevel = LOGL_DEBUG, }, + [DV42BIS] = { + .name = "DV42BIS", + .description = "V.42bis data compression (SNDCP)", + .enabled = 1, .loglevel = LOGL_DEBUG, + } }; static const struct log_info gprs_log_info = { diff --git a/openbsc/src/gprs/v42bis.c b/openbsc/src/gprs/v42bis.c index 6d38916..b8a886d 100644 --- a/openbsc/src/gprs/v42bis.c +++ b/openbsc/src/gprs/v42bis.c @@ -31,9 +31,8 @@ /*! \file */ -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif +#define FALSE 0 +#define TRUE 1 #include #include @@ -44,13 +43,11 @@ #include #include -#include "spandsp/telephony.h" -#include "spandsp/logging.h" -#include "spandsp/bit_operations.h" -#include "spandsp/v42bis.h" +#include +#include +#include +#include -#include "spandsp/private/logging.h" -#include "spandsp/private/v42bis.h" /* Fixed parameters from the spec. */ #define V42BIS_N3 8 /* Character size (bits) */ @@ -310,7 +307,7 @@ { if (ss->transparent) { - printf("Going compressed\n"); + DEBUGP(DV42BIS,"Going compressed\n"); /* 7.8.1 Transition to compressed mode */ /* Switch out of transparent now, between codes. We need to send the octet which did not match, just before switching. */ @@ -332,7 +329,7 @@ { if (!ss->transparent) { - printf("Going transparent\n"); + DEBUGP(DV42BIS,"Going transparent\n"); /* 7.8.2 Transition to transparent mode */ /* Switch into transparent now, between codes, and the unmatched octet should go out in transparent mode, just below */ @@ -401,7 +398,7 @@ { if (s->compress.dict[i].parent_code != 0xFFFF) { - printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); + DEBUGP(DV42BIS,"Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); } } return 0; @@ -454,13 +451,13 @@ ss->escaped = FALSE; if (code == V42BIS_ECM) { - printf("Hit V42BIS_ECM\n"); + DEBUGP(DV42BIS,"Hit V42BIS_ECM\n"); ss->transparent = FALSE; code_len = ss->v42bis_parm_c2; } else if (code == V42BIS_EID) { - printf("Hit V42BIS_EID\n"); + DEBUGP(DV42BIS,"Hit V42BIS_EID\n"); ss->output_buf[ss->output_octet_count++] = ss->escape_code - 1; if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) { @@ -470,11 +467,11 @@ } else if (code == V42BIS_RESET) { - printf("Hit V42BIS_RESET\n"); + DEBUGP(DV42BIS,"Hit V42BIS_RESET\n"); } else { - printf("Hit V42BIS_???? - %" PRIu32 "\n", code); + DEBUGP(DV42BIS,"Hit V42BIS_???? - %" PRIu32 "\n", code); } } else if (code == ss->escape_code) @@ -500,17 +497,17 @@ switch (new_code) { case V42BIS_ETM: - printf("Hit V42BIS_ETM\n"); + DEBUGP(DV42BIS,"Hit V42BIS_ETM\n"); ss->transparent = TRUE; code_len = 8; break; case V42BIS_FLUSH: - printf("Hit V42BIS_FLUSH\n"); + DEBUGP(DV42BIS,"Hit V42BIS_FLUSH\n"); v42bis_decompress_flush(s); break; case V42BIS_STEPUP: /* We need to increase the codeword size */ - printf("Hit V42BIS_STEPUP\n"); + DEBUGP(DV42BIS,"Hit V42BIS_STEPUP\n"); if (ss->v42bis_parm_c3 >= s->v42bis_parm_n2) { /* Invalid condition */ @@ -547,7 +544,7 @@ /* Trace back through the octets which form the string, and output them. */ while (code >= V42BIS_N5) { -if (code > 4095) {printf("Code is 0x%" PRIu32 "\n", code); exit(2);} +if (code > 4095) {DEBUGP(DV42BIS,"Code is 0x%" PRIu32 "\n", code); exit(2);} *string-- = ss->dict[code].node_octet; code = ss->dict[code].parent_code; } @@ -631,7 +628,7 @@ { if (s->decompress.dict[i].parent_code != 0xFFFF) { - printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); + DEBUGP(DV42BIS,"Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); } } return 0; @@ -654,7 +651,8 @@ } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, +SPAN_DECLARE(v42bis_state_t *) v42bis_init(const void *ctx, + v42bis_state_t *s, int negotiated_p0, int negotiated_p1, int negotiated_p2, @@ -673,7 +671,7 @@ return NULL; if (s == NULL) { - if ((s = (v42bis_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (v42bis_state_t *) talloc_zero_size(ctx,sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -735,7 +733,7 @@ SPAN_DECLARE(int) v42bis_free(v42bis_state_t *s) { - free(s); + talloc_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index d5aa356..7acebc0 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid slhc +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid slhc v42bis if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index 5f37b8e..f18b734 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -141,3 +141,9 @@ cat $abs_srcdir/slhc/slhc_test.ok > expout AT_CHECK([$abs_top_builddir/tests/slhc/slhc_test], [], [expout], [ignore]) AT_CLEANUP + +AT_SETUP([v42bis]) +AT_KEYWORDS([v42bis]) +cat $abs_srcdir/v42bis/v42bis_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/v42bis/v42bis_test], [], [expout], [ignore]) +AT_CLEANUP diff --git a/openbsc/tests/v42bis/Makefile.am b/openbsc/tests/v42bis/Makefile.am new file mode 100644 index 0000000..9001c0f --- /dev/null +++ b/openbsc/tests/v42bis/Makefile.am @@ -0,0 +1,21 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) + +EXTRA_DIST = v42bis_test.ok + +noinst_PROGRAMS = v42bis_test + +v42bis_test_SOURCES = v42bis_test.c + +v42bis_test_LDADD = \ + $(top_builddir)/src/gprs/v42bis.o \ + $(top_builddir)/src/libcommon/libcommon.a \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOGB_LIBS) \ + $(LIBCARES_LIBS) \ + $(LIBCRYPTO_LIBS) \ + -lgtp -lrt -lm + + diff --git a/openbsc/tests/v42bis/v42bis_test.c b/openbsc/tests/v42bis/v42bis_test.c new file mode 100644 index 0000000..da5f339 --- /dev/null +++ b/openbsc/tests/v42bis/v42bis_test.c @@ -0,0 +1,278 @@ +/* Test v42bis Compression/Decompression */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#define P0 3 +#define P1 512 +#define P2 20 + +#define BLOCK_SIZE 1024 +#define MAX_BLOCK_SIZE 1024 + +#define UNCOMPR_PACKETS_LEN 6 +char *uncompr_packets[] = { + "45000236000700004006cf2cc0a80002550d93d7400000501e200da7c0c95a70801840002e3700000101080a000174140853d489474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a", + "4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27", + "4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0", + "4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01", + "4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01", + "4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a", + "4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20" +}; + +/* A simple function to show the ascii content of a packet */ +void show_packet(uint8_t *packet, int len) +{ + int i; + char c; + for (i = 0; i < len; i++) { + c = packet[i]; + if (c >= 0x20 && c <= 0x7E) + printf("%c", c); + else + printf("."); + } + printf("\n"); +} + +/* A struct to capture the output data of compressor and decompressor */ +struct v42bis_output_buffer { + uint8_t *buf; + uint8_t *buf_pointer; + int len; +}; + +/* A simple testpattern generator */ +static void gen_test_pattern(uint8_t *data, int len) +{ + int i; + for (i = 0; i < len; i++) + data[i] = i & 0xF0; +} + +/* Handler to capture the output data from the compressor */ +void tx_v42bis_frame_handler(void *user_data, const uint8_t *pkt, int len) +{ + struct v42bis_output_buffer *output_buffer = + (struct v42bis_output_buffer *)user_data; + memcpy(output_buffer->buf_pointer, pkt, len); + output_buffer->buf_pointer += len; + output_buffer->len += len; + return; +} + +/* Handler to capture the output data from the decompressor */ +void tx_v42bis_data_handler(void *user_data, const uint8_t *buf, int len) +{ + /* stub, never used */ + OSMO_ASSERT(false); + return; +} + +/* Handler to capture the output data from the compressor */ +void rx_v42bis_frame_handler(void *user_data, const uint8_t *pkt, int len) +{ + /* stub, never used */ + OSMO_ASSERT(false); + return; +} + +/* Handler to capture the output data from the decompressor */ +void rx_v42bis_data_handler(void *user_data, const uint8_t *buf, int len) +{ + struct v42bis_output_buffer *output_buffer = + (struct v42bis_output_buffer *)user_data; + memcpy(output_buffer->buf_pointer, buf, len); + output_buffer->buf_pointer += len; + output_buffer->len += len; + return; +} + +/* Test V.42bis compression and decompression */ +static void v42bis(const void *ctx, int mode, uint8_t *testvec, int len) +{ + v42bis_state_t *tx_state; + v42bis_state_t *rx_state; + uint8_t *uncompressed_original; + uint8_t *compressed; + uint8_t *uncompressed; + + uncompressed_original = talloc_zero_size(ctx, len); + uncompressed = talloc_zero_size(ctx, len); + + /* Note: We allocate double the size for the compressed buffer, + * because in some cases the compression may increase the amount. + * of data. */ + compressed = talloc_zero_size(ctx, len * 2); + + int rc; + int rc_sum = 0; + struct v42bis_output_buffer compressed_data; + struct v42bis_output_buffer uncompressed_data; + + /* Initalize */ + tx_state = + v42bis_init(ctx, NULL, P0, P1, P2, + &tx_v42bis_frame_handler, NULL, MAX_BLOCK_SIZE, + &tx_v42bis_data_handler, NULL, MAX_BLOCK_SIZE); + OSMO_ASSERT(tx_state); + rx_state = + v42bis_init(ctx, NULL, P0, P1, P2, + &rx_v42bis_frame_handler, NULL, MAX_BLOCK_SIZE, + &rx_v42bis_data_handler, NULL, MAX_BLOCK_SIZE); + OSMO_ASSERT(rx_state); + v42bis_compression_control(tx_state, mode); + + /* Setup input data */ + memcpy(uncompressed_original, testvec, len); + + /* Run compressor */ + compressed_data.buf = compressed; + compressed_data.buf_pointer = compressed; + compressed_data.len = 0; + tx_state->compress.user_data = (&compressed_data); + rc = v42bis_compress(tx_state, uncompressed_original, len); + printf("v42bis_compress() rc=%d\n", rc); + OSMO_ASSERT(rc == 0); + rc = v42bis_compress_flush(tx_state); + printf("v42bis_compress_flush() rc=%d\n", rc); + OSMO_ASSERT(rc == 0); + + /* Decompress again */ + uncompressed_data.buf = uncompressed; + uncompressed_data.buf_pointer = uncompressed; + uncompressed_data.len = 0; + rx_state->decompress.user_data = (&uncompressed_data); + rc = v42bis_decompress(rx_state, compressed_data.buf, + compressed_data.len); + printf("v42bis_decompress() rc=%d\n", rc); + rc = v42bis_decompress_flush(rx_state); + rc_sum += rc; + printf("v42bis_decompress_flush() rc=%d\n", rc); + rc_sum += rc; + + /* Check results */ + printf("Mode: %i\n", mode); + + printf("uncompressed_original= %s ASCII:", + osmo_hexdump_nospc(uncompressed_original, len)); + show_packet(uncompressed_original, len); + printf("uncompressed= %s ASCII:", + osmo_hexdump_nospc(uncompressed_data.buf, + uncompressed_data.len)); + show_packet(uncompressed_data.buf, uncompressed_data.len); + printf("compressed= %s ASCII:", + osmo_hexdump_nospc(compressed_data.buf, compressed_data.len)); + show_packet(compressed_data.buf, compressed_data.len); + + rc = memcmp(uncompressed, uncompressed_original, len); + printf("memcmp() rc=%d\n", rc); + rc_sum += rc; + OSMO_ASSERT(rc_sum == 0); + + /* Free buffers and exit */ + v42bis_free(tx_state); + v42bis_free(rx_state); + talloc_free(uncompressed_original); + talloc_free(compressed); + talloc_free(uncompressed); + printf("\n"); +} + +/* Test V.42bis compression and decompression with generated data*/ +static void test_v42bis(const void *ctx) +{ + printf("Testing compression/decompression with generated data:\n"); + uint8_t testvec[BLOCK_SIZE]; + int len = sizeof(testvec); + gen_test_pattern(testvec, len); + v42bis(ctx, V42BIS_COMPRESSION_MODE_DYNAMIC, testvec, len); + v42bis(ctx, V42BIS_COMPRESSION_MODE_NEVER, testvec, len); + v42bis(ctx, V42BIS_COMPRESSION_MODE_ALWAYS, testvec, len); +} + +/* Test V.42bis compression and decompression with some TCP/IP packets */ +static void test_v42bis_tcpip(const void *ctx, int packet_id) +{ + uint8_t *testvec; + int len; + printf + ("Testing compression/decompression with realistic TCP/IP packets:\n"); + printf("Packet No.: %i\n", packet_id); + len = strlen(uncompr_packets[packet_id]); + testvec = talloc_zero_size(ctx, len); + len = osmo_hexparse(uncompr_packets[packet_id], testvec, len); + v42bis(ctx, V42BIS_COMPRESSION_MODE_DYNAMIC, testvec, len); + v42bis(ctx, V42BIS_COMPRESSION_MODE_NEVER, testvec, len); + v42bis(ctx, V42BIS_COMPRESSION_MODE_ALWAYS, testvec, len); + talloc_free(testvec); +} + +static struct log_info_cat gprs_categories[] = { + [DV42BIS] = { + .name = "DV42BIS", + .description = "V.42bis data compression (SNDCP)", + .enabled = 1,.loglevel = LOGL_DEBUG, + } +}; + +static struct log_info info = { + .cat = gprs_categories, + .num_cat = ARRAY_SIZE(gprs_categories), +}; + +int main(int argc, char **argv) +{ + void *v42bis_ctx; + int i; + + osmo_init_logging(&info); + + v42bis_ctx = talloc_named_const(NULL, 0, "v42bis_ctx"); + + test_v42bis(v42bis_ctx); + + for(i=0;i.w......z.b6Y,..U..k;.......]..lv\....7.....N.i...X...d-....q...Q;.).3...0........l;..C...`4...#1..r0<.....h.k6.N."i0.Z"..C....w.....Q..j4RM....a.....#I.....pGs..d2..wg....`;B.&c..dX"}>."p.f36.F.9.HKA%.......1>.....R.X..F.OQ.ZV.....d*;.6..DQ.T..2j.E...m....d_..p2(..?Y..l1...._...L#.......d....#e.dF'........8.M.k...N4Q.U....E..............}..Z5.i.... +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 2 +uncompressed_original= 45000236000700004006cf2cc0a80002550d93d7400000501e200da7c0c95a70801840002e3700000101080a000174140853d489474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..6.... at ..,....U... at ..P. ....Zp.. at ..7........t..S..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... +uncompressed= 45000236000700004006cf2cc0a80002550d93d7400000501e200da7c0c95a70801840002e3700000101080a000174140853d489474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..6.... at ..,....U... at ..P. ....Zp.. at ..7........t..S..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... +compressed= 24000000408d8001c0001001b3cb302a0000954364f5d000001407880369f032569c200610000b8dc000004040420280005d050214f52251d155080bc8121515140bcc4b8c43429058d8d95c1d0e881b5d5b1d1a5c185c9d0bdb5a5e19590b08185c1c1b1a58d85d1a5bdb8bdd9b990b9dd85c0b9b5d5b1d1a5c185c9d0b9b5a5e19590b08185c1c1b1a58d85d1a5bdb8bdd9b990b9dd85c0b9e1a1d1b5b0ade1b5b0b08185c1c1b1a58d85d1a5bdb8bde1a1d1b5b0ade1b5b0b081d195e1d0bdd9b990b9dd85c0b9ddb5b0b080a8bca83429058d8d95c1d0b50da185c9cd95d0e881d5d198b4e0b081d5d198b4c4d8b081a5cdbcb4e0e0d4e4b4c4b081a5cdbcb4c4c0d8d0d8b5d58dccb4c8b0814da1a599d17d29254cb08109a59cd43429058d8d95c1d0b53185b99dd5859d94e88195b83429e0b5dd85c0b5c1c9bd99a5b194e88089a1d1d1c0e8bcbddd85c0b9cdbdb9e595c9a58dcdcdbdb8b98dbdb4bd5505c1c9bd98bd2ce0c0c1a548c8c0c4b9e1b5b088342921bdcdd0e881dddddcb9e9bd8dacb98dbdb4342955cd95c8b5059d95b9d0e8814dbdb9e515c9a58dcdcdbdb92ce0c0c1a4bd48c908814995b19585cd94bd3585c8b4c4ccb4c8c0c0dc8109c9bdddcd95c8bd3995d119c9bdb9d0bcccb8cc8141c9bd99a5b194bd35251140b4c8b8c0810dbdb999a59dd5c985d1a5bdb8bd0d31110cb4c4b8c434290dbdb9b9958dd1a5bdb8e8812d9595c0b505b1a5d9943429058d8d95c1d0b515b98dbd91a5b99ce881919599b185d194b0819de9a5c0342834280 ASCII:$... at .........0*...Cd........i.2V. ........@@B...]...."Q.U.........K.CB.X..\....][..\.\...Z^.Y...\...X.].[........\..][..\.\...Z^.Y...\...X.].[........\.....[...[...\...X.].[......[...[....^........\...[......B.X..\..P..\..]...]..N...]..LM...\..N..NKLK..\..LL....]X..L.....Y....T....Y.CB.X..\..S.[..XY.N..[.B..].\.\....[.N...........\.....Y\.X........K.P\.........T...K..[..B..................CB.\.\.PY.[.......Q\.X.........K......[.X\.K.X\.LL.L..........\...]...............[.K.RQ..L........Y.\.].[.......LK.CB.....X..[.....Y\.P[.].CB.X..\..Q[....[.....Y..].K....\.B.B. +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 1 +uncompressed_original= 45000236000700004006cf2cc0a80002550d93d7400000501e200da7c0c95a70801840002e3700000101080a000174140853d489474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..6.... at ..,....U... at ..P. ....Zp.. at ..7........t..S..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... +uncompressed= 45000236000700004006cf2cc0a80002550d93d7400000501e200da7c0c95a70801840002e3700000101080a000174140853d489474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..6.... at ..,....U... at ..P. ....Zp.. at ..7........t..S..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... +compressed= 2400c0a3901828060321825a42f61aae085808259b4438494c4223082a986cc2e9cd061b8b0c4750902010160d01810ee1705959ae8c25120ae231908c96572b94c6434188d0200d22198cc68399dc7a23381e0de77361ccc8753b8c8e06c3d9a0ce2f11990e673379b0cc64a71c8e2323c9c4ce313d570634ba6d3ea277b6d5ab15aae57ac16236592cd68b55b0f66b3b9c0de2e3de12ed5dafd86c765c0e0f0b8737d68ee683dd4ecf69b59ced588118b4642da0d0e8b4718118d7513b1a290233c1dcd2301dd6b5fb11a0e6b46c3b1cb643b1c0f06034dceef82331c8dc72303c198ec301ad68ac6b361a4ee6226930ad5a229b0d438d1d128c771813cc871351e0c86a34524d071a09ec619b181ccea72349b0dfeb118970477398f46432cd8c776713e1a0eb603b4286266391c06458227d3ec32270ec6633361546a339f6484b41259c8edad3d1e8f4313e9c8cc6e894528258d59d46044f51c75a56b21f0910ee642a3b1f360ca444511954d1f9326ac6450a8f046dce8f8e84645fa9ea703228eb093f59e8c86c311b08ca7f5fbfe6ee4c2394f9c311988c8d64fbf9ceb623659064462791c8dc1188d283a5389c4d066b19c6924e3451a755f3c9a3bf45a38c090718999cd9e6a499cd06937d88d15a351f69f41a0804 ASCII:$.....(..!.ZB....X.%.D8ILB#.*.l.......GP. .......pYY..%...1...W+..CA.. ."......z#8...sa..u;......./...g3y..d...##...1=W.4.m>.w......z.b6Y,..U..k;.......]..lv\....7.....N.i...X...d-....q...Q;.).3...0........l;..C...`4...#1..r0<.....h.k6.N."i0.Z"..C....w.....Q..j4RM....a.....#I.....pGs..d2..wg....`;B.&c..dX"}>."p.f36.F.9.HKA%.......1>.....R.X..F.OQ.ZV.....d*;.6..DQ.T..2j.E...m....d_..p2(..?Y..l1...._...L#.......d....#e.dF'........8.M.k...N4Q.U....E..............}..Z5.i.... +memcmp() rc=0 + +Testing compression/decompression with realistic TCP/IP packets: +Packet No.: 1 +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 0 +uncompressed_original= 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E.. at F.@. at .....dn..dd...........M....*.........G....^..... ..#..' +uncompressed= 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E.. at F.@. at .....dn..dd...........M....*.........G....^..... ..#..' +compressed= 2404c064324b80870504ab154c35599ce30e3399c061a58239089b0200decaf4d941061b01b985a190180c08040583406092538412d46118605000dcd44735134d454010 ASCII:$..d2K......L5Y...3..a..9........A.............@`.S...a.`P...G5.ME at . +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 2 +uncompressed_original= 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E.. at F.@. at .....dn..dd...........M....*.........G....^..... ..#..' +uncompressed= 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E.. at F.@. at .....dn..dd...........M....*.........G....^..... ..#..' +compressed= 24000400005011b750001001aa69f02a191bb02a19190005eb62e0660040403ceb261360060038ca85800000404202800191f781b46fd7bfff463fff483fff48ffff49c0 ASCII:$....P..P....i.*...*.....b.f.@@<.&.`..8..... at B.......o...F?.H?.H..I. +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 1 +uncompressed_original= 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E.. at F.@. at .....dn..dd...........M....*.........G....^..... ..#..' +uncompressed= 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E.. at F.@. at .....dn..dd...........M....*.........G....^..... ..#..' +compressed= 2404c064324b80870504ab154c35599ce30e3399c061a58239089b0200decaf4d941061b01b985a190180c08040583406092538412d46118605000dcd44735134d454010 ASCII:$..d2K......L5Y...3..a..9........A.............@`.S...a.`P...G5.ME at . +memcmp() rc=0 + +Testing compression/decompression with realistic TCP/IP packets: +Packet No.: 2 +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 0 +uncompressed_original= 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E..[F. at .@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... +uncompressed= 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E..[F. at .@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... +compressed= 2404c065e24b84860321825588e61aacce718799cce030d2c11c844d8101ef657a6ca0830d80dcc893c00c06040202c1a0304929c4096a308c9027f01a0500114e44902808966c08813f44604813ce8626a3521fa2aa5d0c374b0080 ASCII:$..e.K...!.U.....q....0....M...ezl...............0I)..j0..'.....ND.(..l..?D`H...&.R...].7K.. +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 2 +uncompressed_original= 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E..[F. at .@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... +uncompressed= 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E..[F. at .@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... +compressed= 240004000056d1b790001001aa62f02a191bb02a19190005eb62e0660040433ceb261360060038e19d400000404202800191f7c1b46fd87ffec0ffff47ffff487fff88bffec17ffe88007ffc3ffe88c07ffc3ffe89c07ffc3ffe86007ffc00 ASCII:$....V.......b.*...*.....b.f. at C<.&.`..8.. at ..@B.......o......G..H............?.....?.....?...... +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 1 +uncompressed_original= 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E..[F. at .@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... +uncompressed= 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E..[F. at .@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... +compressed= 2404c065e24b84860321825588e61aacce718799cce030d2c11c844d8101ef657a6ca0830d80dcc893c00c06040202c1a0304929c4096a308c9027f01a0500114e44902808966c08813f44604813ce8626a3521fa2aa5d0c374b0080 ASCII:$..e.K...!.U.....q....0....M...ezl...............0I)..j0..'.....ND.(..l..?D`H...&.R...].7K.. +memcmp() rc=0 + +Testing compression/decompression with realistic TCP/IP packets: +Packet No.: 3 +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 0 +uncompressed_original= 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E..7F. at .@.....dn..dd.......3........_.........G....c... +uncompressed= 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E..7F. at .@.....dn..dd.......3........_.........G....c... +compressed= 2404c063a24b8886032182558b161aacce718799cce030d2c11c844d8106cf657a6d44830d80dcc626d00c06040202c1a0304929c8096a308cd028001002 ASCII:$..c.K...!.U.....q....0....M...ezmD.....&........0I)..j0..(... +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 2 +uncompressed_original= 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E..7F. at .@.....dn..dd.......3........_.........G....c... +uncompressed= 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E..7F. at .@.....dn..dd.......3........_.........G....c... +compressed= 24000400004dd1b7d0001001aa6bb02a191bb02a19190005eb62e06600404cfceb2627e0060038d7f5c00000404202800191f841b46fd8ffff4040 ASCII:$....M.......k.*...*.....b.f. at L..&'...8..... at B.....A.o...@@ +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 1 +uncompressed_original= 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E..7F. at .@.....dn..dd.......3........_.........G....c... +uncompressed= 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E..7F. at .@.....dn..dd.......3........_.........G....c... +compressed= 2404c063a24b8886032182558b161aacce718799cce030d2c11c844d8106cf657a6d44830d80dcc626d00c06040202c1a0304929c8096a308cd028001002 ASCII:$..c.K...!.U.....q....0....M...ezmD.....&........0I)..j0..(... +memcmp() rc=0 + +Testing compression/decompression with realistic TCP/IP packets: +Packet No.: 4 +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 0 +uncompressed_original= 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E..7F. at .@.....dn..dd.......6........_.........G....d... +uncompressed= 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E..7F. at .@.....dn..dd.......6........_.........G....d... +compressed= 2404c063a24b8c86032182558b061aacce718799cce030d2c11c844d81072f657a6d4a830d80dcc626a80c06040202c1a0304929c8096a308cf027f01002 ASCII:$..c.K...!.U.....q....0....M../ezmJ.....&........0I)..j0..'... +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 2 +uncompressed_original= 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E..7F. at .@.....dn..dd.......6........_.........G....d... +uncompressed= 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E..7F. at .@.....dn..dd.......6........_.........G....d... +compressed= 24000400004dd1b810001001aa6b702a191bb02a19190005eb62e06600404dbceb2628a0060038d7f4800000404202800191f841b46fd93ffec040 ASCII:$....M.......kp*...*.....b.f. at M..&(...8..... at B.....A.o.?..@ +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 1 +uncompressed_original= 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E..7F. at .@.....dn..dd.......6........_.........G....d... +uncompressed= 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E..7F. at .@.....dn..dd.......6........_.........G....d... +compressed= 2404c063a24b8c86032182558b061aacce718799cce030d2c11c844d81072f657a6d4a830d80dcc626a80c06040202c1a0304929c8096a308cf027f01002 ASCII:$..c.K...!.U.....q....0....M../ezmJ.....&........0I)..j0..'... +memcmp() rc=0 + +Testing compression/decompression with realistic TCP/IP packets: +Packet No.: 5 +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 0 +uncompressed_original= 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E..tF. at .@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... +uncompressed= 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E..tF. at .@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... +compressed= 2404c067724b90860321825587261aacce718799cce030d2c11c844d81078f657a6d50830d80dcc7e4f00c06040202c1a0304929ca096a308ce10068c061389c4e6733a9c4d8b468379bccc72381a046773908ce672a01e0f7369dceea13c06cd802 ASCII:$..grK...!.U.&...q....0....M...ezmP..............0I)..j0...h.a8.Ng3....h7...#..Fw9..g*...6.....l.. +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 2 +uncompressed_original= 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E..tF. at .@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... +uncompressed= 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E..tF. at .@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... +compressed= 24000400005d11b850001001aa5bf02a191bb02a19190005eb62e06600404e7ceb262960060038dee6c00000404202800191f881b46fd903428b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b434295d95b1b18dbdb59481d1bc81c1bdb1b1d5e03428b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4342834280 ASCII:$....]..P....[.*...*.....b.f. at N|.&)`..8..... at B.......o..B.KKKKKKKKKKKKKKKKKCB..[....YH........^.B.KKKKKKKKKKKKKKKKKCB.B. +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 1 +uncompressed_original= 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E..tF. at .@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... +uncompressed= 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E..tF. at .@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... +compressed= 2404c067724b90860321825587261aacce718799cce030d2c11c844d81078f657a6d50830d80dcc7e4f00c06040202c1a0304929ca096a308ce10068c061389c4e6733a9c4d8b468379bccc72381a046773908ce672a01e0f7369dceea13c06cd802 ASCII:$..grK...!.U.&...q....0....M...ezmP..............0I)..j0...h.a8.Ng3....h7...#..Fw9..g*...6.....l.. +memcmp() rc=0 + +Done -- To view, visit https://gerrit.osmocom.org/644 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d Gerrit-PatchSet: 30 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Fri Aug 26 10:34:35 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Fri, 26 Aug 2016 10:34:35 +0000 Subject: [PATCH] openbsc[master]: SLHC (RFC1144 header compression) integration and unit-test In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/635 to look at the new patch set (#14). SLHC (RFC1144 header compression) integration and unit-test The previously pushed slhc implementation has been modified to compile and function outside of the kernel. Also debug log messages were added and datatypes ware matched. The implementation is now ready to be used Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 --- M openbsc/.gitignore M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/debug.h M openbsc/include/openbsc/gprs_llc.h M openbsc/include/openbsc/gprs_sndcp.h A openbsc/include/openbsc/gprs_sndcp_comp.h A openbsc/include/openbsc/gprs_sndcp_pcomp.h M openbsc/include/openbsc/sgsn.h R openbsc/include/openbsc/slhc.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/gprs_llc.c M openbsc/src/gprs/gprs_sndcp.c A openbsc/src/gprs/gprs_sndcp_comp.c A openbsc/src/gprs/gprs_sndcp_pcomp.c M openbsc/src/gprs/sgsn_libgtp.c M openbsc/src/gprs/sgsn_main.c M openbsc/src/gprs/sgsn_vty.c M openbsc/src/gprs/slhc.c M openbsc/tests/Makefile.am M openbsc/tests/sgsn/Makefile.am A openbsc/tests/slhc/Makefile.am A openbsc/tests/slhc/slhc_test.c A openbsc/tests/slhc/slhc_test.ok M openbsc/tests/testsuite.at 25 files changed, 1,968 insertions(+), 119 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/35/635/14 diff --git a/openbsc/.gitignore b/openbsc/.gitignore index 8ce3b70..e75b9eb 100644 --- a/openbsc/.gitignore +++ b/openbsc/.gitignore @@ -83,6 +83,7 @@ tests/mm_auth/mm_auth_test tests/xid/xid_test tests/sndcp_xid/sndcp_xid_test +tests/slhc/slhc_test tests/atconfig tests/atlocal diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 53072bd..18980b0 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -231,6 +231,7 @@ tests/mm_auth/Makefile tests/xid/Makefile tests/sndcp_xid/Makefile + tests/slhc/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index e200b05..88a7e2c 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,8 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h + gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ + slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 43ebb19..90ddca5 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -29,6 +29,7 @@ DBSSGP, DLLC, DSNDCP, + DSLHC, DNAT, DCTRL, DSMPP, diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h index c3b82b1..8b01467 100644 --- a/openbsc/include/openbsc/gprs_llc.h +++ b/openbsc/include/openbsc/gprs_llc.h @@ -174,6 +174,15 @@ * able to create the compression entity. */ struct llist_head *xid; + /* Compression entities */ + struct { + /* In these two list_heads we will store the + * data and protocol compression entities, + * together with their compression states */ + struct llist_head *proto; + struct llist_head *data; + } comp; + /* Internal management */ uint32_t age_timestamp; }; diff --git a/openbsc/include/openbsc/gprs_sndcp.h b/openbsc/include/openbsc/gprs_sndcp.h index fef871a..d970240 100644 --- a/openbsc/include/openbsc/gprs_sndcp.h +++ b/openbsc/include/openbsc/gprs_sndcp.h @@ -21,6 +21,16 @@ struct llist_head frag_list; struct osmo_timer_list timer; + + /* Holds state to know which compression mode is used + * when the packet is re-assembled */ + uint8_t pcomp; + uint8_t dcomp; + + /* Holds the pointers to the compression entity list + * that is used when the re-assembled packet is decompressed */ + struct llist_head *proto; + struct llist_head *data; }; /* See 6.7.1.2 Reassembly */ @@ -50,4 +60,20 @@ extern struct llist_head gprs_sndcp_entities; +/* Set of SNDCP-XID negotiation (See also: TS 144 065, + * Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_req(struct gprs_llc_lle *lle, uint8_t nsapi); + +/* Process SNDCP-XID indication (See also: TS 144 065, + * Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_ind(struct gprs_llc_xid_field *xid_field_indication, + struct gprs_llc_xid_field *xid_field_response, + struct gprs_llc_lle *lle); + +/* Process SNDCP-XID indication + * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_conf(struct gprs_llc_xid_field *xid_field_conf, + struct gprs_llc_xid_field *xid_field_request, + struct gprs_llc_lle *lle); + #endif /* INT_SNDCP_H */ diff --git a/openbsc/include/openbsc/gprs_sndcp_comp.h b/openbsc/include/openbsc/gprs_sndcp_comp.h new file mode 100644 index 0000000..87ab638 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_comp.h @@ -0,0 +1,82 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +/* Header / Data compression entity */ +struct gprs_sndcp_comp { + struct llist_head list; + + /* Serves as an ID in case we want to delete this entity later */ + unsigned int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + + /* Specifies to which NSAPIs the compression entity is assigned */ + uint8_t nsapi_len; /* Number of applicable NSAPIs (default 0) */ + uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */ + + /* Assigned pcomp values */ + uint8_t comp_len; /* Number of contained PCOMP / DCOMP values */ + uint8_t comp[MAX_COMP]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */ + + /* Algorithm parameters */ + int algo; /* Algorithm type (see gprs_sndcp_xid.h) */ + int compclass; /* See gprs_sndcp_xid.h/c */ + void *state; /* Algorithm status and parameters */ +}; + +#define MAX_COMP 16 /* Maximum number of possible pcomp/dcomp values */ +#define MAX_NSAPI 11 /* Maximum number usable NSAPIs */ + +/* Allocate a compression enitiy list */ +struct llist_head *gprs_sndcp_comp_alloc(const void *ctx); + +/* Free a compression entitiy list */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities); + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, unsigned int entity); + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_add(const void *ctx, + struct llist_head *comp_entities, + const struct gprs_sndcp_comp_field + *comp_field); + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head + *comp_entities, uint8_t comp); + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head + *comp_entities, uint8_t nsapi); + +/* Find a comp_index for a given pcomp/dcomp value */ +uint8_t gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp *comp_entity, + uint8_t comp); + +/* Find a pcomp/dcomp value for a given comp_index */ +uint8_t gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp *comp_entity, + uint8_t comp_index); diff --git a/openbsc/include/openbsc/gprs_sndcp_pcomp.h b/openbsc/include/openbsc/gprs_sndcp_pcomp.h new file mode 100644 index 0000000..0733866 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_pcomp.h @@ -0,0 +1,44 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field); + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity); + +/* Expand packet header */ +int gprs_sndcp_pcomp_expand(uint8_t *data_o, uint8_t *data_i, unsigned int len, + uint8_t pcomp, + const struct llist_head *comp_entities); + +/* Compress packet header */ +int gprs_sndcp_pcomp_compress(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t *pcomp, + const struct llist_head *comp_entities, + uint8_t nsapi); diff --git a/openbsc/include/openbsc/sgsn.h b/openbsc/include/openbsc/sgsn.h index 59126fe..acd3e4b 100644 --- a/openbsc/include/openbsc/sgsn.h +++ b/openbsc/include/openbsc/sgsn.h @@ -89,6 +89,12 @@ int dynamic_lookup; struct oap_config oap; + + /* RFC1144 TCP/IP Header compression */ + struct { + int enabled; + int s01; + } pcomp_rfc1144; }; struct sgsn_instance { diff --git a/openbsc/include/openbsc/slhc_vj.h b/openbsc/include/openbsc/slhc.h similarity index 97% rename from openbsc/include/openbsc/slhc_vj.h rename to openbsc/include/openbsc/slhc.h index 8716d59..cd5a47c 100644 --- a/openbsc/include/openbsc/slhc_vj.h +++ b/openbsc/include/openbsc/slhc.h @@ -171,7 +171,8 @@ #define NULLSLCOMPR (struct slcompress *)0 /* In slhc.c: */ -struct slcompress *slhc_init(int rslots, int tslots); +struct slcompress *slhc_init(const void *ctx, int rslots, int tslots); + void slhc_free(struct slcompress *comp); int slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, @@ -180,4 +181,7 @@ int slhc_remember(struct slcompress *comp, unsigned char *icp, int isize); int slhc_toss(struct slcompress *comp); +void slhc_i_status(struct slcompress *comp); +void slhc_o_status(struct slcompress *comp); + #endif /* _SLHC_H */ diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index fa4a3dd..2910c02 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -26,7 +26,8 @@ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ - oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c + oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ + slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c index d6c8866..34b7afe 100644 --- a/openbsc/src/gprs/gprs_llc.c +++ b/openbsc/src/gprs/gprs_llc.c @@ -39,6 +39,7 @@ #include #include #include +#include #include static struct gprs_llc_llme *llme_alloc(uint32_t tlli); @@ -139,6 +140,16 @@ struct llist_head *xid_fields; struct gprs_llc_xid_field *xid_field; + struct gprs_llc_xid_field *xid_field_request; + struct gprs_llc_xid_field *xid_field_request_l3 = NULL; + + /* Pick layer3 XID from the XID request we have sent last */ + if (lle->llme->xid) { + llist_for_each_entry(xid_field_request, lle->llme->xid, list) { + if (xid_field_request->type == GPRS_LLC_XID_T_L3_PAR) + xid_field_request_l3 = xid_field_request; + } + } /* Parse and analyze XID-Response */ xid_fields = gprs_llc_parse_xid(NULL, bytes, bytes_len); @@ -149,12 +160,10 @@ llist_for_each_entry(xid_field, xid_fields, list) { /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ - if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { - LOGP(DLLC, LOGL_NOTICE, - "Ignoring SNDCP-XID-Field: XID: type=%i, data_len=%i, data=%s\n", - xid_field->type, xid_field->data_len, - osmo_hexdump_nospc(xid_field->data, - xid_field->data_len)); + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR && + xid_field_request_l3) { + sndcp_sn_xid_conf(xid_field, + xid_field_request_l3, lle); } /* Process LLC-XID fields: */ @@ -203,10 +212,6 @@ struct gprs_llc_xid_field *xid_field; struct gprs_llc_xid_field *xid_field_response; - /* Flush eventually pending XID fields */ - talloc_free(lle->llme->xid); - lle->llme->xid = NULL; - /* Parse and analyze XID-Request */ xid_fields = gprs_llc_parse_xid(lle->llme, bytes_request, bytes_request_len); @@ -235,6 +240,23 @@ (lle->llme, xid_field); llist_add(&xid_field_response->list, xid_fields_response); + } + } + + /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ + llist_for_each_entry(xid_field, xid_fields, list) { + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { + + xid_field_response = + talloc_zero(lle->llme, + struct gprs_llc_xid_field); + rc = sndcp_sn_xid_ind(xid_field, + xid_field_response, lle); + if (rc == 0) + llist_add(&xid_field_response->list, + xid_fields_response); + else + talloc_free(xid_field_response); } } @@ -524,11 +546,16 @@ llist_add(&llme->list, &gprs_llc_llmes); + llme->comp.proto = gprs_sndcp_comp_alloc(llme); + llme->comp.data = gprs_sndcp_comp_alloc(llme); + return llme; } static void llme_free(struct gprs_llc_llme *llme) { + gprs_sndcp_comp_free(llme->comp.proto); + gprs_sndcp_comp_free(llme->comp.data); talloc_free(llme->xid); llist_del(&llme->list); talloc_free(llme); diff --git a/openbsc/src/gprs/gprs_sndcp.c b/openbsc/src/gprs/gprs_sndcp.c index 4f71121..05957db 100644 --- a/openbsc/src/gprs/gprs_sndcp.c +++ b/openbsc/src/gprs/gprs_sndcp.c @@ -35,6 +35,131 @@ #include #include #include +#include +#include +#include +#include + +#define DEBUG_IP_PACKETS 1 /* 0=Disabled, 1=Enabled */ + +#if DEBUG_IP_PACKETS == 1 +/* Calculate TCP/IP checksum */ +static uint16_t calc_ip_csum(uint8_t *data, int len) +{ + int i; + uint32_t accumulator = 0; + uint16_t *pointer = (uint16_t *) data; + + for (i = len; i > 1; i -= 2) { + accumulator += *pointer; + pointer++; + } + + if (len % 2) + accumulator += *pointer; + + accumulator = (accumulator & 0xffff) + ((accumulator >> 16) & 0xffff); + accumulator += (accumulator >> 16) & 0xffff; + return (~accumulator); +} + +/* Calculate TCP/IP checksum */ +static uint16_t calc_tcpip_csum(const void *ctx, uint8_t *packet, int len) +{ + uint8_t *buf; + uint16_t csum; + + buf = talloc_zero_size(ctx, len); + memset(buf, 0, len); + memcpy(buf, packet + 12, 8); + buf[9] = packet[9]; + buf[11] = (len - 20) & 0xFF; + buf[10] = (len - 20) >> 8 & 0xFF; + memcpy(buf + 12, packet + 20, len - 20); + csum = calc_ip_csum(buf, len - 20 + 12); + talloc_free(buf); + return csum; +} + +/* Show some ip packet details */ +static void debug_ip_packet(uint8_t *data, int len, int dir, char *info) +{ + uint8_t tcp_flags; + char flags_debugmsg[256]; + int len_short; + static unsigned int packet_count = 0; + static unsigned int tcp_csum_err_count = 0; + static unsigned int ip_csum_err_count = 0; + + packet_count++; + + if (len > 80) + len_short = 80; + else + len_short = len; + + if (dir) + DEBUGP(DSNDCP, "%s: PHONE => NETWORK: %s\n", info, + osmo_hexdump_nospc(data, len_short)); + else + DEBUGP(DSNDCP, "%s: PHONE <= NETWORK: %s\n", info, + osmo_hexdump_nospc(data, len_short)); + + DEBUGP(DSNDCP, "%s: Length.: %d\n", info, len); + DEBUGP(DSNDCP, "%s: NO.: %d\n", info, packet_count); + + if (len < 20) { + DEBUGP(DSNDCP, "%s: Error: Short IP packet!\n", info); + return; + } + + if (calc_ip_csum(data, 20) != 0) { + DEBUGP(DSNDCP, "%s: Bad IP-Header checksum!\n", info); + ip_csum_err_count++; + } else + DEBUGP(DSNDCP, "%s: IP-Header checksum ok.\n", info); + + if (data[9] == 0x06) { + if (len < 40) { + DEBUGP(DSNDCP, "%s: Error: Short TCP packet!\n", info); + return; + } + + DEBUGP(DSNDCP, "%s: Protocol type: TCP\n", info); + tcp_flags = data[33]; + + if (calc_tcpip_csum(NULL, data, len) != 0) { + DEBUGP(DSNDCP, "%s: Bad TCP checksum!\n", info); + tcp_csum_err_count++; + } else + DEBUGP(DSNDCP, "%s: TCP checksum ok.\n", info); + + memset(flags_debugmsg, 0, sizeof(flags_debugmsg)); + if (tcp_flags & 1) + strcat(flags_debugmsg, "FIN "); + if (tcp_flags & 2) + strcat(flags_debugmsg, "SYN "); + if (tcp_flags & 4) + strcat(flags_debugmsg, "RST "); + if (tcp_flags & 8) + strcat(flags_debugmsg, "PSH "); + if (tcp_flags & 16) + strcat(flags_debugmsg, "ACK "); + if (tcp_flags & 32) + strcat(flags_debugmsg, "URG "); + DEBUGP(DSNDCP, "%s: FLAGS: %s\n", info, flags_debugmsg); + } else if (data[9] == 0x11) { + DEBUGP(DSNDCP, "%s: Protocol type: UDP\n", info); + } else { + DEBUGP(DSNDCP, "%s: Protocol type: (%02x)\n", info, data[9]); + } + + DEBUGP(DSNDCP, "%s: IP-Header checksum errors: %d\n", info, + ip_csum_err_count); + DEBUGP(DSNDCP, "%s: TCP-Checksum errors: %d\n", info, + tcp_csum_err_count); +} +#endif /* Chapter 7.2: SN-PDU Formats */ struct sndcp_common_hdr { @@ -143,6 +268,9 @@ struct msgb *msg; unsigned int seg_nr; uint8_t *npdu; + int npdu_len; + int rc; + uint8_t *expnd; LOGP(DSNDCP, LOGL_DEBUG, "TLLI=0x%08x NSAPI=%u: Defragment output PDU %u " "num_seg=%u tot_len=%u\n", sne->lle->llme->tlli, sne->nsapi, @@ -173,16 +301,46 @@ talloc_free(dqe); } + npdu_len = sne->defrag.tot_len; + /* FIXME: cancel timer */ /* actually send the N-PDU to the SGSN core code, which then * hands it off to the correct GTP tunnel + GGSN via gtp_data_req() */ - return sgsn_rx_sndcp_ud_ind(&sne->ra_id, sne->lle->llme->tlli, - sne->nsapi, msg, sne->defrag.tot_len, npdu); + + /* Decompress packet */ +#if DEBUG_IP_PACKETS == 1 + DEBUGP(DSNDCP, " \n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, "===================================================\n"); +#endif + expnd = talloc_zero_size(msg, msg->len + 64); + rc = gprs_sndcp_pcomp_expand(expnd, npdu, npdu_len, + sne->defrag.pcomp, sne->defrag.proto); + if (rc < 0) { + LOGP(DSNDCP, LOGL_ERROR, + "TCP/IP Header decompression failed!\n"); + talloc_free(expnd); + return -EIO; + } else + npdu_len = rc; +#if DEBUG_IP_PACKETS == 1 + debug_ip_packet(expnd, npdu_len, 1, "defrag_segments()"); + DEBUGP(DSNDCP, "===================================================\n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, " \n"); +#endif + + /* Hand off packet to gtp */ + rc = sgsn_rx_sndcp_ud_ind(&sne->ra_id, sne->lle->llme->tlli, + sne->nsapi, msg, npdu_len, expnd); + + talloc_free(expnd); + return rc; } -static int defrag_input(struct gprs_sndcp_entity *sne, struct msgb *msg, uint8_t *hdr, - unsigned int len) +static int defrag_input(struct gprs_sndcp_entity *sne, struct msgb *msg, + uint8_t *hdr, unsigned int len) { struct sndcp_common_hdr *sch; struct sndcp_udata_hdr *suh; @@ -343,7 +501,8 @@ }; /* returns '1' if there are more fragments to send, '0' if none */ -static int sndcp_send_ud_frag(struct sndcp_frag_state *fs) +static int sndcp_send_ud_frag(struct sndcp_frag_state *fs, + uint8_t pcomp, uint8_t dcomp) { struct gprs_sndcp_entity *sne = fs->sne; struct gprs_llc_lle *lle = sne->lle; @@ -380,8 +539,8 @@ if (sch->first) { scomph = (struct sndcp_comp_hdr *) msgb_put(fmsg, sizeof(*scomph)); - scomph->pcomp = 0; - scomph->dcomp = 0; + scomph->pcomp = pcomp; + scomph->dcomp = dcomp; } /* append the user-data header */ @@ -446,8 +605,37 @@ struct sndcp_comp_hdr *scomph; struct sndcp_udata_hdr *suh; struct sndcp_frag_state fs; + uint8_t pcomp = 0; + uint8_t dcomp = 0; + int rc; + uint8_t *compr; /* Identifiers from UP: (TLLI, SAPI) + (BVCI, NSEI) */ + + /* Compress packet */ +#if DEBUG_IP_PACKETS == 1 + DEBUGP(DSNDCP, " \n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, "===================================================\n"); + debug_ip_packet(msg->data, msg->len, 0, "sndcp_initdata_req()"); +#endif + compr = talloc_zero_size(msg, msg->len); + rc = gprs_sndcp_pcomp_compress(compr, msg->data, msg->len, &pcomp, + lle->llme->comp.proto, nsapi); + if (rc < 0) { + LOGP(DSNDCP, LOGL_ERROR, "TCP/IP Header compression failed!\n"); + talloc_free(compr); + return -EIO; + } else { + msg->len = rc; + memcpy(msg->data, compr, rc); + } + talloc_free(compr); +#if DEBUG_IP_PACKETS == 1 + DEBUGP(DSNDCP, "===================================================\n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, " \n"); +#endif sne = gprs_sndcp_entity_by_lle(lle, nsapi); if (!sne) { @@ -469,7 +657,7 @@ /* call function to generate and send fragments until all * of the N-PDU has been sent */ while (1) { - int rc = sndcp_send_ud_frag(&fs); + int rc = sndcp_send_ud_frag(&fs,pcomp,dcomp); if (rc == 0) return 0; if (rc < 0) @@ -489,8 +677,8 @@ sne->tx_npdu_nr = (sne->tx_npdu_nr + 1) % 0xfff; scomph = (struct sndcp_comp_hdr *) msgb_push(msg, sizeof(*scomph)); - scomph->pcomp = 0; - scomph->dcomp = 0; + scomph->pcomp = pcomp; + scomph->dcomp = dcomp; /* prepend common SNDCP header */ sch = (struct sndcp_common_hdr *) msgb_push(msg, sizeof(*sch)); @@ -512,6 +700,8 @@ uint8_t *npdu; uint16_t npdu_num __attribute__((unused)); int npdu_len; + int rc; + uint8_t *expnd; sch = (struct sndcp_common_hdr *) hdr; if (sch->first) { @@ -540,26 +730,58 @@ /* FIXME: move this RA_ID up to the LLME or even higher */ bssgp_parse_cell_id(&sne->ra_id, msgb_bcid(msg)); + if(scomph) { + sne->defrag.pcomp = scomph->pcomp; + sne->defrag.dcomp = scomph->dcomp; + sne->defrag.proto = lle->llme->comp.proto; + sne->defrag.data = lle->llme->comp.data; + } + /* any non-first segment is by definition something to defragment * as is any segment that tells us there are more segments */ if (!sch->first || sch->more) return defrag_input(sne, msg, hdr, len); - if (scomph && (scomph->pcomp || scomph->dcomp)) { - LOGP(DSNDCP, LOGL_ERROR, "We don't support compression yet\n"); - return -EIO; - } - npdu_num = (suh->npdu_high << 8) | suh->npdu_low; npdu = (uint8_t *)suh + sizeof(*suh); - npdu_len = (msg->data + msg->len) - npdu; + npdu_len = (msg->data + msg->len) - npdu - 3; /* -3 'removes' the FCS */ + if (npdu_len <= 0) { LOGP(DSNDCP, LOGL_ERROR, "Short SNDCP N-PDU: %d\n", npdu_len); return -EIO; } /* actually send the N-PDU to the SGSN core code, which then * hands it off to the correct GTP tunnel + GGSN via gtp_data_req() */ - return sgsn_rx_sndcp_ud_ind(&sne->ra_id, lle->llme->tlli, sne->nsapi, msg, npdu_len, npdu); + + /* Decompress packet */ +#if DEBUG_IP_PACKETS == 1 + DEBUGP(DSNDCP, " \n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, "===================================================\n"); +#endif + expnd = talloc_zero_size(msg, npdu_len + 64); + rc = gprs_sndcp_pcomp_expand(expnd, npdu, npdu_len, + sne->defrag.pcomp, sne->defrag.proto); + if (rc < 0) { + LOGP(DSNDCP, LOGL_ERROR, + "TCP/IP Header decompression failed!\n"); + talloc_free(expnd); + return -EIO; + } else + npdu_len = rc; +#if DEBUG_IP_PACKETS == 1 + debug_ip_packet(expnd, npdu_len, 1, "sndcp_llunitdata_ind()"); + DEBUGP(DSNDCP, "===================================================\n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, " \n"); +#endif + + /* Hand off packet to gtp */ + rc = sgsn_rx_sndcp_ud_ind(&sne->ra_id, lle->llme->tlli, + sne->nsapi, msg, npdu_len, expnd); + + talloc_free(expnd); + return rc; } #if 0 @@ -619,3 +841,322 @@ case LL_STATUS_IND: } #endif + +/* Generate SNDCP-XID message */ +static int gprs_llc_gen_sndcp_xid(uint8_t *bytes, int bytes_len, uint8_t nsapi) +{ + LLIST_HEAD(comp_fields); + struct gprs_sndcp_pcomp_rfc1144_params rfc1144_params; + struct gprs_sndcp_comp_field rfc1144_comp_field; + + memset(&rfc1144_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + + /* Setup which NSAPIs shall make use of rfc1144 */ + rfc1144_params.nsapi[0] = nsapi; + rfc1144_params.nsapi_len = 1; + + /* Setup rfc1144 operating parameters */ + rfc1144_params.s01 = sgsn->cfg.pcomp_rfc1144.s01; + + /* Setup rfc1144 compression field */ + rfc1144_comp_field.p = 1; + rfc1144_comp_field.entity = 0; + rfc1144_comp_field.algo = RFC_1144; + rfc1144_comp_field.comp[RFC1144_PCOMP1] = 1; + rfc1144_comp_field.comp[RFC1144_PCOMP2] = 2; + rfc1144_comp_field.comp_len = RFC1144_PCOMP_NUM; + rfc1144_comp_field.rfc1144_params = &rfc1144_params; + + /* Add compression field(s) to list */ + if (sgsn->cfg.pcomp_rfc1144.enabled) + llist_add(&rfc1144_comp_field.list, &comp_fields); + + /* Compile bytestream */ + return gprs_sndcp_compile_xid(bytes, bytes_len, &comp_fields); +} + +/* Set of SNDCP-XID bnegotiation (See also: TS 144 065, + * Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_req(struct gprs_llc_lle *lle, uint8_t nsapi) +{ + /* Note: The specification requires the SNDCP-User to set of an + * SNDCP xid request. See also 3GPP TS 44.065, 6.8 XID parameter + * negotiation, Figure 11: SNDCP XID negotiation procedure. In + * our case the SNDCP-User is sgsn_libgtp.c, which calls + * sndcp_sn_xid_req directly. */ + + uint8_t l3params[1024]; + int xid_len; + struct gprs_llc_xid_field xid_field_request; + + /* Generate compression parameter bytestream */ + xid_len = gprs_llc_gen_sndcp_xid(l3params, sizeof(l3params), nsapi); + + /* Send XID with the SNDCP-XID bytetsream included */ + if (xid_len > 0) { + xid_field_request.type = GPRS_LLC_XID_T_L3_PAR; + xid_field_request.data = l3params; + xid_field_request.data_len = xid_len; + return gprs_ll_xid_req(lle, &xid_field_request); + } + + /* When bytestream can not be generated, proceed without SNDCP-XID */ + else { + return gprs_ll_xid_req(lle, NULL); + } +} + +/* Handle header compression entites */ +static int handle_pcomp_entities(struct gprs_sndcp_comp_field *comp_field, + struct gprs_llc_lle *lle) +{ + /* Note: This functions also transforms the comp_field into its + * echo form (strips comp values, resets propose bit etc...) + * the processed comp_fields can then be sent back as XID- + * Response without further modification. */ + + /* Delete propose bit */ + comp_field->p = 0; + + /* Process proposed parameters */ + switch (comp_field->algo) { + case RFC_1144: + if (sgsn->cfg.pcomp_rfc1144.enabled && + comp_field->rfc1144_params->nsapi_len > 0) { + LOGP(DSNDCP, LOGL_DEBUG, + "Accepting RFC1144 header compression...\n"); + gprs_sndcp_comp_add(lle->llme, lle->llme->comp.proto, + comp_field); + } else { + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting RFC1144 header compression...\n"); + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + comp_field->rfc1144_params->nsapi_len = 0; + } + break; + case RFC_2507: + /* RFC 2507 is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting RFC2507 header compression...\n"); + comp_field->rfc2507_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + break; + case ROHC: + /* ROHC is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting ROHC header compression...\n"); + comp_field->rohc_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + break; + } + + return 0; +} + +/* Hanle data compression entites */ +static int handle_dcomp_entities(struct gprs_sndcp_comp_field *comp_field, + struct gprs_llc_lle *lle) +{ + /* See note in handle_pcomp_entities() */ + + /* Delete propose bit */ + comp_field->p = 0; + + /* Process proposed parameters */ + switch (comp_field->algo) { + case V42BIS: + /* V42BIS is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting V.42bis data compression...\n"); + comp_field->v42bis_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + break; + case V44: + /* V44 is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting V.44 data compression...\n"); + comp_field->v44_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + break; + } + + return 0; + +} + +/* Process SNDCP-XID indication + * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_ind(struct gprs_llc_xid_field *xid_field_indication, + struct gprs_llc_xid_field *xid_field_response, + struct gprs_llc_lle *lle) +{ + /* Note: This function computes the SNDCP-XID response that is sent + * back to the phone when a phone originated XID is received. The + * Input XID fields are directly processed and the result is directly + * handed back. */ + + int rc; + int compclass; + + struct llist_head *comp_fields; + struct gprs_sndcp_comp_field *comp_field; + + OSMO_ASSERT(xid_field_indication); + OSMO_ASSERT(xid_field_response); + OSMO_ASSERT(lle); + + /* Parse SNDCP-CID XID-Field */ + comp_fields = gprs_sndcp_parse_xid(lle->llme, + xid_field_indication->data, + xid_field_indication->data_len, + NULL); + if (!comp_fields) + return -EINVAL; + + /* Don't bother with empty indications */ + if (llist_empty(comp_fields)) { + xid_field_response->data = NULL; + xid_field_response->data_len = 0; + DEBUGP(DSNDCP, + "SNDCP-XID indication did not contain any parameters!\n"); + return 0; + } + + /* Handle compression entites */ + DEBUGP(DSNDCP, "Unmodified SNDCP-XID received from the phone:\n"); + gprs_sndcp_dump_comp_fields(comp_fields, LOGL_DEBUG); + + llist_for_each_entry(comp_field, comp_fields, list) { + compclass = gprs_sndcp_get_compression_class(comp_field); + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + rc = handle_pcomp_entities(comp_field, lle); + else if (compclass == SNDCP_XID_DATA_COMPRESSION) + rc = handle_dcomp_entities(comp_field, lle); + else { + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + rc = 0; + } + + if (rc < 0) { + talloc_free(comp_fields); + return -EINVAL; + } + } + + DEBUGP(DSNDCP, + "Modified version of received SNDCP-XID to be sent back from the ggsn:\n"); + gprs_sndcp_dump_comp_fields(comp_fields, LOGL_DEBUG); + + /* Reserve some memory to store the modified SNDCP-XID bytes */ + xid_field_response->data = + talloc_zero_size(lle->llme, xid_field_indication->data_len); + + /* Set Type flag for response */ + xid_field_response->type = GPRS_LLC_XID_T_L3_PAR; + + /* Compile modified SNDCP-XID bytes */ + rc = gprs_sndcp_compile_xid(xid_field_response->data, + xid_field_indication->data_len, + comp_fields); + + if (rc > 0) + xid_field_response->data_len = rc; + else { + talloc_free(xid_field_response->data); + xid_field_response->data = NULL; + xid_field_response->data_len = 0; + return -EINVAL; + } + + talloc_free(comp_fields); + + return 0; +} + +/* Process SNDCP-XID indication + * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_conf(struct gprs_llc_xid_field *xid_field_conf, + struct gprs_llc_xid_field *xid_field_request, + struct gprs_llc_lle *lle) +{ + /* Note: This function handles an incomming SNDCP-XID confirmiation. + * Since the confirmation fields may lack important parameters we + * will reconstruct these missing fields using the original request + * we have sent. After that we will create (or delete) the + * compression entites */ + + struct llist_head *comp_fields_req; + struct llist_head *comp_fields_conf; + struct gprs_sndcp_comp_field *comp_field; + int rc; + int compclass; + + /* We need both, the confirmation that is sent back by the phone, + * and the original request we have sent. If one of this is missing + * we can not process the confirmation, the caller must check if + * request and confirmation fields are available. */ + OSMO_ASSERT(xid_field_conf); + OSMO_ASSERT(xid_field_request); + + /* Parse SNDCP-CID XID-Field */ + comp_fields_req = gprs_sndcp_parse_xid(lle->llme, + xid_field_request->data, + xid_field_request->data_len, + NULL); + if (!comp_fields_req) + return -EINVAL; + + DEBUGP(DSNDCP, "Unmodified SNDCP-XID sent from the ggsn:\n"); + gprs_sndcp_dump_comp_fields(comp_fields_req, LOGL_DEBUG); + + /* Parse SNDCP-CID XID-Field */ + comp_fields_conf = gprs_sndcp_parse_xid(lle->llme, + xid_field_conf->data, + xid_field_conf->data_len, + comp_fields_req); + if (!comp_fields_conf) + return -EINVAL; + + DEBUGP(DSNDCP, + "Modified SNDCP-XID received from the phone:\n"); + gprs_sndcp_dump_comp_fields(comp_fields_conf, LOGL_DEBUG); + + /* Handle compression entites */ + llist_for_each_entry(comp_field, comp_fields_conf, list) { + compclass = gprs_sndcp_get_compression_class(comp_field); + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + rc = handle_pcomp_entities(comp_field, lle); + else if (compclass == SNDCP_XID_DATA_COMPRESSION) + rc = handle_dcomp_entities(comp_field, lle); + else { + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + rc = 0; + } + + if (rc < 0) { + talloc_free(comp_fields_req); + talloc_free(comp_fields_conf); + return -EINVAL; + } + } + + talloc_free(comp_fields_req); + talloc_free(comp_fields_conf); + + return 0; +} diff --git a/openbsc/src/gprs/gprs_sndcp_comp.c b/openbsc/src/gprs/gprs_sndcp_comp.c new file mode 100644 index 0000000..ede584e --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_comp.c @@ -0,0 +1,320 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +/* Create a new compression entity from a XID-Field */ +static struct gprs_sndcp_comp *gprs_sndcp_comp_create(const void *ctx, + const struct + gprs_sndcp_comp_field + *comp_field) +{ + struct gprs_sndcp_comp *comp_entity; + comp_entity = talloc_zero(ctx, struct gprs_sndcp_comp); + + /* Copy relevant information from the SNDCP-XID field */ + comp_entity->entity = comp_field->entity; + comp_entity->comp_len = comp_field->comp_len; + memcpy(comp_entity->comp, comp_field->comp, sizeof(comp_entity->comp)); + + if (comp_field->rfc1144_params) { + comp_entity->nsapi_len = comp_field->rfc1144_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc1144_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->rfc2507_params) { + comp_entity->nsapi_len = comp_field->rfc2507_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc2507_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->rohc_params) { + comp_entity->nsapi_len = comp_field->rohc_params->nsapi_len; + memcpy(comp_entity->nsapi, comp_field->rohc_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->v42bis_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->v44_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + sizeof(comp_entity->nsapi)); + } else { + /* The caller is expected to check carefully if the all + * data fields required for compression entity creation + * are present. Otherwise we blow an assertion here */ + OSMO_ASSERT(false); + } + comp_entity->algo = comp_field->algo; + + /* Check if an NSAPI is selected, if not, it does not make sense + * to create the compression entity, since the caller should + * have checked the presence of the NSAPI, we blow an assertion + * in case of missing NSAPIs */ + OSMO_ASSERT(comp_entity->nsapi_len > 0); + + /* Determine of which class our compression entity will be + * (Protocol or Data compresson ?) */ + comp_entity->compclass = gprs_sndcp_get_compression_class(comp_field); + + OSMO_ASSERT(comp_entity->compclass != -1); + + /* Create an algorithm specific compression context */ + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + if (gprs_sndcp_pcomp_init(ctx, comp_entity, comp_field) != 0) { + talloc_free(comp_entity); + comp_entity = NULL; + } + } else { + LOGP(DSNDCP, LOGL_ERROR, + "We don't support data compression yet!\n"); + talloc_free(comp_entity); + return NULL; + } + + /* Display info message */ + if (comp_entity == NULL) { + LOGP(DSNDCP, LOGL_ERROR, + "Header compression entity (%d) creation failed!\n", + comp_entity->entity); + return NULL; + } + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "New header compression entity (%d) created.\n", + comp_entity->entity); + } else { + LOGP(DSNDCP, LOGL_INFO, + "New data compression entity (%d) created.\n", + comp_entity->entity); + } + + return comp_entity; +} + +/* Allocate a compression enitiy list */ +struct llist_head *gprs_sndcp_comp_alloc(const void *ctx) +{ + struct llist_head *lh; + + lh = talloc_zero(ctx, struct llist_head); + INIT_LLIST_HEAD(lh); + + return lh; +} + +/* Free a compression entitiy list */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities) +{ + struct gprs_sndcp_comp *comp_entity; + + /* We expect the caller to take care of allocating a + * compression entity list properly. Attempting to + * free a non existing list clearly points out + * a malfunction. */ + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + /* Free compression entity */ + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %d ...\n", + comp_entity->entity); + gprs_sndcp_pcomp_term(comp_entity); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %d ...\n", + comp_entity->entity); + } + } + + talloc_free(comp_entities); +} + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, + unsigned int entity) +{ + struct gprs_sndcp_comp *comp_entity; + struct gprs_sndcp_comp *comp_entity_to_delete = NULL; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) { + comp_entity_to_delete = comp_entity; + break; + } + } + + if (!comp_entity_to_delete) + return; + + if (comp_entity_to_delete->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %d ...\n", + comp_entity_to_delete->entity); + gprs_sndcp_pcomp_term(comp_entity_to_delete); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %d ...\n", + comp_entity_to_delete->entity); + } + + /* Delete compression entity */ + llist_del(&comp_entity_to_delete->list); + talloc_free(comp_entity_to_delete); +} + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_add(const void *ctx, + struct llist_head *comp_entities, + const struct gprs_sndcp_comp_field + *comp_field) +{ + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(comp_entities); + OSMO_ASSERT(comp_field); + + /* Just to be sure, if the entity is already in + * the list it will be deleted now */ + gprs_sndcp_comp_delete(comp_entities, comp_field->entity); + + /* Create and add a new entity to the list */ + comp_entity = gprs_sndcp_comp_create(ctx, comp_field); + + if (!comp_entity) + return NULL; + + llist_add(&comp_entity->list, comp_entities); + return comp_entity; +} + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head + *comp_entities, uint8_t comp) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return comp_entity; + } + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given pcomp/dcomp value %d.\n", + comp); + return NULL; +} + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head + *comp_entities, uint8_t nsapi) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->nsapi_len; i++) { + if (comp_entity->nsapi[i] == nsapi) + return comp_entity; + } + } + + return NULL; +} + +/* Find a comp_index for a given pcomp/dcomp value */ +uint8_t gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp *comp_entity, + uint8_t comp) +{ + /* Note: This function returns a normalized version of the comp value, + * which matches up with the position of the comp field. Since comp=0 + * is reserved for "no compression", the index value starts counting + * at one. The return value is the PCOMPn/DCOMPn value one can find + * in the Specification (see e.g. 3GPP TS 44.065, 6.5.3.2, Table 7) */ + + int i; + OSMO_ASSERT(comp_entity); + + /* A pcomp/dcomp value of zero is reserved for "no comproession", + * So we just bail and return zero in this case */ + if (comp == 0) + return 0; + + /* Look in the pcomp/dcomp list for the index */ + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return i + 1; + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching comp_index for given pcomp/dcomp value %d\n", + comp); + return 0; +} + +/* Find a pcomp/dcomp value for a given comp_index */ +uint8_t gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp *comp_entity, + uint8_t comp_index) +{ + OSMO_ASSERT(comp_entity); + + /* A comp_index of zero translates to zero right away. */ + if (comp_index == 0) + return 0; + + if (comp_index > comp_entity->comp_len) { + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching pcomp/dcomp value for given comp_index value %d.\n", + comp_index); + return 0; + } + + /* Look in the pcomp/dcomp list for the comp_index, see + * note in gprs_sndcp_comp_get_idx() */ + return comp_entity->comp[comp_index - 1]; +} diff --git a/openbsc/src/gprs/gprs_sndcp_pcomp.c b/openbsc/src/gprs/gprs_sndcp_pcomp.c new file mode 100644 index 0000000..eca48b6 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_pcomp.c @@ -0,0 +1,288 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a new header compression + * entity is created by gprs_sndcp.c */ + + OSMO_ASSERT(comp_entity); + OSMO_ASSERT(comp_field); + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + comp_entity->state = + slhc_init(ctx, comp_field->rfc1144_params->s01 + 1, + comp_field->rfc1144_params->s01 + 1); + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression initalized.\n"); + return 0; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a header compression + * entity is deleted by gprs_sndcp.c */ + + OSMO_ASSERT(comp_entity); + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + if (comp_entity->state) { + slhc_free((struct slcompress *)comp_entity->state); + comp_entity->state = NULL; + } + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression terminated.\n"); + return; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Compress a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_compress(uint8_t *pcomp_index, + uint8_t *data_o, uint8_t *data_i, + unsigned int len, + struct slcompress *comp) +{ + uint8_t *comp_ptr; + int compr_len; + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Run compressor */ + compr_len = slhc_compress(comp, data_i, len, data_o, &comp_ptr, 0); + + /* Generate pcomp_index */ + if (data_o[0] & SL_TYPE_COMPRESSED_TCP) { + *pcomp_index = 2; + data_o[0] &= ~SL_TYPE_COMPRESSED_TCP; + } else if ((data_o[0] & SL_TYPE_UNCOMPRESSED_TCP) == + SL_TYPE_UNCOMPRESSED_TCP) { + *pcomp_index = 1; + data_o[0] &= 0x4F; + } else + *pcomp_index = 0; + + return compr_len; +} + +/* Expand a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_expand(uint8_t *data_o, uint8_t *data_i, + unsigned int len, + uint8_t pcomp_index, + struct slcompress *comp) +{ + int data_decompressed_len; + int type; + + /* Note: this function should never be called with pcomp_index=0, + * since this condition is already filtered + * out by gprs_sndcp_pcomp_expand() */ + + /* Determine the data type by the PCOMP index */ + switch (pcomp_index) { + case 0: + type = SL_TYPE_IP; + case 1: + type = SL_TYPE_UNCOMPRESSED_TCP; + break; + case 2: + type = SL_TYPE_COMPRESSED_TCP; + break; + default: + LOGP(DSNDCP, LOGL_ERROR, "gprs_sndcp_pcomp_rfc1144_expand() Invalid pcomp_index value (%d) detected, assuming no compression!\n", + pcomp_index); + type = SL_TYPE_IP; + break; + } + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Restore the original version nibble on + * marked uncompressed packets */ + if (type == SL_TYPE_UNCOMPRESSED_TCP) { + /* Just in case the phone tags uncompressed tcp-data + * (normally this is handled by pcomp so there is + * no need for tagging the data) */ + data_o[0] &= 0x4F; + data_decompressed_len = slhc_remember(comp, data_o, len); + return data_decompressed_len; + } + + /* Uncompress compressed packets */ + else if (type == SL_TYPE_COMPRESSED_TCP) { + data_decompressed_len = slhc_uncompress(comp, data_o, len); + return data_decompressed_len; + } + + /* Regular or unknown packets will not be touched */ + return len; +} + +/* Expand packet header */ +int gprs_sndcp_pcomp_expand(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t pcomp, + const struct llist_head *comp_entities) +{ + int rc; + uint8_t pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data_o); + OSMO_ASSERT(data_i); + OSMO_ASSERT(comp_entities); + + LOGP(DSNDCP, LOGL_DEBUG, "Compression entity list: comp_entities=%p\n", + comp_entities); + + LOGP(DSNDCP, LOGL_DEBUG, "Header compression mode: pcomp=%d\n", pcomp); + + /* Skip on pcomp=0 */ + if (pcomp == 0) { + memcpy(data_o, data_i, len); + return len; + } + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_comp(comp_entities, pcomp); + + /* Skip compression if no suitable compression entity can be found */ + if (comp_entity == NULL) { + memcpy(data_o, data_i, len); + return len; + } + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION); + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144); + + /* Find pcomp_index */ + pcomp_index = gprs_sndcp_comp_get_idx(comp_entity, pcomp); + + /* Run decompression algo */ + rc = gprs_sndcp_pcomp_rfc1144_expand(data_o, data_i, len, pcomp_index, + comp_entity->state); + slhc_i_status(comp_entity->state); + slhc_o_status(comp_entity->state); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header expansion done, old length=%d, new length=%d, entity=%p\n", + len, rc, comp_entity); + + return rc; +} + +/* Compress packet header */ +int gprs_sndcp_pcomp_compress(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t *pcomp, + const struct llist_head *comp_entities, + uint8_t nsapi) +{ + int rc; + uint8_t pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data_o); + OSMO_ASSERT(data_i); + OSMO_ASSERT(pcomp); + OSMO_ASSERT(comp_entities); + + LOGP(DSNDCP, LOGL_DEBUG, "Compression entity list: comp_entities=%p\n", + comp_entities); + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_nsapi(comp_entities, nsapi); + + /* Skip compression if no suitable compression entity can be found */ + if (!comp_entity) { + *pcomp = 0; + memcpy(data_o, data_i, len); + return len; + } + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION); + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144); + + /* Run compression algo */ + rc = gprs_sndcp_pcomp_rfc1144_compress(&pcomp_index, data_o, data_i, + len, comp_entity->state); + slhc_i_status(comp_entity->state); + slhc_o_status(comp_entity->state); + + /* Find pcomp value */ + *pcomp = gprs_sndcp_comp_get_comp(comp_entity, pcomp_index); + + LOGP(DSNDCP, LOGL_DEBUG, "Header compression mode: pcomp=%d\n", *pcomp); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header expansion done, old length=%d, new length=%d, entity=%p\n", + len, rc, comp_entity); + return rc; +} diff --git a/openbsc/src/gprs/sgsn_libgtp.c b/openbsc/src/gprs/sgsn_libgtp.c index be7637a..6e6bbfd 100644 --- a/openbsc/src/gprs/sgsn_libgtp.c +++ b/openbsc/src/gprs/sgsn_libgtp.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -307,6 +308,8 @@ static int send_act_pdp_cont_acc(struct sgsn_pdp_ctx *pctx) { struct sgsn_signal_data sig_data; + int rc; + struct gprs_llc_lle *lle; /* Inform others about it */ memset(&sig_data, 0, sizeof(sig_data)); @@ -314,7 +317,17 @@ osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_ACT, &sig_data); /* Send PDP CTX ACT to MS */ - return gsm48_tx_gsm_act_pdp_acc(pctx); + rc = gsm48_tx_gsm_act_pdp_acc(pctx); + if(rc < 0) + return rc; + + /* Send SNDCP XID to MS */ + lle = &pctx->mm->gb.llme->lle[pctx->sapi]; + rc = sndcp_sn_xid_req(lle,pctx->nsapi); + if(rc < 0) + return rc; + + return 0; } /* The GGSN has confirmed the creation of a PDP Context */ diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c index 52fc985..894ce84 100644 --- a/openbsc/src/gprs/sgsn_main.c +++ b/openbsc/src/gprs/sgsn_main.c @@ -292,6 +292,11 @@ .description = "SCCP User Adaptation (SUA)", .enabled = 1, .loglevel = LOGL_DEBUG, }, + [DSLHC] = { + .name = "DSLHC", + .description = "RFC1144 TCP/IP Header compression (SLHC)", + .enabled = 1, .loglevel = LOGL_DEBUG, + }, }; static const struct log_info gprs_log_info = { diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c index e6dc68d..bc53743 100644 --- a/openbsc/src/gprs/sgsn_vty.c +++ b/openbsc/src/gprs/sgsn_vty.c @@ -269,6 +269,12 @@ vty_out(vty, " timer t3395 %d%s", g_cfg->timers.T3395, VTY_NEWLINE); vty_out(vty, " timer t3397 %d%s", g_cfg->timers.T3397, VTY_NEWLINE); + if (g_cfg->pcomp_rfc1144.enabled) { + vty_out(vty, " compression rfc1144 slots %d%s", + g_cfg->pcomp_rfc1144.s01+1, VTY_NEWLINE); + } else + vty_out(vty, " no compression rfc1144%s", VTY_NEWLINE); + return CMD_SUCCESS; } @@ -1074,6 +1080,28 @@ return CMD_SUCCESS; } +#define COMPRESSION_STR "Configure compression\n" +DEFUN(cfg_no_comp_rfc1144, cfg_no_comp_rfc1144_cmd, + "no compression rfc1144", + NO_STR COMPRESSION_STR + "disable rfc1144 TCP/IP header compression\n") +{ + g_cfg->pcomp_rfc1144.enabled = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_comp_rfc1144, cfg_comp_rfc1144_cmd, + "compression rfc1144 slots <1-256>", + COMPRESSION_STR + "RFC1144 Header compresion scheme\n" + "Number of compression state slots\n" + "Number of compression state slots\n") +{ + g_cfg->pcomp_rfc1144.enabled = 1; + g_cfg->pcomp_rfc1144.s01 = atoi(argv[0]) - 1; + return CMD_SUCCESS; +} + int sgsn_vty_init(void) { install_element_ve(&show_sgsn_cmd); @@ -1128,6 +1156,9 @@ install_element(SGSN_NODE, &cfg_sgsn_T3395_cmd); install_element(SGSN_NODE, &cfg_sgsn_T3397_cmd); + install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd); + install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd); + return 0; } diff --git a/openbsc/src/gprs/slhc.c b/openbsc/src/gprs/slhc.c index 27ed252..cbdf8db 100644 --- a/openbsc/src/gprs/slhc.c +++ b/openbsc/src/gprs/slhc.c @@ -50,61 +50,77 @@ * driver code belonging close to PPP and SLIP */ -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#ifdef CONFIG_INET -/* Entire module is for IP only */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#define ERR_PTR(x) x + static unsigned char *encode(unsigned char *cp, unsigned short n); static long decode(unsigned char **cpp); static unsigned char * put16(unsigned char *cp, unsigned short x); static unsigned short pull16(unsigned char **cpp); +/* Replacement for kernel space function ip_fast_csum() */ +static uint16_t ip_fast_csum(uint8_t *iph, int ihl) +{ + int i; + uint16_t temp; + uint32_t accumulator = 0xFFFF; + + for(i=0;i0xFFFF) + { + accumulator++; + accumulator&=0xFFFF; + } + } + + return (uint16_t)(htons(~accumulator)&0xFFFF); +} + +/* Replacement for kernel space function put_unaligned() */ +static void put_unaligned(uint16_t val, void *ptr) +{ + memcpy(ptr,&val,sizeof(val)); +} + + /* Allocate compression data structure * slots must be in range 0 to 255 (zero meaning no compression) * Returns pointer to structure or ERR_PTR() on error. */ struct slcompress * -slhc_init(int rslots, int tslots) +slhc_init(const void *ctx, int rslots, int tslots) { register short i; register struct cstate *ts; struct slcompress *comp; if (rslots < 0 || rslots > 255 || tslots < 0 || tslots > 255) - return ERR_PTR(-EINVAL); + return NULL; - comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL); + comp = (struct slcompress *)talloc_zero_size(ctx,sizeof(struct slcompress)); if (! comp) goto out_fail; if (rslots > 0) { size_t rsize = rslots * sizeof(struct cstate); - comp->rstate = kzalloc(rsize, GFP_KERNEL); + comp->rstate = (struct cstate *) talloc_zero_size(ctx, rsize); if (! comp->rstate) goto out_free; comp->rslot_limit = rslots - 1; @@ -112,7 +128,7 @@ if (tslots > 0) { size_t tsize = tslots * sizeof(struct cstate); - comp->tstate = kzalloc(tsize, GFP_KERNEL); + comp->tstate = (struct cstate *) talloc_zero_size(ctx, tsize); if (! comp->tstate) goto out_free2; comp->tslot_limit = tslots - 1; @@ -141,11 +157,11 @@ return comp; out_free2: - kfree(comp->rstate); + talloc_free(comp->rstate); out_free: - kfree(comp); + talloc_free(comp); out_fail: - return ERR_PTR(-ENOMEM); + return NULL; } @@ -153,16 +169,18 @@ void slhc_free(struct slcompress *comp) { + DEBUGP(DSLHC, "slhc_free(): Freeing compression states...\n"); + if ( comp == NULLSLCOMPR ) return; if ( comp->tstate != NULLSLSTATE ) - kfree( comp->tstate ); + talloc_free(comp->tstate ); if ( comp->rstate != NULLSLSTATE ) - kfree( comp->rstate ); + talloc_free( comp->rstate ); - kfree( comp ); + talloc_free( comp ); } @@ -187,6 +205,8 @@ } else { *cp++ = n; } + + DEBUGP(DSLHC, "encode(): n=%04x\n",n); return cp; } @@ -256,6 +276,7 @@ comp->sls_o_nontcp++; else comp->sls_o_tcp++; + DEBUGP(DSLHC, "slhc_compress(): Not a TCP packat, will not touch...\n"); return isize; } /* Extract TCP header */ @@ -271,6 +292,7 @@ ! (th->ack)){ /* TCP connection stuff; send as regular IP */ comp->sls_o_tcp++; + DEBUGP(DSLHC, "slhc_compress(): Packet is part of a TCP connection, will not touch...\n"); return isize; } /* @@ -287,6 +309,9 @@ * states via linear search. If we don't find a state * for the datagram, the oldest state is (re-)used. */ + + DEBUGP(DSLHC, "slhc_compress(): Compressible packet detected!\n"); + for ( ; ; ) { if( ip->saddr == cs->cs_ip.saddr && ip->daddr == cs->cs_ip.daddr @@ -310,11 +335,14 @@ * state points to the newest and we only need to set * xmit_oldest to update the lru linkage. */ + + DEBUGP(DSLHC, "slhc_compress(): Header not yet seen, will memorize header for the next turn...\n"); comp->sls_o_misses++; comp->xmit_oldest = lcs->cs_this; goto uncompressed; found: + DEBUGP(DSLHC, "slhc_compress(): Header already seen, trying to compress...\n"); /* * Found it -- move to the front on the connection list. */ @@ -344,6 +372,39 @@ */ oth = &cs->cs_tcp; + /* Display a little more debug information about which of the + * header fields changed unexpectedly */ + if(ip->version != cs->cs_ip.version) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->version != cs->cs_ip.version\n"); + if(ip->ihl != cs->cs_ip.ihl) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->ihl != cs->cs_ip.ihl\n"); + if(ip->tos != cs->cs_ip.tos) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->tos != cs->cs_ip.tos\n"); + if((ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))\n"); + if(ip->ttl != cs->cs_ip.ttl) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->ttl != cs->cs_ip.ttl\n"); + if(th->doff != cs->cs_tcp.doff) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: th->doff != cs->cs_tcp.doff\n"); + if(ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) { + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0)\n"); + DEBUGP(DSLHC, "slhc_compress(): ip->ihl = %i\n", ip->ihl); + DEBUGP(DSLHC, "slhc_compress(): ip+1 = %s\n", + osmo_hexdump_nospc((uint8_t*)(ip+1),((ip->ihl)-5)*4)); + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: cs->cs_ipopt = %s\n", + osmo_hexdump_nospc((uint8_t*)(cs->cs_ipopt),((ip->ihl)-5)*4)); + } + if(th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0) { + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)\n"); + DEBUGP(DSLHC, "slhc_compress(): th->doff = %i\n", th->doff); + DEBUGP(DSLHC, "slhc_compress(): th+1 = %s\n", + osmo_hexdump_nospc((uint8_t*)(th+1),((th->doff)-5)*4)); + DEBUGP(DSLHC, "slhc_compress(): cs->cs_tcpopt = %s\n", + osmo_hexdump_nospc((uint8_t*)cs->cs_tcpopt, + ((th->doff)-5)*4)); + } + + if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl || ip->tos != cs->cs_ip.tos || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000)) @@ -351,6 +412,7 @@ || th->doff != cs->cs_tcp.doff || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){ + DEBUGP(DSLHC, "slhc_compress(): The header contains unexpected changes, can't compress...\n"); goto uncompressed; } @@ -362,6 +424,7 @@ */ if(th->urg){ deltaS = ntohs(th->urg_ptr); + DEBUGP(DSLHC, "slhc_compress(): flag: Urgent Pointer (U) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_U; } else if(th->urg_ptr != oth->urg_ptr){ @@ -369,21 +432,29 @@ * implementation should never do this but RFC793 * doesn't prohibit the change so we have to deal * with it. */ + DEBUGP(DSLHC, "slhc_compress(): URG not set but urp changed, can't compress...\n"); goto uncompressed; } if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){ + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Window (W) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_W; } if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){ - if(deltaA > 0x0000ffff) + if(deltaA > 0x0000ffff) { + DEBUGP(DSLHC, "slhc_compress(): (deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L, can't compress...\n"); goto uncompressed; + } + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Ack (A) = 1\n"); cp = encode(cp,deltaA); changes |= NEW_A; } if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){ - if(deltaS > 0x0000ffff) + if(deltaS > 0x0000ffff) { + DEBUGP(DSLHC, "slhc_compress(): (deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L, can't compress...\n"); goto uncompressed; + } + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_S; } @@ -399,17 +470,21 @@ if(ip->tot_len != cs->cs_ip.tot_len && ntohs(cs->cs_ip.tot_len) == hlen) break; + DEBUGP(DSLHC, "slhc_compress(): Retransmitted packet detected, can't compress...\n"); goto uncompressed; case SPECIAL_I: case SPECIAL_D: /* actual changes match one of our special case encodings -- * send packet uncompressed. */ + DEBUGP(DSLHC, "slhc_compress(): Special case detected, can't compress...\n"); goto uncompressed; case NEW_S|NEW_A: if(deltaS == deltaA && deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ /* special case for echoed terminal traffic */ + DEBUGP(DSLHC, "slhc_compress(): Special case for echoed terminal traffic detected...\n"); + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1, Delta Window (W) = 1, Urgent Pointer (U) = 1\n"); changes = SPECIAL_I; cp = new_seq; } @@ -417,6 +492,8 @@ case NEW_S: if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ /* special case for data xfer */ + DEBUGP(DSLHC, "slhc_compress(): Special case for data xfer detected...\n"); + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1, Delta Ack (A) = 1, Delta Window (W) = 1, Urgent Pointer (U) = 1\n"); changes = SPECIAL_D; cp = new_seq; } @@ -424,11 +501,14 @@ } deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id); if(deltaS != 1){ + DEBUGP(DSLHC, "slhc_compress(): flag: Delta IP ID (I) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_I; } - if(th->psh) + if(th->psh) { + DEBUGP(DSLHC, "slhc_compress(): flag: Push (P) = 1\n"); changes |= TCP_PUSH_BIT; + } /* Grab the cksum before we overwrite it below. Then update our * state with this packet's header. */ @@ -445,6 +525,7 @@ if(compress_cid == 0 || comp->xmit_current != cs->cs_this){ cp = ocp; *cpp = ocp; + DEBUGP(DSLHC, "slhc_compress(): flag: Connection number (C) = 1\n"); *cp++ = changes | NEW_C; *cp++ = cs->cs_this; comp->xmit_current = cs->cs_this; @@ -456,6 +537,10 @@ *(__sum16 *)cp = csum; cp += 2; /* deltaS is now the size of the change section of the compressed header */ + + DEBUGP(DSLHC, "slhc_compress(): Delta-list length (deltaS) = %li\n",deltaS); + DEBUGP(DSLHC, "slhc_compress(): Original header len (hlen) = %i\n",hlen); + memcpy(cp,new_seq,deltaS); /* Write list of deltas */ memcpy(cp+deltaS,icp+hlen,isize-hlen); comp->sls_o_compressed++; @@ -467,6 +552,7 @@ * to use on future compressed packets in the protocol field). */ uncompressed: + DEBUGP(DSLHC, "slhc_compress(): Packet will be sent uncompressed...\n"); memcpy(&cs->cs_ip,ip,20); memcpy(&cs->cs_tcp,th,20); if (ip->ihl > 5) @@ -538,6 +624,8 @@ switch(changes & SPECIALS_MASK){ case SPECIAL_I: /* Echoed terminal traffic */ + DEBUGP(DSLHC, "slhc_uncompress(): Echoed terminal traffic detected\n"); + { register short i; i = ntohs(ip->tot_len) - hdrlen; @@ -547,11 +635,13 @@ break; case SPECIAL_D: /* Unidirectional data */ + DEBUGP(DSLHC, "slhc_uncompress(): Unidirectional data detected\n"); thp->seq = htonl( ntohl(thp->seq) + ntohs(ip->tot_len) - hdrlen); break; default: + DEBUGP(DSLHC, "slhc_uncompress(): default packet type detected\n"); if(changes & NEW_U){ thp->urg = 1; if((x = decode(&cp)) == -1) { @@ -601,6 +691,7 @@ ip->tot_len = htons(len); ip->check = 0; + DEBUGP(DSLHC, "slhc_uncompress(): making space for the reconstructed header...\n"); memmove(icp + hdrlen, cp, len - hdrlen); cp = icp; @@ -625,6 +716,7 @@ return len; bad: + DEBUGP(DSLHC, "slhc_uncompress(): bad packet detected!\n"); comp->sls_i_error++; return slhc_toss( comp ); } @@ -641,6 +733,7 @@ if(isize < 20) { /* The packet is shorter than a legal IP header */ comp->sls_i_runt++; + DEBUGP(DSLHC, "slhc_remember(): The packet is shorter than a legal IP header ==> slhc_toss()\n"); return slhc_toss( comp ); } /* Peek at the IP header's IHL field to find its length */ @@ -648,6 +741,7 @@ if(ihl < 20 / 4){ /* The IP header length field is too small */ comp->sls_i_runt++; + DEBUGP(DSLHC, "slhc_remember(): The IP header length field is too small ==> slhc_toss()\n"); return slhc_toss( comp ); } index = icp[9]; @@ -656,10 +750,12 @@ if (ip_fast_csum(icp, ihl)) { /* Bad IP header checksum; discard */ comp->sls_i_badcheck++; + DEBUGP(DSLHC, "slhc_remember(): Bad IP header checksum; discard ==> slhc_toss()\n"); return slhc_toss( comp ); } if(index > comp->rslot_limit) { comp->sls_i_error++; + DEBUGP(DSLHC, "slhc_remember(): index > comp->rslot_limit ==> slhc_toss()\n"); return slhc_toss(comp); } @@ -683,6 +779,7 @@ int slhc_toss(struct slcompress *comp) { + DEBUGP(DSLHC, "slhc_toss(): Reset compression state...\n"); if ( comp == NULLSLCOMPR ) return 0; @@ -690,55 +787,27 @@ return 0; } -#else /* CONFIG_INET */ - -int -slhc_toss(struct slcompress *comp) +void slhc_i_status(struct slcompress *comp) { - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss"); - return -EINVAL; -} -int -slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress"); - return -EINVAL; -} -int -slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, - unsigned char *ocp, unsigned char **cpp, int compress_cid) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress"); - return -EINVAL; + if (comp != NULLSLCOMPR) { + DEBUGP(DSLHC, "slhc_i_status(): %d Cmp, %d Uncmp, %d Bad, %d Tossed\n", + comp->sls_i_compressed, + comp->sls_i_uncompressed, + comp->sls_i_error, + comp->sls_i_tossed); + } } -int -slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +void slhc_o_status(struct slcompress *comp) { - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember"); - return -EINVAL; + if (comp != NULLSLCOMPR) { + DEBUGP(DSLHC, "slhc_o_status(): %d Cmp, %d Uncmp, %d AsIs, %d NotTCP %d Searches, %d Misses\n", + comp->sls_o_compressed, + comp->sls_o_uncompressed, + comp->sls_o_tcp, + comp->sls_o_nontcp, + comp->sls_o_searches, + comp->sls_o_misses); + } } -void -slhc_free(struct slcompress *comp) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free"); -} -struct slcompress * -slhc_init(int rslots, int tslots) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init"); - return NULL; -} - -#endif /* CONFIG_INET */ - -/* VJ header compression */ -EXPORT_SYMBOL(slhc_init); -EXPORT_SYMBOL(slhc_free); -EXPORT_SYMBOL(slhc_remember); -EXPORT_SYMBOL(slhc_compress); -EXPORT_SYMBOL(slhc_uncompress); -EXPORT_SYMBOL(slhc_toss); - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index 1debb2d..d5aa356 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid slhc if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 45d1780..1804280 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -32,6 +32,9 @@ $(top_builddir)/src/gprs/oap_messages.o \ $(top_builddir)/src/gprs/gprs_llc_xid.o \ $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ + $(top_builddir)/src/gprs/slhc.o \ + $(top_builddir)/src/gprs/gprs_sndcp_comp.o \ + $(top_builddir)/src/gprs/gprs_sndcp_pcomp.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ diff --git a/openbsc/tests/slhc/Makefile.am b/openbsc/tests/slhc/Makefile.am new file mode 100644 index 0000000..d21990f --- /dev/null +++ b/openbsc/tests/slhc/Makefile.am @@ -0,0 +1,21 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) + +EXTRA_DIST = slhc_test.ok + +noinst_PROGRAMS = slhc_test + +slhc_test_SOURCES = slhc_test.c + +slhc_test_LDADD = \ + $(top_builddir)/src/gprs/slhc.o \ + $(top_builddir)/src/libcommon/libcommon.a \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOGB_LIBS) \ + $(LIBCARES_LIBS) \ + $(LIBCRYPTO_LIBS) \ + -lgtp -lrt -lm + + diff --git a/openbsc/tests/slhc/slhc_test.c b/openbsc/tests/slhc/slhc_test.c new file mode 100644 index 0000000..59a5425 --- /dev/null +++ b/openbsc/tests/slhc/slhc_test.c @@ -0,0 +1,298 @@ +/* Test SLHC/RFC1144 TCP/IP Header compression/decompression */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include +#include + +#include + +#include +#include +#include + +/* Number of compression slots (S0-1) */ +#define SLOTS 8 + +/* Maximum packet bytes to display */ +#define DISP_MAX_BYTES 100 + +/* Sample packets to test with */ +#define PACKETS_LEN 6 +char *packets[] = { + "4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27", + "4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0", + "4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01", + "4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01", + "4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a", + "4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20" +}; + +/* Compress a packet using Van Jacobson RFC1144 header compression */ +static int compress(uint8_t *data_o, uint8_t *data_i, int len, + struct slcompress *comp) +{ + uint8_t *comp_ptr; /* Not used */ + int compr_len; + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Run compressor */ + compr_len = slhc_compress(comp, data_i, len, data_o, &comp_ptr, 0); + return compr_len; +} + +/* Expand a packet using Van Jacobson RFC1144 header compression */ +static int expand(uint8_t *data_o, uint8_t *data_i, int len, + struct slcompress *comp) +{ + int data_decompressed_len; + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Handle an uncompressed packet (learn header information */ + if ((data_i[0] & SL_TYPE_UNCOMPRESSED_TCP) == SL_TYPE_UNCOMPRESSED_TCP) { + data_o[0] &= 0x4F; + data_decompressed_len = slhc_remember(comp, data_o, len); + return data_decompressed_len; + } + + /* Uncompress compressed packets */ + else if (data_o[0] & SL_TYPE_COMPRESSED_TCP) { + data_decompressed_len = slhc_uncompress(comp, data_o, len); + return data_decompressed_len; + } + + /* Regular or unknown packets will not be touched */ + return len; +} + +/* Calculate IP Header checksum */ +static uint16_t calc_ip_csum(uint8_t *data, int len) +{ + int i; + uint32_t accumulator = 0; + uint16_t *pointer = (uint16_t *) data; + + for (i = len; i > 1; i -= 2) { + accumulator += *pointer; + pointer++; + } + + if (len % 2) + accumulator += *pointer; + + accumulator = (accumulator & 0xffff) + ((accumulator >> 16) & 0xffff); + accumulator += (accumulator >> 16) & 0xffff; + return (~accumulator); +} + +/* Calculate TCP/IP checksum */ +static uint16_t calc_tcpip_csum(const void *ctx, uint8_t *packet, int len) +{ + uint8_t *buf; + uint16_t csum; + + buf = talloc_zero_size(ctx, len); + memset(buf, 0, len); + memcpy(buf, packet + 12, 8); + buf[9] = packet[9]; + buf[11] = (len - 20) & 0xFF; + buf[10] = (len - 20) >> 8 & 0xFF; + memcpy(buf + 12, packet + 20, len - 20); + csum = calc_ip_csum(buf, len - 20 + 12); + talloc_free(buf); + return csum; +} + +/* Check TCP/IP packet */ +static void check_packet(const void *ctx, uint8_t *packet, int len) +{ + /* Check IP header */ + OSMO_ASSERT(len > 20); + OSMO_ASSERT(calc_ip_csum(packet, 20) == 0); + + /* Check TCP packet */ + if (packet[9] != 0x06) + return; + OSMO_ASSERT(len > 40); + OSMO_ASSERT(calc_tcpip_csum(ctx, packet, len) == 0); +} + +/* Strip TCP options from TCP/IP packet */ +static int strip_tcp_options(const void *ctx, uint8_t *packet, int len) +{ + uint8_t doff; + uint16_t csum; + + /* Check if the packet can be handled here */ + if (len < 37) + return len; + if (packet[9] != 0x06) + return len; + + /* Strip TCP/IP options from packet */ + doff = ((packet[32] >> 4) & 0x0F) * 4; + memmove(packet + 40, packet + doff + 20, len - 40 - (doff - 20)); + len = len - (doff - 20); + + /* Repair data offset (TCP header length) */ + packet[32] &= 0x0F; + packet[32] |= 0x50; + + /* Repair checksum */ + packet[36] = 0; + packet[37] = 0; + csum = calc_tcpip_csum(ctx, packet, len); + packet[36] = csum & 0xFF; + packet[37] = csum >> 8 & 0xFF; + + /* Repair total length */ + packet[3] = len & 0xFF; + packet[2] = len >> 8 & 0xFF; + + /* Repair IP header checksum */ + packet[10] = 0; + packet[11] = 0; + csum = calc_ip_csum(packet, 20); + packet[10] = csum & 0xFF; + packet[11] = csum >> 8 & 0xFF; + printf("csum=%04x\n", csum); + + return len; +} + +/* Compress / Decompress packets */ +static void test_slhc(const void *ctx) +{ + char packet_ascii[2048]; + int i; + + struct slcompress *comp; + uint8_t packet[1024]; + int packet_len; + uint8_t packet_compr[1024]; + int packet_compr_len; + uint8_t packet_decompr[1024]; + int packet_decompr_len; + + printf("Allocating compression state...\n"); + comp = slhc_init(ctx, SLOTS, SLOTS); + OSMO_ASSERT(comp); + + for(i=0;i DISP_MAX_BYTES) + packet_compr_len = DISP_MAX_BYTES; + if (packet_len > DISP_MAX_BYTES) + packet_len = DISP_MAX_BYTES; + if (packet_decompr_len > DISP_MAX_BYTES) + packet_decompr_len = DISP_MAX_BYTES; + printf("Original Packet: (%i bytes) %s\n", packet_len, + osmo_hexdump_nospc(packet, packet_len)); + printf("DecompressedPacket: (%i bytes) %s\n", + packet_decompr_len, osmo_hexdump_nospc(packet_decompr, + packet_decompr_len)); + printf("CompressedPacket: (%i bytes) %s\n", packet_compr_len, + osmo_hexdump_nospc(packet_compr, packet_compr_len)); + slhc_o_status(comp); + slhc_o_status(comp); + + printf("\n"); + } + + printf("Freeing compression state...\n"); + slhc_free(comp); + printf("\n"); +} + +static struct log_info_cat gprs_categories[] = { + [DSNDCP] = { + .name = "DSNDCP", + .description = + "GPRS Sub-Network Dependent Control Protocol (SNDCP)", + .enabled = 1,.loglevel = LOGL_DEBUG, + }, + [DSLHC] = { + .name = "DSLHC", + .description = + "Van Jacobson RFC1144 TCP/IP header compression (SLHC)", + .enabled = 1,.loglevel = LOGL_DEBUG, + } +}; + +static struct log_info info = { + .cat = gprs_categories, + .num_cat = ARRAY_SIZE(gprs_categories), +}; + +int main(int argc, char **argv) +{ + void *ctx; + + osmo_init_logging(&info); + + ctx = talloc_named_const(NULL, 0, "slhc_ctx"); + + test_slhc(ctx); + + printf("Done\n"); + + talloc_report_full(ctx, stderr); + OSMO_ASSERT(talloc_total_blocks(ctx) == 1); + return 0; +} + +/* stubs */ +struct osmo_prim_hdr; +int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) +{ + abort(); +} diff --git a/openbsc/tests/slhc/slhc_test.ok b/openbsc/tests/slhc/slhc_test.ok new file mode 100644 index 0000000..636241d --- /dev/null +++ b/openbsc/tests/slhc/slhc_test.ok @@ -0,0 +1,52 @@ +Allocating compression state... +csum=b3a9 +Compressing... +Decompressing... +Results: +Original Packet: (52 bytes) 4510003446dd40004006a9b3c0a8646ec0a864640017ad8b81980100f3ac984d501800e371410000fffd18fffd20fffd23fffd27 +DecompressedPacket: (52 bytes) 4510003446dd40004006a9b3c0a8646ec0a864640017ad8b81980100f3ac984d501800e371410000fffd18fffd20fffd23fffd27 +CompressedPacket: (52 bytes) 7510003446dd40004000a9b3c0a8646ec0a864640017ad8b81980100f3ac984d501800e371410000fffd18fffd20fffd23fffd27 + +csum=97a9 +Compressing... +Decompressing... +Results: +Original Packet: (79 bytes) 4510004f46de40004006a997c0a8646ec0a864640017ad8b8198010cf3ac984d501800e3cda40000fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 +DecompressedPacket: (79 bytes) 4510004f46de40004006a997c0a8646ec0a864640017ad8b8198010cf3ac984d501800e3cda40000fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 +CompressedPacket: (43 bytes) df00cda4fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 + +csum=baa9 +Compressing... +Decompressing... +Results: +Original Packet: (43 bytes) 4510002b46df40004006a9bac0a8646ec0a864640017ad8b81980133f3ac989f501800e3a70a0000fffd01 +DecompressedPacket: (43 bytes) 4510002b46df40004006a9bac0a8646ec0a864640017ad8b81980133f3ac989f501800e3a70a0000fffd01 +CompressedPacket: (9 bytes) dc00a70a5227fffd01 + +csum=b9a9 +Compressing... +Decompressing... +Results: +Original Packet: (43 bytes) 4510002b46e040004006a9b9c0a8646ec0a864640017ad8b81980136f3ac98a2501800e3a7060000fffb01 +DecompressedPacket: (43 bytes) 4510002b46e040004006a9b9c0a8646ec0a864640017ad8b81980136f3ac98a2501800e3a7060000fffb01 +CompressedPacket: (7 bytes) db00a706fffb01 + +csum=7ba9 +Compressing... +Decompressing... +Results: +Original Packet: (100 bytes) 4510006846e140004006a97bc0a8646ec0a864640017ad8b81980139f3ac98a5501800e3c2d000000d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d +DecompressedPacket: (100 bytes) 4510006846e140004006a97bc0a8646ec0a864640017ad8b81980139f3ac98a5501800e3c2d000000d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d +CompressedPacket: (68 bytes) db00c2d00d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a + +csum=aca9 +Compressing... +Decompressing... +Results: +Original Packet: (54 bytes) 4510003646e240004006a9acc0a8646ec0a864640017ad8b81980179f3ac98a5501800e321fb0000706f6c6c7578206c6f67696e3a20 +DecompressedPacket: (54 bytes) 4510003646e240004006a9acc0a8646ec0a864640017ad8b81980179f3ac98a5501800e321fb0000706f6c6c7578206c6f67696e3a20 +CompressedPacket: (18 bytes) df0021fb706f6c6c7578206c6f67696e3a20 + +Freeing compression state... + +Done diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index 85a81d6..5f37b8e 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -136,3 +136,8 @@ AT_CHECK([$abs_top_builddir/tests/sndcp_xid/sndcp_xid_test], [], [expout], [ignore]) AT_CLEANUP +AT_SETUP([slhc]) +AT_KEYWORDS([slhc]) +cat $abs_srcdir/slhc/slhc_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/slhc/slhc_test], [], [expout], [ignore]) +AT_CLEANUP -- To view, visit https://gerrit.osmocom.org/635 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 Gerrit-PatchSet: 14 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Fri Aug 26 10:34:35 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Fri, 26 Aug 2016 10:34:35 +0000 Subject: [PATCH] openbsc[master]: Adding LLC-XID related modifications in LLC In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/652 to look at the new patch set (#14). Adding LLC-XID related modifications in LLC With this commit the already existing XID mechanism has been modified to suit the needs for the upcomming SNDCP-XID patches. This commit should not break anything since it does not alter the current behaviour (incoming XID is still just echoed, on GMM-Reset a basic XID message is still echoed) Change-Id: I65b9d625e72d3d61c99abdc7041773701d694d52 --- M openbsc/include/openbsc/gprs_llc.h M openbsc/src/gprs/gprs_llc.c M openbsc/tests/sgsn/Makefile.am 3 files changed, 315 insertions(+), 57 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/52/652/14 diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h index 0e497a0..c3b82b1 100644 --- a/openbsc/include/openbsc/gprs_llc.h +++ b/openbsc/include/openbsc/gprs_llc.h @@ -4,6 +4,7 @@ #include #include #include +#include /* Section 4.7 LLC Layer Structure */ enum gprs_llc_sapi { @@ -166,6 +167,13 @@ uint16_t nsei; struct gprs_llc_lle lle[NUM_SAPIS]; + /* Copy of the XID fields we have sent with the last + * network originated XID-Request. Since the phone + * may strip the optional fields in the confirmation + * we need to remeber those fields in order to be + * able to create the compression entity. */ + struct llist_head *xid; + /* Internal management */ uint32_t age_timestamp; }; @@ -219,6 +227,10 @@ int gprs_llgmm_reset_oldmsg(struct msgb* oldmsg, uint8_t sapi, struct gprs_llc_llme *llme); +/* Set of LL-XID negotiation (See also: TS 101 351, Section 7.2.2.4) */ +int gprs_ll_xid_req(struct gprs_llc_lle *lle, + struct gprs_llc_xid_field *l3_xid_field); + /* 04.64 Chapter 7.2.1.1 LLGMM-ASSIGN */ int gprs_llgmm_assign(struct gprs_llc_llme *llme, uint32_t old_tlli, uint32_t new_tlli); diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c index 7724ebb..d6c8866 100644 --- a/openbsc/src/gprs/gprs_llc.c +++ b/openbsc/src/gprs/gprs_llc.c @@ -38,8 +38,286 @@ #include #include #include +#include +#include static struct gprs_llc_llme *llme_alloc(uint32_t tlli); +static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg, + int command); +static int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi, + int command, enum gprs_llc_u_cmd u_cmd, int pf_bit); + +/* BEGIN XID RELATED */ + +/* Generate XID message */ +static int gprs_llc_generate_xid(uint8_t *bytes, int bytes_len, + struct gprs_llc_xid_field *l3_xid_field, + struct gprs_llc_llme *llme) +{ + /* Note: Called by gprs_ll_xid_req() */ + + LLIST_HEAD(xid_fields); + + struct gprs_llc_xid_field xid_version; + struct gprs_llc_xid_field xid_n201u; + struct gprs_llc_xid_field xid_n201i; + + xid_version.type = GPRS_LLC_XID_T_VERSION; + xid_version.data = (uint8_t *) "\x00"; + xid_version.data_len = 1; + + xid_n201u.type = GPRS_LLC_XID_T_N201_U; + xid_n201u.data = (uint8_t *) "\x05\xf0"; + xid_n201u.data_len = 2; + + xid_n201i.type = GPRS_LLC_XID_T_N201_I; + xid_n201i.data = (uint8_t *) "\x05\xf0"; + xid_n201i.data_len = 2; + + /* Add locally managed XID Fields */ + llist_add(&xid_n201i.list, &xid_fields); + llist_add(&xid_n201u.list, &xid_fields); + llist_add(&xid_version.list, &xid_fields); + + /* Append layer 3 XID field (if present) */ + if (l3_xid_field) { + /* Enforce layer 3 XID type (just to be sure) */ + l3_xid_field->type = GPRS_LLC_XID_T_L3_PAR; + + /* Add Layer 3 XID field to the list */ + llist_add(&l3_xid_field->list, &xid_fields); + } + + /* Store generated XID for later reference */ + talloc_free(llme->xid); + llme->xid = gprs_llc_copy_xid(llme, &xid_fields); + + return gprs_llc_compile_xid(bytes, bytes_len, &xid_fields); +} + +/* Generate XID message that will cause the GMM to reset */ +static int gprs_llc_generate_xid_for_gmm_reset(uint8_t *bytes, + int bytes_len, uint32_t iov_ui, + struct gprs_llc_llme *llme) +{ + /* Called by gprs_llgmm_reset() and + * gprs_llgmm_reset_oldmsg() */ + + LLIST_HEAD(xid_fields); + + struct gprs_llc_xid_field xid_reset; + struct gprs_llc_xid_field xid_iovui; + + /* First XID component must be RESET */ + xid_reset.type = GPRS_LLC_XID_T_RESET; + xid_reset.data = NULL; + xid_reset.data_len = 0; + + /* Add new IOV-UI */ + xid_iovui.type = GPRS_LLC_XID_T_IOV_UI; + xid_iovui.data = (uint8_t *) & iov_ui; + xid_iovui.data_len = 4; + + /* Add locally managed XID Fields */ + llist_add(&xid_iovui.list, &xid_fields); + llist_add(&xid_reset.list, &xid_fields); + + /* Store generated XID for later reference */ + talloc_free(llme->xid); + llme->xid = gprs_llc_copy_xid(llme, &xid_fields); + + return gprs_llc_compile_xid(bytes, bytes_len, &xid_fields); +} + +/* Process an incoming XID confirmation */ +static int gprs_llc_process_xid_conf(uint8_t *bytes, int bytes_len, + struct gprs_llc_lle *lle) +{ + /* Note: This function handles the response of a network originated + * XID-Request. There XID messages reflected by the phone are analyzed + * and processed here. The caller is called by rx_llc_xid(). */ + + struct llist_head *xid_fields; + struct gprs_llc_xid_field *xid_field; + + /* Parse and analyze XID-Response */ + xid_fields = gprs_llc_parse_xid(NULL, bytes, bytes_len); + + if (xid_fields) { + + gprs_llc_dump_xid_fields(xid_fields, LOGL_DEBUG); + llist_for_each_entry(xid_field, xid_fields, list) { + + /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { + LOGP(DLLC, LOGL_NOTICE, + "Ignoring SNDCP-XID-Field: XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + osmo_hexdump_nospc(xid_field->data, + xid_field->data_len)); + } + + /* Process LLC-XID fields: */ + else { + + /* FIXME: Do something more useful with the + * echoed XID-Information. Currently we + * just ignore the response completely and + * by doing so we blindly accept any changes + * the MS might have done to the our XID + * inquiry. There is a remainig risk of + * malfunction! */ + LOGP(DLLC, LOGL_NOTICE, + "Ignoring XID-Field: XID: type=%d, data_len=%d, data=%s\n", + xid_field->type, xid_field->data_len, + osmo_hexdump_nospc(xid_field->data, + xid_field->data_len)); + } + } + talloc_free(xid_fields); + } + + /* Flush pending XID fields */ + talloc_free(lle->llme->xid); + lle->llme->xid = NULL; + + return 0; +} + +/* Process an incoming XID indication and generate an appropiate response */ +static int gprs_llc_process_xid_ind(uint8_t *bytes_request, + int bytes_request_len, + uint8_t *bytes_response, + int bytes_response_maxlen, + struct gprs_llc_lle *lle) +{ + /* Note: This function computes the response that is sent back to the + * phone when a phone originated XID is received. The function is + * called by rx_llc_xid() */ + + int rc = -EINVAL; + + struct llist_head *xid_fields; + struct llist_head *xid_fields_response; + + struct gprs_llc_xid_field *xid_field; + struct gprs_llc_xid_field *xid_field_response; + + /* Flush eventually pending XID fields */ + talloc_free(lle->llme->xid); + lle->llme->xid = NULL; + + /* Parse and analyze XID-Request */ + xid_fields = + gprs_llc_parse_xid(lle->llme, bytes_request, bytes_request_len); + if (xid_fields) { + xid_fields_response = talloc_zero(lle->llme, struct llist_head); + INIT_LLIST_HEAD(xid_fields_response); + gprs_llc_dump_xid_fields(xid_fields, LOGL_DEBUG); + + /* Process LLC-XID fields: */ + llist_for_each_entry(xid_field, xid_fields, list) { + + if (xid_field->type != GPRS_LLC_XID_T_L3_PAR) { + /* FIXME: Check the incoming XID parameters for + * for validity. Currently we just blindly + * accept all XID fields by just echoing them. + * There is a remaining risk of malfunction + * when a phone submits values which defer from + * the default! */ + LOGP(DLLC, LOGL_NOTICE, + "Echoing XID-Field: XID: type=%d, data_len=%d, data=%s\n", + xid_field->type, xid_field->data_len, + osmo_hexdump_nospc(xid_field->data, + xid_field->data_len)); + xid_field_response = + gprs_llc_dup_xid_field + (lle->llme, xid_field); + llist_add(&xid_field_response->list, + xid_fields_response); + } + } + + rc = gprs_llc_compile_xid(bytes_response, + bytes_response_maxlen, + xid_fields_response); + talloc_free(xid_fields_response); + talloc_free(xid_fields); + } + + return rc; +} + +/* Dispatch XID indications and responses comming from the Phone */ +static void rx_llc_xid(struct gprs_llc_lle *lle, + struct gprs_llc_hdr_parsed *gph) +{ + uint8_t response[1024]; + int response_len; + + /* FIXME: 8.5.3.3: check if XID is invalid */ + if (gph->is_cmd) { + LOGP(DLLC, LOGL_NOTICE, + "Received XID indication from phone.\n"); + + struct msgb *resp; + uint8_t *xid; + resp = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + + response_len = + gprs_llc_process_xid_ind(gph->data, gph->data_len, + response, sizeof(response), + lle); + xid = msgb_put(resp, response_len); + memcpy(xid, response, response_len); + + gprs_llc_tx_xid(lle, resp, 0); + } else { + LOGP(DLLC, LOGL_NOTICE, + "Received XID confirmation from phone.\n"); + gprs_llc_process_xid_conf(gph->data, gph->data_len, lle); + /* FIXME: if we had sent a XID reset, send + * LLGMM-RESET.conf to GMM */ + } +} + + +/* Set of LL-XID negotiation (See also: TS 101 351, Section 7.2.2.4) */ +int gprs_ll_xid_req(struct gprs_llc_lle *lle, + struct gprs_llc_xid_field *l3_xid_field) +{ + /* Note: This functions is calle from gprs_sndcp.c */ + + uint8_t xid_bytes[1024];; + int xid_bytes_len; + uint8_t *xid; + struct msgb *msg; + + /* Generate XID */ + xid_bytes_len = + gprs_llc_generate_xid(xid_bytes, sizeof(xid_bytes), + l3_xid_field, lle->llme); + + /* Only perform XID sending if the XID message contains something */ + if (xid_bytes_len > 0) { + /* Transmit XID bytes */ + msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); + LOGP(DLLC, LOGL_NOTICE, "Sending XID request to phone...\n"); + gprs_llc_tx_xid(lle, msg, 1); + } else { + LOGP(DLLC, LOGL_ERROR, + "XID-Message generation failed, XID not sent!\n"); + return -EINVAL; + } + + return 0; +} +/* END XID RELATED */ + + + /* Entry function from upper level (LLC), asking us to transmit a BSSGP PDU * to a remote MS (identified by TLLI) at a BTS identified by its BVCI and NSEI */ @@ -51,7 +329,7 @@ memset(&dup, 0, sizeof(dup)); /* before we have received some identity from the MS, we might * not yet have a MMC context (e.g. XID negotiation of primarly - * LLC connection fro GMM sapi). */ + * LLC connection from GMM sapi). */ if (mmctx) { dup.imsi = mmctx->imsi; dup.drx_parms = mmctx->drx_parms; @@ -251,6 +529,7 @@ static void llme_free(struct gprs_llc_llme *llme) { + talloc_free(llme->xid); llist_del(&llme->list); talloc_free(llme); } @@ -464,54 +743,6 @@ /* Send BSSGP-DL-UNITDATA.req */ return _bssgp_tx_dl_ud(msg, mmctx); -} - -/* According to 6.4.1.6 / Figure 11 */ -static int msgb_put_xid_par(struct msgb *msg, uint8_t type, uint8_t length, uint8_t *data) -{ - uint8_t header_len = 1; - uint8_t *cur; - - /* type is a 5-bit field... */ - if (type > 0x1f) - return -EINVAL; - - if (length > 3) - header_len = 2; - - cur = msgb_put(msg, length + header_len); - - /* build the header without or with XL bit */ - if (length <= 3) { - *cur++ = (type << 2) | (length & 3); - } else { - *cur++ = 0x80 | (type << 2) | (length >> 6); - *cur++ = (length << 2); - } - - /* copy over the payload of the parameter*/ - memcpy(cur, data, length); - - return length + header_len; -} - -static void rx_llc_xid(struct gprs_llc_lle *lle, - struct gprs_llc_hdr_parsed *gph) -{ - /* FIXME: 8.5.3.3: check if XID is invalid */ - if (gph->is_cmd) { - /* FIXME: implement XID negotiation using SNDCP */ - struct msgb *resp; - uint8_t *xid; - resp = msgb_alloc_headroom(4096, 1024, "LLC_XID"); - xid = msgb_put(resp, gph->data_len); - memcpy(xid, gph->data, gph->data_len); - gprs_llc_tx_xid(lle, resp, 0); - } else { - /* FIXME: if we had sent a XID reset, send - * LLGMM-RESET.conf to GMM */ - /* FIXME: implement XID negotiation using SNDCP */ - } } static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph, @@ -784,17 +1015,24 @@ { struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); struct gprs_llc_lle *lle = &llme->lle[1]; + uint8_t xid_bytes[1024]; + int xid_bytes_len; + uint8_t *xid; + LOGP(DLLC, LOGL_NOTICE, "LLGM Reset\n"); if (RAND_bytes((uint8_t *) &llme->iov_ui, 4) != 1) { LOGP(DLLC, LOGL_NOTICE, "RAND_bytes failed for LLC XID reset, " "falling back to rand()\n"); llme->iov_ui = rand(); } - /* First XID component must be RESET */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL); - /* randomly select new IOV-UI */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &llme->iov_ui); + /* Generate XID message */ + xid_bytes_len = gprs_llc_generate_xid_for_gmm_reset(xid_bytes, + sizeof(xid_bytes),llme->iov_ui,llme); + if(xid_bytes_len < 0) + return -EINVAL; + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); /* Reset some of the LLC parameters. See GSM 04.64, 8.5.3.1 */ lle->vu_recv = 0; @@ -810,17 +1048,24 @@ struct gprs_llc_llme *llme) { struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + uint8_t xid_bytes[1024]; + int xid_bytes_len; + uint8_t *xid; + LOGP(DLLC, LOGL_NOTICE, "LLGM Reset\n"); if (RAND_bytes((uint8_t *) &llme->iov_ui, 4) != 1) { LOGP(DLLC, LOGL_NOTICE, "RAND_bytes failed for LLC XID reset, " "falling back to rand()\n"); llme->iov_ui = rand(); } - /* First XID component must be RESET */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL); - /* randomly select new IOV-UI */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &llme->iov_ui); + /* Generate XID message */ + xid_bytes_len = gprs_llc_generate_xid_for_gmm_reset(xid_bytes, + sizeof(xid_bytes),llme->iov_ui,llme); + if(xid_bytes_len < 0) + return -EINVAL; + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); /* FIXME: Start T200, wait for XID response */ diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index b6036c7..74af159 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -30,6 +30,7 @@ $(top_builddir)/src/gprs/gprs_gb_parse.o \ $(top_builddir)/src/gprs/oap.o \ $(top_builddir)/src/gprs/oap_messages.o \ + $(top_builddir)/src/gprs/gprs_llc_xid.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ -- To view, visit https://gerrit.osmocom.org/652 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I65b9d625e72d3d61c99abdc7041773701d694d52 Gerrit-PatchSet: 14 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Fri Aug 26 10:34:35 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Fri, 26 Aug 2016 10:34:35 +0000 Subject: [PATCH] openbsc[master]: Adding LLC-XID encoder / decoder and unit test In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/638 to look at the new patch set (#10). Adding LLC-XID encoder / decoder and unit test The lle-xid encoder/decoder is needed to encode and decode llc xid parameter messages. We need this to exchange sndcp-parameters (SNDCP-XID) and also simple parameters such as encryption IOVs Change-Id: Ia06e4cb08bf9b48c2a4682606d1b1a91d19a9d37 --- M openbsc/.gitignore M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_llc_xid.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_llc_xid.c M openbsc/tests/Makefile.am M openbsc/tests/testsuite.at A openbsc/tests/xid/Makefile.am A openbsc/tests/xid/xid_test.c A openbsc/tests/xid/xid_test.ok 11 files changed, 526 insertions(+), 3 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/38/638/10 diff --git a/openbsc/.gitignore b/openbsc/.gitignore index 0a2965d..518a960 100644 --- a/openbsc/.gitignore +++ b/openbsc/.gitignore @@ -81,6 +81,7 @@ tests/oap/oap_test tests/gtphub/gtphub_test tests/mm_auth/mm_auth_test +tests/xid/xid_test tests/atconfig tests/atlocal diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 0980413..fbf2930 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -229,6 +229,7 @@ tests/oap/Makefile tests/gtphub/Makefile tests/mm_auth/Makefile + tests/xid/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index c272b14..11f650d 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,7 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h + gtphub.h gprs_llc_xid.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_llc_xid.h b/openbsc/include/openbsc/gprs_llc_xid.h new file mode 100644 index 0000000..d340d40 --- /dev/null +++ b/openbsc/include/openbsc/gprs_llc_xid.h @@ -0,0 +1,57 @@ +/* GPRS LLC XID field encoding/decoding as per 3GPP TS 44.064 */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include + +/* 3GPP TS 44.064 6.4.1.6 Exchange Identification (XID) + command/response parameter field */ +struct gprs_llc_xid_field { + struct llist_head list; + uint8_t type; /* See also Table 6: LLC layer parameter + negotiation */ + uint8_t *data; /* Payload data (memory is owned by the + * creator of the struct) */ + unsigned int data_len; /* Payload length */ +}; + +/* Transform a list with XID fields into a XID message (dst) */ +int gprs_llc_compile_xid(uint8_t *dst, int dst_maxlen, + const struct llist_head *xid_fields); + +/* Transform a XID message (dst) into a list of XID fields */ +struct llist_head *gprs_llc_parse_xid(const void *ctx, const uint8_t *src, + int src_len); + +/* Create a duplicate of an XID-Field */ +struct gprs_llc_xid_field *gprs_llc_dup_xid_field(const void *ctx, + const struct gprs_llc_xid_field *xid_field); + +/* Copy an llist with xid fields */ +struct llist_head *gprs_llc_copy_xid(const void *ctx, + const struct llist_head *xid_fields); + +/* Dump a list with XID fields (Debug) */ +void gprs_llc_dump_xid_fields(const struct llist_head *xid_fields, + unsigned int logl); + diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 6dc7e16..8cbdd91 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -28,7 +28,7 @@ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ - oap.c oap_messages.c + oap.c oap_messages.c gprs_llc_xid.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/gprs_llc_xid.c b/openbsc/src/gprs/gprs_llc_xid.c new file mode 100644 index 0000000..4b1685e --- /dev/null +++ b/openbsc/src/gprs/gprs_llc_xid.c @@ -0,0 +1,262 @@ +/* GPRS LLC XID field encoding/decoding as per 3GPP TS 44.064 */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Parse XID parameter field */ +static int decode_xid_field(struct gprs_llc_xid_field *xid_field, + const uint8_t *src, uint8_t src_len) +{ + uint8_t xl; + uint8_t type; + uint8_t len; + int src_counter = 0; + + /* Exit immediately if it is clear that no + * parseable data is present */ + if (src_len < 1 || !src) + return -EINVAL; + + /* Extract header info */ + xl = (*src >> 7) & 1; + type = (*src >> 2) & 0x1F; + + /* Extract length field */ + len = (*src) & 0x3; + src++; + src_counter++; + if (xl) { + if (src_len < 2) + return -EINVAL; + len = (len << 6) & 0xC0; + len |= ((*src) >> 2) & 0x3F; + src++; + src_counter++; + } + + /* Fill out struct */ + xid_field->type = type; + xid_field->data_len = len; + if (len > 0) { + if (src_len < src_counter + len) + return -EINVAL; + xid_field->data = + talloc_memdup(xid_field,src,xid_field->data_len); + } else + xid_field->data = NULL; + + /* Return consumed length */ + return src_counter + len; +} + +/* Encode XID parameter field */ +static int encode_xid_field(uint8_t *dst, int dst_maxlen, + const struct gprs_llc_xid_field *xid_field) +{ + int xl = 0; + + /* When the length does not fit into 2 bits, + * we need extended length fields */ + if (xid_field->data_len > 3) + xl = 1; + + /* Exit immediately if it is clear that no + * encoding result can be stored */ + if (dst_maxlen < xid_field->data_len + 1 + xl) + return -EINVAL; + + /* There are only 5 bits reserved for the type, exit on exceed */ + if (xid_field->type > 31) + return -EINVAL; + + /* Encode header */ + memset(dst, 0, dst_maxlen); + if (xl) + dst[0] |= 0x80; + dst[0] |= (((xid_field->type) & 0x1F) << 2); + + if (xl) { + dst[0] |= (((xid_field->data_len) >> 6) & 0x03); + dst[1] = ((xid_field->data_len) << 2) & 0xFC; + } else + dst[0] |= ((xid_field->data_len) & 0x03); + + /* Append payload data */ + if (xid_field->data && xid_field->data_len) + memcpy(dst + 1 + xl, xid_field->data, xid_field->data_len); + + /* Return generated length */ + return xid_field->data_len + 1 + xl; +} + +/* Transform a list with XID fields into a XID message (dst) */ +int gprs_llc_compile_xid(uint8_t *dst, int dst_maxlen, + const struct llist_head *xid_fields) +{ + struct gprs_llc_xid_field *xid_field; + int rc; + int byte_counter = 0; + + OSMO_ASSERT(xid_fields); + OSMO_ASSERT(dst); + + llist_for_each_entry_reverse(xid_field, xid_fields, list) { + /* Encode XID-Field */ + rc = encode_xid_field(dst, dst_maxlen, xid_field); + if (rc < 0) + return -EINVAL; + + /* Advance pointer and lower maxlen for the + * next encoding round */ + dst += rc; + byte_counter += rc; + dst_maxlen -= rc; + } + + /* Return generated length */ + return byte_counter; +} + +/* Transform a XID message (dst) into a list of XID fields */ +struct llist_head *gprs_llc_parse_xid(const void *ctx, const uint8_t *src, + int src_len) +{ + struct gprs_llc_xid_field *xid_field; + struct llist_head *xid_fields; + + int rc; + int max_loops = src_len; + + OSMO_ASSERT(src); + + xid_fields = talloc_zero(ctx, struct llist_head); + INIT_LLIST_HEAD(xid_fields); + + while (1) { + /* Bail in case decode_xid_field() constantly returns zero */ + if (max_loops <= 0) { + talloc_free(xid_fields); + return NULL; + } + + /* Decode XID field */ + xid_field = talloc_zero(xid_fields, struct gprs_llc_xid_field); + rc = decode_xid_field(xid_field, src, src_len); + + /* Immediately stop on error */ + if (rc < 0) { + talloc_free(xid_fields); + return NULL; + } + + /* Add parsed XID field to list */ + llist_add(&xid_field->list, xid_fields); + + /* Advance pointer and lower dst_len for the next + * decoding round */ + src += rc; + src_len -= rc; + + /* We are (scuccessfully) done when no further byes are left */ + if (src_len == 0) + return xid_fields; + + max_loops--; + } +} + +/* Create a duplicate of an XID-Field */ +struct gprs_llc_xid_field *gprs_llc_dup_xid_field(const void *ctx, const struct + gprs_llc_xid_field + *xid_field) +{ + struct gprs_llc_xid_field *dup; + + OSMO_ASSERT(xid_field); + + /* Create a copy of the XID field in memory */ + dup = talloc_memdup(ctx, xid_field, sizeof(*xid_field)); + dup->data = talloc_memdup(ctx, xid_field->data, xid_field->data_len); + + /* Unlink duplicate from source list */ + INIT_LLIST_HEAD(&dup->list); + + return dup; +} + +/* Copy an llist with xid fields */ +struct llist_head *gprs_llc_copy_xid(const void *ctx, + const struct llist_head *xid_fields) +{ + struct gprs_llc_xid_field *xid_field; + struct llist_head *xid_fields_copy; + + OSMO_ASSERT(xid_fields); + + xid_fields_copy = talloc_zero(ctx, struct llist_head); + INIT_LLIST_HEAD(xid_fields_copy); + + /* Create duplicates and add them to the target list */ + llist_for_each_entry(xid_field, xid_fields, list) { + llist_add(&gprs_llc_dup_xid_field(ctx, xid_field)->list, + xid_fields_copy); + } + + return xid_fields_copy; +} + +/* Dump a list with XID fields (Debug) */ +void gprs_llc_dump_xid_fields(const struct llist_head *xid_fields, + unsigned int logl) +{ + struct gprs_llc_xid_field *xid_field; + + OSMO_ASSERT(xid_fields); + + llist_for_each_entry(xid_field, xid_fields, list) { + if (xid_field->data_len) { + OSMO_ASSERT(xid_field->data); + LOGP(DLLC, logl, + "XID: type=%d, data_len=%d, data=%s\n", + xid_field->type, xid_field->data_len, + osmo_hexdump_nospc(xid_field->data, + xid_field->data_len)); + } else { + LOGP(DLLC, logl, + "XID: type=%d, data_len=%d, data=NULL\n", + xid_field->type, xid_field->data_len); + } + } +} diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index 09298a3..ba5ca28 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index dab9568..6470ab9 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -124,3 +124,8 @@ AT_CHECK([$abs_top_builddir/tests/mm_auth/mm_auth_test], [], [expout], [ignore]) AT_CLEANUP +AT_SETUP([xid]) +AT_KEYWORDS([xid]) +cat $abs_srcdir/xid/xid_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/xid/xid_test], [], [expout], [ignore]) +AT_CLEANUP diff --git a/openbsc/tests/xid/Makefile.am b/openbsc/tests/xid/Makefile.am new file mode 100644 index 0000000..9b64965 --- /dev/null +++ b/openbsc/tests/xid/Makefile.am @@ -0,0 +1,21 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) + +EXTRA_DIST = xid_test.ok + +noinst_PROGRAMS = xid_test + +xid_test_SOURCES = xid_test.c + +xid_test_LDADD = \ + $(top_builddir)/src/gprs/gprs_llc_xid.o \ + $(top_builddir)/src/libcommon/libcommon.a \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOGB_LIBS) \ + $(LIBCARES_LIBS) \ + $(LIBCRYPTO_LIBS) \ + -lgtp -lrt -lm + + diff --git a/openbsc/tests/xid/xid_test.c b/openbsc/tests/xid/xid_test.c new file mode 100644 index 0000000..b77a4ae --- /dev/null +++ b/openbsc/tests/xid/xid_test.c @@ -0,0 +1,164 @@ +/* Test LLC-XID Encoding/Decoding */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include +#include + +#include + +#include +#include + +/* Test XID encoding */ +static void test_xid_encode(const void *ctx) +{ + struct gprs_llc_xid_field xid_field_1; + struct gprs_llc_xid_field xid_field_2; + struct gprs_llc_xid_field xid_field_3; + struct gprs_llc_xid_field xid_field_4; + LLIST_HEAD(xid_fields); + uint8_t xid[255]; + uint8_t xid_expected[] = + { 0x10, 0x8c, 0x14, 0x43, 0x43, 0x43, 0x43, 0x43, 0x0b, 0x42, 0x42, + 0x42, 0x05, 0x41 }; + int rc; + + printf("Testing LLC XID-Encoder\n"); + + /* Setup some simple XID data */ + xid_field_1.type = 1; + xid_field_2.type = 2; + xid_field_3.type = 3; + xid_field_4.type = 4; + + xid_field_1.data = (uint8_t *) "A"; + xid_field_2.data = (uint8_t *) "BBB"; + xid_field_3.data = (uint8_t *) "CCCCC"; + xid_field_4.data = NULL; + + xid_field_1.data_len = 1; + xid_field_2.data_len = 3; + xid_field_3.data_len = 5; + xid_field_4.data_len = 0; + + llist_add(&xid_field_4.list, &xid_fields); + llist_add(&xid_field_3.list, &xid_fields); + llist_add(&xid_field_2.list, &xid_fields); + llist_add(&xid_field_1.list, &xid_fields); + + printf("Data to encode:\n"); + gprs_llc_dump_xid_fields(&xid_fields, DSNDCP); + + /* Encode data */ + rc = gprs_llc_compile_xid(xid, sizeof(xid), &xid_fields); + OSMO_ASSERT(rc == 14); + printf("Encoded: %s (%i bytes)\n", osmo_hexdump_nospc(xid, rc), rc); + printf("Expected: %s (%i bytes)\n", + osmo_hexdump_nospc(xid_expected, sizeof(xid_expected)), + (int)sizeof(xid_expected)); + + OSMO_ASSERT(memcmp(xid_expected, xid, sizeof(xid_expected)) == 0); + + printf("\n"); +} + +/* Test XID decoding */ +static void test_xid_decode(const void *ctx) +{ + struct llist_head *xid_fields; + int rc; + + printf("Testing LLC XID-Decoder/Encoder\n"); + + /* Example of a real world LLC-XID message */ + uint8_t xid[] = + { 0x01, 0x00, 0x16, 0x05, 0xf0, 0x1a, 0x05, 0xf0, 0xac, 0xd8, 0x00, + 0x01, 0x00, 0x02, 0x31, 0x82, 0x02, 0x27, 0x89, 0xff, 0xe0, 0x00, 0x0f, + 0x00, 0xa8, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x01, 0x02, + 0x00, 0x03, 0x01, 0x03, 0x00, 0x04, 0x01, 0x04, 0x00, 0x05, 0x01, 0x05, + 0x00, 0x06, 0x00, 0x07, 0x01, 0x07, 0x00, 0x08, 0x01, 0x08, 0x80, 0x00, + 0x04, 0x12, 0x00, 0x40, 0x07 }; + + uint8_t xid_r[512]; + + /* Decode and display XID fields */ + xid_fields = gprs_llc_parse_xid(ctx, xid, sizeof(xid)); + OSMO_ASSERT(xid_fields); + + printf("Decoded:\n"); + gprs_llc_dump_xid_fields(xid_fields, DSNDCP); + + + /* Encode xid-fields again */ + rc = gprs_llc_compile_xid(xid_r, sizeof(xid_r), xid_fields); + printf("Result length=%i\n",rc); + printf("Encoded: %s\n", osmo_hexdump_nospc(xid, sizeof(xid))); + printf("Rencoded: %s\n", osmo_hexdump_nospc(xid_r, rc)); + + OSMO_ASSERT(rc == 64); + OSMO_ASSERT(memcmp(xid, xid_r, sizeof(xid)) == 0); + + /* Free xid fields */ + talloc_free(xid_fields); + + printf("\n"); +} + +static struct log_info_cat gprs_categories[] = { + [DSNDCP] = { + .name = "DSNDCP", + .description = + "GPRS Sub-Network Dependent Control Protocol (SNDCP)", + .enabled = 1,.loglevel = LOGL_DEBUG, + } +}; + +static struct log_info info = { + .cat = gprs_categories, + .num_cat = ARRAY_SIZE(gprs_categories), +}; + +int main(int argc, char **argv) +{ + void *xid_ctx; + + osmo_init_logging(&info); + + xid_ctx = talloc_named_const(NULL, 0, "xid_ctx"); + + test_xid_decode(xid_ctx); + test_xid_encode(xid_ctx); + printf("Done\n"); + + talloc_report_full(xid_ctx, stderr); + OSMO_ASSERT(talloc_total_blocks(xid_ctx) == 1); + return 0; +} + +/* stubs */ +struct osmo_prim_hdr; +int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) +{ + abort(); +} diff --git a/openbsc/tests/xid/xid_test.ok b/openbsc/tests/xid/xid_test.ok new file mode 100644 index 0000000..4cf825c --- /dev/null +++ b/openbsc/tests/xid/xid_test.ok @@ -0,0 +1,12 @@ +Testing LLC XID-Decoder/Encoder +Decoded: +Result length=64 +Encoded: 01001605f01a05f0acd8000100023182022789ffe0000f00a8000000010101000201020003010300040104000501050006000701070008010880000412004007 +Rencoded: 01001605f01a05f0acd8000100023182022789ffe0000f00a8000000010101000201020003010300040104000501050006000701070008010880000412004007 + +Testing LLC XID-Encoder +Data to encode: +Encoded: 108c1443434343430b4242420541 (14 bytes) +Expected: 108c1443434343430b4242420541 (14 bytes) + +Done -- To view, visit https://gerrit.osmocom.org/638 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia06e4cb08bf9b48c2a4682606d1b1a91d19a9d37 Gerrit-PatchSet: 10 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Fri Aug 26 12:46:07 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Fri, 26 Aug 2016 12:46:07 +0000 Subject: [PATCH] osmo-pcu[master]: TBF flow: Coverity fix Message-ID: Review at https://gerrit.osmocom.org/769 TBF flow: Coverity fix Related: CID#1361925, CID:#1361924 Change-Id: Ib1f71a8940eed7ad74211092275dfa29aa353fc7 --- M src/tbf_dl.cpp 1 file changed, 3 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/69/769/1 diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp index a24cc21..4c67a12 100644 --- a/src/tbf_dl.cpp +++ b/src/tbf_dl.cpp @@ -691,6 +691,9 @@ msg_data = msgb_put(dl_msg, msg_len); + OSMO_ASSERT(rlc.num_data_blocks <= ARRAY_SIZE(rlc.block_info)); + OSMO_ASSERT(rlc.num_data_blocks > 0); + /* Copy block(s) to RLC message */ for (data_block_idx = 0; data_block_idx < rlc.num_data_blocks; data_block_idx++) -- To view, visit https://gerrit.osmocom.org/769 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ib1f71a8940eed7ad74211092275dfa29aa353fc7 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Fri Aug 26 13:34:56 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Fri, 26 Aug 2016 13:34:56 +0000 Subject: osmo-pcu[master]: Handle EGPRS 11 bit RACH in osmo-pcu In-Reply-To: References: Message-ID: Patch Set 4: Code-Review+1 -- To view, visit https://gerrit.osmocom.org/430 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I61d74a32f7764644ed86f7fdf97fa3c2f61503f7 Gerrit-PatchSet: 4 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: arvind.sirsikar Gerrit-Reviewer: bhargava_abhyankar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Fri Aug 26 13:36:53 2016 From: gerrit-no-reply at lists.osmocom.org (bhargava_abhyankar) Date: Fri, 26 Aug 2016 13:36:53 +0000 Subject: osmo-pcu[master]: Update the function immediate assignment for EGPRS In-Reply-To: References: Message-ID: Patch Set 5: I have addressed all the comments. Would like to know the status of the patch. -- To view, visit https://gerrit.osmocom.org/431 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ie5e309156e5dbbb6add74a1b4d257c4ee2332e52 Gerrit-PatchSet: 5 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: bhargava_abhyankar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Fri Aug 26 13:37:07 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Fri, 26 Aug 2016 13:37:07 +0000 Subject: osmo-pcu[master]: Update the function immediate assignment for EGPRS In-Reply-To: References: Message-ID: Patch Set 5: Code-Review+1 -- To view, visit https://gerrit.osmocom.org/431 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ie5e309156e5dbbb6add74a1b4d257c4ee2332e52 Gerrit-PatchSet: 5 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-Reviewer: bhargava_abhyankar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Fri Aug 26 13:37:37 2016 From: gerrit-no-reply at lists.osmocom.org (pravin) Date: Fri, 26 Aug 2016 13:37:37 +0000 Subject: osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Patch Set 21: > Build Successful > > http://jenkins.osmocom.org/jenkins/job/osmo-pcu-gerrit/283/ : > SUCCESS' --verified 1 --code-review 0 I have tried to address all the comments. please let me know the status. -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 21 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: pravin Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Fri Aug 26 16:11:57 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Fri, 26 Aug 2016 16:11:57 +0000 Subject: [PATCH] openbsc[master]: Adding compression control and final fixups In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/642 to look at the new patch set (#24). Adding compression control and final fixups - Add module to handle compression entities - Add module to control header compression - Introduce VTY commands for heade compression configuration - Add changes in sndcp and llc to integrate header compression Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 --- M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/gprs_llc.h M openbsc/include/openbsc/gprs_sndcp.h A openbsc/include/openbsc/gprs_sndcp_comp.h A openbsc/include/openbsc/gprs_sndcp_pcomp.h M openbsc/include/openbsc/sgsn.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/gprs_llc.c M openbsc/src/gprs/gprs_sndcp.c A openbsc/src/gprs/gprs_sndcp_comp.c A openbsc/src/gprs/gprs_sndcp_pcomp.c M openbsc/src/gprs/sgsn_libgtp.c M openbsc/src/gprs/sgsn_vty.c M openbsc/tests/sgsn/Makefile.am 14 files changed, 1,419 insertions(+), 30 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/42/642/24 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index f402fea..88a7e2c 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,7 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ - slhc.h + slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h index c3b82b1..8b01467 100644 --- a/openbsc/include/openbsc/gprs_llc.h +++ b/openbsc/include/openbsc/gprs_llc.h @@ -174,6 +174,15 @@ * able to create the compression entity. */ struct llist_head *xid; + /* Compression entities */ + struct { + /* In these two list_heads we will store the + * data and protocol compression entities, + * together with their compression states */ + struct llist_head *proto; + struct llist_head *data; + } comp; + /* Internal management */ uint32_t age_timestamp; }; diff --git a/openbsc/include/openbsc/gprs_sndcp.h b/openbsc/include/openbsc/gprs_sndcp.h index fef871a..d970240 100644 --- a/openbsc/include/openbsc/gprs_sndcp.h +++ b/openbsc/include/openbsc/gprs_sndcp.h @@ -21,6 +21,16 @@ struct llist_head frag_list; struct osmo_timer_list timer; + + /* Holds state to know which compression mode is used + * when the packet is re-assembled */ + uint8_t pcomp; + uint8_t dcomp; + + /* Holds the pointers to the compression entity list + * that is used when the re-assembled packet is decompressed */ + struct llist_head *proto; + struct llist_head *data; }; /* See 6.7.1.2 Reassembly */ @@ -50,4 +60,20 @@ extern struct llist_head gprs_sndcp_entities; +/* Set of SNDCP-XID negotiation (See also: TS 144 065, + * Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_req(struct gprs_llc_lle *lle, uint8_t nsapi); + +/* Process SNDCP-XID indication (See also: TS 144 065, + * Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_ind(struct gprs_llc_xid_field *xid_field_indication, + struct gprs_llc_xid_field *xid_field_response, + struct gprs_llc_lle *lle); + +/* Process SNDCP-XID indication + * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_conf(struct gprs_llc_xid_field *xid_field_conf, + struct gprs_llc_xid_field *xid_field_request, + struct gprs_llc_lle *lle); + #endif /* INT_SNDCP_H */ diff --git a/openbsc/include/openbsc/gprs_sndcp_comp.h b/openbsc/include/openbsc/gprs_sndcp_comp.h new file mode 100644 index 0000000..87ab638 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_comp.h @@ -0,0 +1,82 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +/* Header / Data compression entity */ +struct gprs_sndcp_comp { + struct llist_head list; + + /* Serves as an ID in case we want to delete this entity later */ + unsigned int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + + /* Specifies to which NSAPIs the compression entity is assigned */ + uint8_t nsapi_len; /* Number of applicable NSAPIs (default 0) */ + uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */ + + /* Assigned pcomp values */ + uint8_t comp_len; /* Number of contained PCOMP / DCOMP values */ + uint8_t comp[MAX_COMP]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */ + + /* Algorithm parameters */ + int algo; /* Algorithm type (see gprs_sndcp_xid.h) */ + int compclass; /* See gprs_sndcp_xid.h/c */ + void *state; /* Algorithm status and parameters */ +}; + +#define MAX_COMP 16 /* Maximum number of possible pcomp/dcomp values */ +#define MAX_NSAPI 11 /* Maximum number usable NSAPIs */ + +/* Allocate a compression enitiy list */ +struct llist_head *gprs_sndcp_comp_alloc(const void *ctx); + +/* Free a compression entitiy list */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities); + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, unsigned int entity); + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_add(const void *ctx, + struct llist_head *comp_entities, + const struct gprs_sndcp_comp_field + *comp_field); + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head + *comp_entities, uint8_t comp); + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head + *comp_entities, uint8_t nsapi); + +/* Find a comp_index for a given pcomp/dcomp value */ +uint8_t gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp *comp_entity, + uint8_t comp); + +/* Find a pcomp/dcomp value for a given comp_index */ +uint8_t gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp *comp_entity, + uint8_t comp_index); diff --git a/openbsc/include/openbsc/gprs_sndcp_pcomp.h b/openbsc/include/openbsc/gprs_sndcp_pcomp.h new file mode 100644 index 0000000..0733866 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_pcomp.h @@ -0,0 +1,44 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field); + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity); + +/* Expand packet header */ +int gprs_sndcp_pcomp_expand(uint8_t *data_o, uint8_t *data_i, unsigned int len, + uint8_t pcomp, + const struct llist_head *comp_entities); + +/* Compress packet header */ +int gprs_sndcp_pcomp_compress(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t *pcomp, + const struct llist_head *comp_entities, + uint8_t nsapi); diff --git a/openbsc/include/openbsc/sgsn.h b/openbsc/include/openbsc/sgsn.h index 59126fe..acd3e4b 100644 --- a/openbsc/include/openbsc/sgsn.h +++ b/openbsc/include/openbsc/sgsn.h @@ -89,6 +89,12 @@ int dynamic_lookup; struct oap_config oap; + + /* RFC1144 TCP/IP Header compression */ + struct { + int enabled; + int s01; + } pcomp_rfc1144; }; struct sgsn_instance { diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 245636b..2910c02 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -27,7 +27,7 @@ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ - slhc.c + slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c index d6c8866..34b7afe 100644 --- a/openbsc/src/gprs/gprs_llc.c +++ b/openbsc/src/gprs/gprs_llc.c @@ -39,6 +39,7 @@ #include #include #include +#include #include static struct gprs_llc_llme *llme_alloc(uint32_t tlli); @@ -139,6 +140,16 @@ struct llist_head *xid_fields; struct gprs_llc_xid_field *xid_field; + struct gprs_llc_xid_field *xid_field_request; + struct gprs_llc_xid_field *xid_field_request_l3 = NULL; + + /* Pick layer3 XID from the XID request we have sent last */ + if (lle->llme->xid) { + llist_for_each_entry(xid_field_request, lle->llme->xid, list) { + if (xid_field_request->type == GPRS_LLC_XID_T_L3_PAR) + xid_field_request_l3 = xid_field_request; + } + } /* Parse and analyze XID-Response */ xid_fields = gprs_llc_parse_xid(NULL, bytes, bytes_len); @@ -149,12 +160,10 @@ llist_for_each_entry(xid_field, xid_fields, list) { /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ - if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { - LOGP(DLLC, LOGL_NOTICE, - "Ignoring SNDCP-XID-Field: XID: type=%i, data_len=%i, data=%s\n", - xid_field->type, xid_field->data_len, - osmo_hexdump_nospc(xid_field->data, - xid_field->data_len)); + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR && + xid_field_request_l3) { + sndcp_sn_xid_conf(xid_field, + xid_field_request_l3, lle); } /* Process LLC-XID fields: */ @@ -203,10 +212,6 @@ struct gprs_llc_xid_field *xid_field; struct gprs_llc_xid_field *xid_field_response; - /* Flush eventually pending XID fields */ - talloc_free(lle->llme->xid); - lle->llme->xid = NULL; - /* Parse and analyze XID-Request */ xid_fields = gprs_llc_parse_xid(lle->llme, bytes_request, bytes_request_len); @@ -235,6 +240,23 @@ (lle->llme, xid_field); llist_add(&xid_field_response->list, xid_fields_response); + } + } + + /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ + llist_for_each_entry(xid_field, xid_fields, list) { + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { + + xid_field_response = + talloc_zero(lle->llme, + struct gprs_llc_xid_field); + rc = sndcp_sn_xid_ind(xid_field, + xid_field_response, lle); + if (rc == 0) + llist_add(&xid_field_response->list, + xid_fields_response); + else + talloc_free(xid_field_response); } } @@ -524,11 +546,16 @@ llist_add(&llme->list, &gprs_llc_llmes); + llme->comp.proto = gprs_sndcp_comp_alloc(llme); + llme->comp.data = gprs_sndcp_comp_alloc(llme); + return llme; } static void llme_free(struct gprs_llc_llme *llme) { + gprs_sndcp_comp_free(llme->comp.proto); + gprs_sndcp_comp_free(llme->comp.data); talloc_free(llme->xid); llist_del(&llme->list); talloc_free(llme); diff --git a/openbsc/src/gprs/gprs_sndcp.c b/openbsc/src/gprs/gprs_sndcp.c index 4f71121..05957db 100644 --- a/openbsc/src/gprs/gprs_sndcp.c +++ b/openbsc/src/gprs/gprs_sndcp.c @@ -35,6 +35,131 @@ #include #include #include +#include +#include +#include +#include + +#define DEBUG_IP_PACKETS 1 /* 0=Disabled, 1=Enabled */ + +#if DEBUG_IP_PACKETS == 1 +/* Calculate TCP/IP checksum */ +static uint16_t calc_ip_csum(uint8_t *data, int len) +{ + int i; + uint32_t accumulator = 0; + uint16_t *pointer = (uint16_t *) data; + + for (i = len; i > 1; i -= 2) { + accumulator += *pointer; + pointer++; + } + + if (len % 2) + accumulator += *pointer; + + accumulator = (accumulator & 0xffff) + ((accumulator >> 16) & 0xffff); + accumulator += (accumulator >> 16) & 0xffff; + return (~accumulator); +} + +/* Calculate TCP/IP checksum */ +static uint16_t calc_tcpip_csum(const void *ctx, uint8_t *packet, int len) +{ + uint8_t *buf; + uint16_t csum; + + buf = talloc_zero_size(ctx, len); + memset(buf, 0, len); + memcpy(buf, packet + 12, 8); + buf[9] = packet[9]; + buf[11] = (len - 20) & 0xFF; + buf[10] = (len - 20) >> 8 & 0xFF; + memcpy(buf + 12, packet + 20, len - 20); + csum = calc_ip_csum(buf, len - 20 + 12); + talloc_free(buf); + return csum; +} + +/* Show some ip packet details */ +static void debug_ip_packet(uint8_t *data, int len, int dir, char *info) +{ + uint8_t tcp_flags; + char flags_debugmsg[256]; + int len_short; + static unsigned int packet_count = 0; + static unsigned int tcp_csum_err_count = 0; + static unsigned int ip_csum_err_count = 0; + + packet_count++; + + if (len > 80) + len_short = 80; + else + len_short = len; + + if (dir) + DEBUGP(DSNDCP, "%s: PHONE => NETWORK: %s\n", info, + osmo_hexdump_nospc(data, len_short)); + else + DEBUGP(DSNDCP, "%s: PHONE <= NETWORK: %s\n", info, + osmo_hexdump_nospc(data, len_short)); + + DEBUGP(DSNDCP, "%s: Length.: %d\n", info, len); + DEBUGP(DSNDCP, "%s: NO.: %d\n", info, packet_count); + + if (len < 20) { + DEBUGP(DSNDCP, "%s: Error: Short IP packet!\n", info); + return; + } + + if (calc_ip_csum(data, 20) != 0) { + DEBUGP(DSNDCP, "%s: Bad IP-Header checksum!\n", info); + ip_csum_err_count++; + } else + DEBUGP(DSNDCP, "%s: IP-Header checksum ok.\n", info); + + if (data[9] == 0x06) { + if (len < 40) { + DEBUGP(DSNDCP, "%s: Error: Short TCP packet!\n", info); + return; + } + + DEBUGP(DSNDCP, "%s: Protocol type: TCP\n", info); + tcp_flags = data[33]; + + if (calc_tcpip_csum(NULL, data, len) != 0) { + DEBUGP(DSNDCP, "%s: Bad TCP checksum!\n", info); + tcp_csum_err_count++; + } else + DEBUGP(DSNDCP, "%s: TCP checksum ok.\n", info); + + memset(flags_debugmsg, 0, sizeof(flags_debugmsg)); + if (tcp_flags & 1) + strcat(flags_debugmsg, "FIN "); + if (tcp_flags & 2) + strcat(flags_debugmsg, "SYN "); + if (tcp_flags & 4) + strcat(flags_debugmsg, "RST "); + if (tcp_flags & 8) + strcat(flags_debugmsg, "PSH "); + if (tcp_flags & 16) + strcat(flags_debugmsg, "ACK "); + if (tcp_flags & 32) + strcat(flags_debugmsg, "URG "); + DEBUGP(DSNDCP, "%s: FLAGS: %s\n", info, flags_debugmsg); + } else if (data[9] == 0x11) { + DEBUGP(DSNDCP, "%s: Protocol type: UDP\n", info); + } else { + DEBUGP(DSNDCP, "%s: Protocol type: (%02x)\n", info, data[9]); + } + + DEBUGP(DSNDCP, "%s: IP-Header checksum errors: %d\n", info, + ip_csum_err_count); + DEBUGP(DSNDCP, "%s: TCP-Checksum errors: %d\n", info, + tcp_csum_err_count); +} +#endif /* Chapter 7.2: SN-PDU Formats */ struct sndcp_common_hdr { @@ -143,6 +268,9 @@ struct msgb *msg; unsigned int seg_nr; uint8_t *npdu; + int npdu_len; + int rc; + uint8_t *expnd; LOGP(DSNDCP, LOGL_DEBUG, "TLLI=0x%08x NSAPI=%u: Defragment output PDU %u " "num_seg=%u tot_len=%u\n", sne->lle->llme->tlli, sne->nsapi, @@ -173,16 +301,46 @@ talloc_free(dqe); } + npdu_len = sne->defrag.tot_len; + /* FIXME: cancel timer */ /* actually send the N-PDU to the SGSN core code, which then * hands it off to the correct GTP tunnel + GGSN via gtp_data_req() */ - return sgsn_rx_sndcp_ud_ind(&sne->ra_id, sne->lle->llme->tlli, - sne->nsapi, msg, sne->defrag.tot_len, npdu); + + /* Decompress packet */ +#if DEBUG_IP_PACKETS == 1 + DEBUGP(DSNDCP, " \n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, "===================================================\n"); +#endif + expnd = talloc_zero_size(msg, msg->len + 64); + rc = gprs_sndcp_pcomp_expand(expnd, npdu, npdu_len, + sne->defrag.pcomp, sne->defrag.proto); + if (rc < 0) { + LOGP(DSNDCP, LOGL_ERROR, + "TCP/IP Header decompression failed!\n"); + talloc_free(expnd); + return -EIO; + } else + npdu_len = rc; +#if DEBUG_IP_PACKETS == 1 + debug_ip_packet(expnd, npdu_len, 1, "defrag_segments()"); + DEBUGP(DSNDCP, "===================================================\n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, " \n"); +#endif + + /* Hand off packet to gtp */ + rc = sgsn_rx_sndcp_ud_ind(&sne->ra_id, sne->lle->llme->tlli, + sne->nsapi, msg, npdu_len, expnd); + + talloc_free(expnd); + return rc; } -static int defrag_input(struct gprs_sndcp_entity *sne, struct msgb *msg, uint8_t *hdr, - unsigned int len) +static int defrag_input(struct gprs_sndcp_entity *sne, struct msgb *msg, + uint8_t *hdr, unsigned int len) { struct sndcp_common_hdr *sch; struct sndcp_udata_hdr *suh; @@ -343,7 +501,8 @@ }; /* returns '1' if there are more fragments to send, '0' if none */ -static int sndcp_send_ud_frag(struct sndcp_frag_state *fs) +static int sndcp_send_ud_frag(struct sndcp_frag_state *fs, + uint8_t pcomp, uint8_t dcomp) { struct gprs_sndcp_entity *sne = fs->sne; struct gprs_llc_lle *lle = sne->lle; @@ -380,8 +539,8 @@ if (sch->first) { scomph = (struct sndcp_comp_hdr *) msgb_put(fmsg, sizeof(*scomph)); - scomph->pcomp = 0; - scomph->dcomp = 0; + scomph->pcomp = pcomp; + scomph->dcomp = dcomp; } /* append the user-data header */ @@ -446,8 +605,37 @@ struct sndcp_comp_hdr *scomph; struct sndcp_udata_hdr *suh; struct sndcp_frag_state fs; + uint8_t pcomp = 0; + uint8_t dcomp = 0; + int rc; + uint8_t *compr; /* Identifiers from UP: (TLLI, SAPI) + (BVCI, NSEI) */ + + /* Compress packet */ +#if DEBUG_IP_PACKETS == 1 + DEBUGP(DSNDCP, " \n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, "===================================================\n"); + debug_ip_packet(msg->data, msg->len, 0, "sndcp_initdata_req()"); +#endif + compr = talloc_zero_size(msg, msg->len); + rc = gprs_sndcp_pcomp_compress(compr, msg->data, msg->len, &pcomp, + lle->llme->comp.proto, nsapi); + if (rc < 0) { + LOGP(DSNDCP, LOGL_ERROR, "TCP/IP Header compression failed!\n"); + talloc_free(compr); + return -EIO; + } else { + msg->len = rc; + memcpy(msg->data, compr, rc); + } + talloc_free(compr); +#if DEBUG_IP_PACKETS == 1 + DEBUGP(DSNDCP, "===================================================\n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, " \n"); +#endif sne = gprs_sndcp_entity_by_lle(lle, nsapi); if (!sne) { @@ -469,7 +657,7 @@ /* call function to generate and send fragments until all * of the N-PDU has been sent */ while (1) { - int rc = sndcp_send_ud_frag(&fs); + int rc = sndcp_send_ud_frag(&fs,pcomp,dcomp); if (rc == 0) return 0; if (rc < 0) @@ -489,8 +677,8 @@ sne->tx_npdu_nr = (sne->tx_npdu_nr + 1) % 0xfff; scomph = (struct sndcp_comp_hdr *) msgb_push(msg, sizeof(*scomph)); - scomph->pcomp = 0; - scomph->dcomp = 0; + scomph->pcomp = pcomp; + scomph->dcomp = dcomp; /* prepend common SNDCP header */ sch = (struct sndcp_common_hdr *) msgb_push(msg, sizeof(*sch)); @@ -512,6 +700,8 @@ uint8_t *npdu; uint16_t npdu_num __attribute__((unused)); int npdu_len; + int rc; + uint8_t *expnd; sch = (struct sndcp_common_hdr *) hdr; if (sch->first) { @@ -540,26 +730,58 @@ /* FIXME: move this RA_ID up to the LLME or even higher */ bssgp_parse_cell_id(&sne->ra_id, msgb_bcid(msg)); + if(scomph) { + sne->defrag.pcomp = scomph->pcomp; + sne->defrag.dcomp = scomph->dcomp; + sne->defrag.proto = lle->llme->comp.proto; + sne->defrag.data = lle->llme->comp.data; + } + /* any non-first segment is by definition something to defragment * as is any segment that tells us there are more segments */ if (!sch->first || sch->more) return defrag_input(sne, msg, hdr, len); - if (scomph && (scomph->pcomp || scomph->dcomp)) { - LOGP(DSNDCP, LOGL_ERROR, "We don't support compression yet\n"); - return -EIO; - } - npdu_num = (suh->npdu_high << 8) | suh->npdu_low; npdu = (uint8_t *)suh + sizeof(*suh); - npdu_len = (msg->data + msg->len) - npdu; + npdu_len = (msg->data + msg->len) - npdu - 3; /* -3 'removes' the FCS */ + if (npdu_len <= 0) { LOGP(DSNDCP, LOGL_ERROR, "Short SNDCP N-PDU: %d\n", npdu_len); return -EIO; } /* actually send the N-PDU to the SGSN core code, which then * hands it off to the correct GTP tunnel + GGSN via gtp_data_req() */ - return sgsn_rx_sndcp_ud_ind(&sne->ra_id, lle->llme->tlli, sne->nsapi, msg, npdu_len, npdu); + + /* Decompress packet */ +#if DEBUG_IP_PACKETS == 1 + DEBUGP(DSNDCP, " \n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, "===================================================\n"); +#endif + expnd = talloc_zero_size(msg, npdu_len + 64); + rc = gprs_sndcp_pcomp_expand(expnd, npdu, npdu_len, + sne->defrag.pcomp, sne->defrag.proto); + if (rc < 0) { + LOGP(DSNDCP, LOGL_ERROR, + "TCP/IP Header decompression failed!\n"); + talloc_free(expnd); + return -EIO; + } else + npdu_len = rc; +#if DEBUG_IP_PACKETS == 1 + debug_ip_packet(expnd, npdu_len, 1, "sndcp_llunitdata_ind()"); + DEBUGP(DSNDCP, "===================================================\n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, " \n"); +#endif + + /* Hand off packet to gtp */ + rc = sgsn_rx_sndcp_ud_ind(&sne->ra_id, lle->llme->tlli, + sne->nsapi, msg, npdu_len, expnd); + + talloc_free(expnd); + return rc; } #if 0 @@ -619,3 +841,322 @@ case LL_STATUS_IND: } #endif + +/* Generate SNDCP-XID message */ +static int gprs_llc_gen_sndcp_xid(uint8_t *bytes, int bytes_len, uint8_t nsapi) +{ + LLIST_HEAD(comp_fields); + struct gprs_sndcp_pcomp_rfc1144_params rfc1144_params; + struct gprs_sndcp_comp_field rfc1144_comp_field; + + memset(&rfc1144_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + + /* Setup which NSAPIs shall make use of rfc1144 */ + rfc1144_params.nsapi[0] = nsapi; + rfc1144_params.nsapi_len = 1; + + /* Setup rfc1144 operating parameters */ + rfc1144_params.s01 = sgsn->cfg.pcomp_rfc1144.s01; + + /* Setup rfc1144 compression field */ + rfc1144_comp_field.p = 1; + rfc1144_comp_field.entity = 0; + rfc1144_comp_field.algo = RFC_1144; + rfc1144_comp_field.comp[RFC1144_PCOMP1] = 1; + rfc1144_comp_field.comp[RFC1144_PCOMP2] = 2; + rfc1144_comp_field.comp_len = RFC1144_PCOMP_NUM; + rfc1144_comp_field.rfc1144_params = &rfc1144_params; + + /* Add compression field(s) to list */ + if (sgsn->cfg.pcomp_rfc1144.enabled) + llist_add(&rfc1144_comp_field.list, &comp_fields); + + /* Compile bytestream */ + return gprs_sndcp_compile_xid(bytes, bytes_len, &comp_fields); +} + +/* Set of SNDCP-XID bnegotiation (See also: TS 144 065, + * Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_req(struct gprs_llc_lle *lle, uint8_t nsapi) +{ + /* Note: The specification requires the SNDCP-User to set of an + * SNDCP xid request. See also 3GPP TS 44.065, 6.8 XID parameter + * negotiation, Figure 11: SNDCP XID negotiation procedure. In + * our case the SNDCP-User is sgsn_libgtp.c, which calls + * sndcp_sn_xid_req directly. */ + + uint8_t l3params[1024]; + int xid_len; + struct gprs_llc_xid_field xid_field_request; + + /* Generate compression parameter bytestream */ + xid_len = gprs_llc_gen_sndcp_xid(l3params, sizeof(l3params), nsapi); + + /* Send XID with the SNDCP-XID bytetsream included */ + if (xid_len > 0) { + xid_field_request.type = GPRS_LLC_XID_T_L3_PAR; + xid_field_request.data = l3params; + xid_field_request.data_len = xid_len; + return gprs_ll_xid_req(lle, &xid_field_request); + } + + /* When bytestream can not be generated, proceed without SNDCP-XID */ + else { + return gprs_ll_xid_req(lle, NULL); + } +} + +/* Handle header compression entites */ +static int handle_pcomp_entities(struct gprs_sndcp_comp_field *comp_field, + struct gprs_llc_lle *lle) +{ + /* Note: This functions also transforms the comp_field into its + * echo form (strips comp values, resets propose bit etc...) + * the processed comp_fields can then be sent back as XID- + * Response without further modification. */ + + /* Delete propose bit */ + comp_field->p = 0; + + /* Process proposed parameters */ + switch (comp_field->algo) { + case RFC_1144: + if (sgsn->cfg.pcomp_rfc1144.enabled && + comp_field->rfc1144_params->nsapi_len > 0) { + LOGP(DSNDCP, LOGL_DEBUG, + "Accepting RFC1144 header compression...\n"); + gprs_sndcp_comp_add(lle->llme, lle->llme->comp.proto, + comp_field); + } else { + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting RFC1144 header compression...\n"); + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + comp_field->rfc1144_params->nsapi_len = 0; + } + break; + case RFC_2507: + /* RFC 2507 is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting RFC2507 header compression...\n"); + comp_field->rfc2507_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + break; + case ROHC: + /* ROHC is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting ROHC header compression...\n"); + comp_field->rohc_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + break; + } + + return 0; +} + +/* Hanle data compression entites */ +static int handle_dcomp_entities(struct gprs_sndcp_comp_field *comp_field, + struct gprs_llc_lle *lle) +{ + /* See note in handle_pcomp_entities() */ + + /* Delete propose bit */ + comp_field->p = 0; + + /* Process proposed parameters */ + switch (comp_field->algo) { + case V42BIS: + /* V42BIS is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting V.42bis data compression...\n"); + comp_field->v42bis_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + break; + case V44: + /* V44 is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting V.44 data compression...\n"); + comp_field->v44_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + break; + } + + return 0; + +} + +/* Process SNDCP-XID indication + * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_ind(struct gprs_llc_xid_field *xid_field_indication, + struct gprs_llc_xid_field *xid_field_response, + struct gprs_llc_lle *lle) +{ + /* Note: This function computes the SNDCP-XID response that is sent + * back to the phone when a phone originated XID is received. The + * Input XID fields are directly processed and the result is directly + * handed back. */ + + int rc; + int compclass; + + struct llist_head *comp_fields; + struct gprs_sndcp_comp_field *comp_field; + + OSMO_ASSERT(xid_field_indication); + OSMO_ASSERT(xid_field_response); + OSMO_ASSERT(lle); + + /* Parse SNDCP-CID XID-Field */ + comp_fields = gprs_sndcp_parse_xid(lle->llme, + xid_field_indication->data, + xid_field_indication->data_len, + NULL); + if (!comp_fields) + return -EINVAL; + + /* Don't bother with empty indications */ + if (llist_empty(comp_fields)) { + xid_field_response->data = NULL; + xid_field_response->data_len = 0; + DEBUGP(DSNDCP, + "SNDCP-XID indication did not contain any parameters!\n"); + return 0; + } + + /* Handle compression entites */ + DEBUGP(DSNDCP, "Unmodified SNDCP-XID received from the phone:\n"); + gprs_sndcp_dump_comp_fields(comp_fields, LOGL_DEBUG); + + llist_for_each_entry(comp_field, comp_fields, list) { + compclass = gprs_sndcp_get_compression_class(comp_field); + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + rc = handle_pcomp_entities(comp_field, lle); + else if (compclass == SNDCP_XID_DATA_COMPRESSION) + rc = handle_dcomp_entities(comp_field, lle); + else { + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + rc = 0; + } + + if (rc < 0) { + talloc_free(comp_fields); + return -EINVAL; + } + } + + DEBUGP(DSNDCP, + "Modified version of received SNDCP-XID to be sent back from the ggsn:\n"); + gprs_sndcp_dump_comp_fields(comp_fields, LOGL_DEBUG); + + /* Reserve some memory to store the modified SNDCP-XID bytes */ + xid_field_response->data = + talloc_zero_size(lle->llme, xid_field_indication->data_len); + + /* Set Type flag for response */ + xid_field_response->type = GPRS_LLC_XID_T_L3_PAR; + + /* Compile modified SNDCP-XID bytes */ + rc = gprs_sndcp_compile_xid(xid_field_response->data, + xid_field_indication->data_len, + comp_fields); + + if (rc > 0) + xid_field_response->data_len = rc; + else { + talloc_free(xid_field_response->data); + xid_field_response->data = NULL; + xid_field_response->data_len = 0; + return -EINVAL; + } + + talloc_free(comp_fields); + + return 0; +} + +/* Process SNDCP-XID indication + * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_conf(struct gprs_llc_xid_field *xid_field_conf, + struct gprs_llc_xid_field *xid_field_request, + struct gprs_llc_lle *lle) +{ + /* Note: This function handles an incomming SNDCP-XID confirmiation. + * Since the confirmation fields may lack important parameters we + * will reconstruct these missing fields using the original request + * we have sent. After that we will create (or delete) the + * compression entites */ + + struct llist_head *comp_fields_req; + struct llist_head *comp_fields_conf; + struct gprs_sndcp_comp_field *comp_field; + int rc; + int compclass; + + /* We need both, the confirmation that is sent back by the phone, + * and the original request we have sent. If one of this is missing + * we can not process the confirmation, the caller must check if + * request and confirmation fields are available. */ + OSMO_ASSERT(xid_field_conf); + OSMO_ASSERT(xid_field_request); + + /* Parse SNDCP-CID XID-Field */ + comp_fields_req = gprs_sndcp_parse_xid(lle->llme, + xid_field_request->data, + xid_field_request->data_len, + NULL); + if (!comp_fields_req) + return -EINVAL; + + DEBUGP(DSNDCP, "Unmodified SNDCP-XID sent from the ggsn:\n"); + gprs_sndcp_dump_comp_fields(comp_fields_req, LOGL_DEBUG); + + /* Parse SNDCP-CID XID-Field */ + comp_fields_conf = gprs_sndcp_parse_xid(lle->llme, + xid_field_conf->data, + xid_field_conf->data_len, + comp_fields_req); + if (!comp_fields_conf) + return -EINVAL; + + DEBUGP(DSNDCP, + "Modified SNDCP-XID received from the phone:\n"); + gprs_sndcp_dump_comp_fields(comp_fields_conf, LOGL_DEBUG); + + /* Handle compression entites */ + llist_for_each_entry(comp_field, comp_fields_conf, list) { + compclass = gprs_sndcp_get_compression_class(comp_field); + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + rc = handle_pcomp_entities(comp_field, lle); + else if (compclass == SNDCP_XID_DATA_COMPRESSION) + rc = handle_dcomp_entities(comp_field, lle); + else { + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + rc = 0; + } + + if (rc < 0) { + talloc_free(comp_fields_req); + talloc_free(comp_fields_conf); + return -EINVAL; + } + } + + talloc_free(comp_fields_req); + talloc_free(comp_fields_conf); + + return 0; +} diff --git a/openbsc/src/gprs/gprs_sndcp_comp.c b/openbsc/src/gprs/gprs_sndcp_comp.c new file mode 100644 index 0000000..ede584e --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_comp.c @@ -0,0 +1,320 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +/* Create a new compression entity from a XID-Field */ +static struct gprs_sndcp_comp *gprs_sndcp_comp_create(const void *ctx, + const struct + gprs_sndcp_comp_field + *comp_field) +{ + struct gprs_sndcp_comp *comp_entity; + comp_entity = talloc_zero(ctx, struct gprs_sndcp_comp); + + /* Copy relevant information from the SNDCP-XID field */ + comp_entity->entity = comp_field->entity; + comp_entity->comp_len = comp_field->comp_len; + memcpy(comp_entity->comp, comp_field->comp, sizeof(comp_entity->comp)); + + if (comp_field->rfc1144_params) { + comp_entity->nsapi_len = comp_field->rfc1144_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc1144_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->rfc2507_params) { + comp_entity->nsapi_len = comp_field->rfc2507_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc2507_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->rohc_params) { + comp_entity->nsapi_len = comp_field->rohc_params->nsapi_len; + memcpy(comp_entity->nsapi, comp_field->rohc_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->v42bis_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->v44_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + sizeof(comp_entity->nsapi)); + } else { + /* The caller is expected to check carefully if the all + * data fields required for compression entity creation + * are present. Otherwise we blow an assertion here */ + OSMO_ASSERT(false); + } + comp_entity->algo = comp_field->algo; + + /* Check if an NSAPI is selected, if not, it does not make sense + * to create the compression entity, since the caller should + * have checked the presence of the NSAPI, we blow an assertion + * in case of missing NSAPIs */ + OSMO_ASSERT(comp_entity->nsapi_len > 0); + + /* Determine of which class our compression entity will be + * (Protocol or Data compresson ?) */ + comp_entity->compclass = gprs_sndcp_get_compression_class(comp_field); + + OSMO_ASSERT(comp_entity->compclass != -1); + + /* Create an algorithm specific compression context */ + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + if (gprs_sndcp_pcomp_init(ctx, comp_entity, comp_field) != 0) { + talloc_free(comp_entity); + comp_entity = NULL; + } + } else { + LOGP(DSNDCP, LOGL_ERROR, + "We don't support data compression yet!\n"); + talloc_free(comp_entity); + return NULL; + } + + /* Display info message */ + if (comp_entity == NULL) { + LOGP(DSNDCP, LOGL_ERROR, + "Header compression entity (%d) creation failed!\n", + comp_entity->entity); + return NULL; + } + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "New header compression entity (%d) created.\n", + comp_entity->entity); + } else { + LOGP(DSNDCP, LOGL_INFO, + "New data compression entity (%d) created.\n", + comp_entity->entity); + } + + return comp_entity; +} + +/* Allocate a compression enitiy list */ +struct llist_head *gprs_sndcp_comp_alloc(const void *ctx) +{ + struct llist_head *lh; + + lh = talloc_zero(ctx, struct llist_head); + INIT_LLIST_HEAD(lh); + + return lh; +} + +/* Free a compression entitiy list */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities) +{ + struct gprs_sndcp_comp *comp_entity; + + /* We expect the caller to take care of allocating a + * compression entity list properly. Attempting to + * free a non existing list clearly points out + * a malfunction. */ + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + /* Free compression entity */ + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %d ...\n", + comp_entity->entity); + gprs_sndcp_pcomp_term(comp_entity); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %d ...\n", + comp_entity->entity); + } + } + + talloc_free(comp_entities); +} + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, + unsigned int entity) +{ + struct gprs_sndcp_comp *comp_entity; + struct gprs_sndcp_comp *comp_entity_to_delete = NULL; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) { + comp_entity_to_delete = comp_entity; + break; + } + } + + if (!comp_entity_to_delete) + return; + + if (comp_entity_to_delete->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %d ...\n", + comp_entity_to_delete->entity); + gprs_sndcp_pcomp_term(comp_entity_to_delete); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %d ...\n", + comp_entity_to_delete->entity); + } + + /* Delete compression entity */ + llist_del(&comp_entity_to_delete->list); + talloc_free(comp_entity_to_delete); +} + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_add(const void *ctx, + struct llist_head *comp_entities, + const struct gprs_sndcp_comp_field + *comp_field) +{ + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(comp_entities); + OSMO_ASSERT(comp_field); + + /* Just to be sure, if the entity is already in + * the list it will be deleted now */ + gprs_sndcp_comp_delete(comp_entities, comp_field->entity); + + /* Create and add a new entity to the list */ + comp_entity = gprs_sndcp_comp_create(ctx, comp_field); + + if (!comp_entity) + return NULL; + + llist_add(&comp_entity->list, comp_entities); + return comp_entity; +} + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head + *comp_entities, uint8_t comp) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return comp_entity; + } + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given pcomp/dcomp value %d.\n", + comp); + return NULL; +} + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head + *comp_entities, uint8_t nsapi) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->nsapi_len; i++) { + if (comp_entity->nsapi[i] == nsapi) + return comp_entity; + } + } + + return NULL; +} + +/* Find a comp_index for a given pcomp/dcomp value */ +uint8_t gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp *comp_entity, + uint8_t comp) +{ + /* Note: This function returns a normalized version of the comp value, + * which matches up with the position of the comp field. Since comp=0 + * is reserved for "no compression", the index value starts counting + * at one. The return value is the PCOMPn/DCOMPn value one can find + * in the Specification (see e.g. 3GPP TS 44.065, 6.5.3.2, Table 7) */ + + int i; + OSMO_ASSERT(comp_entity); + + /* A pcomp/dcomp value of zero is reserved for "no comproession", + * So we just bail and return zero in this case */ + if (comp == 0) + return 0; + + /* Look in the pcomp/dcomp list for the index */ + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return i + 1; + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching comp_index for given pcomp/dcomp value %d\n", + comp); + return 0; +} + +/* Find a pcomp/dcomp value for a given comp_index */ +uint8_t gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp *comp_entity, + uint8_t comp_index) +{ + OSMO_ASSERT(comp_entity); + + /* A comp_index of zero translates to zero right away. */ + if (comp_index == 0) + return 0; + + if (comp_index > comp_entity->comp_len) { + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching pcomp/dcomp value for given comp_index value %d.\n", + comp_index); + return 0; + } + + /* Look in the pcomp/dcomp list for the comp_index, see + * note in gprs_sndcp_comp_get_idx() */ + return comp_entity->comp[comp_index - 1]; +} diff --git a/openbsc/src/gprs/gprs_sndcp_pcomp.c b/openbsc/src/gprs/gprs_sndcp_pcomp.c new file mode 100644 index 0000000..dcc3288 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_pcomp.c @@ -0,0 +1,288 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a new header compression + * entity is created by gprs_sndcp.c */ + + OSMO_ASSERT(comp_entity); + OSMO_ASSERT(comp_field); + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + comp_entity->state = + slhc_init(ctx, comp_field->rfc1144_params->s01 + 1, + comp_field->rfc1144_params->s01 + 1); + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression initalized.\n"); + return 0; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a header compression + * entity is deleted by gprs_sndcp.c */ + + OSMO_ASSERT(comp_entity); + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + if (comp_entity->state) { + slhc_free((struct slcompress *)comp_entity->state); + comp_entity->state = NULL; + } + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression terminated.\n"); + return; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Compress a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_compress(uint8_t *pcomp_index, + uint8_t *data_o, uint8_t *data_i, + unsigned int len, + struct slcompress *comp) +{ + uint8_t *comp_ptr; + int compr_len; + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Run compressor */ + compr_len = slhc_compress(comp, data_i, len, data_o, &comp_ptr, 0); + + /* Generate pcomp_index */ + if (data_o[0] & SL_TYPE_COMPRESSED_TCP) { + *pcomp_index = 2; + data_o[0] &= ~SL_TYPE_COMPRESSED_TCP; + } else if ((data_o[0] & SL_TYPE_UNCOMPRESSED_TCP) == + SL_TYPE_UNCOMPRESSED_TCP) { + *pcomp_index = 1; + data_o[0] &= 0x4F; + } else + *pcomp_index = 0; + + return compr_len; +} + +/* Expand a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_expand(uint8_t *data_o, uint8_t *data_i, + unsigned int len, + uint8_t pcomp_index, + struct slcompress *comp) +{ + int data_decompressed_len; + int type; + + /* Note: this function should never be called with pcomp_index=0, + * since this condition is already filtered + * out by gprs_sndcp_pcomp_expand() */ + + /* Determine the data type by the PCOMP index */ + switch (pcomp_index) { + case 0: + type = SL_TYPE_IP; + case 1: + type = SL_TYPE_UNCOMPRESSED_TCP; + break; + case 2: + type = SL_TYPE_COMPRESSED_TCP; + break; + default: + LOGP(DSNDCP, LOGL_ERROR, "gprs_sndcp_pcomp_rfc1144_expand() Invalid pcomp_index value (%d) detected, assuming no compression!\n", + pcomp_index); + type = SL_TYPE_IP; + break; + } + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Restore the original version nibble on + * marked uncompressed packets */ + if (type == SL_TYPE_UNCOMPRESSED_TCP) { + /* Just in case the phone tags uncompressed tcp-data + * (normally this is handled by pcomp so there is + * no need for tagging the data) */ + data_o[0] &= 0x4F; + data_decompressed_len = slhc_remember(comp, data_o, len); + return data_decompressed_len; + } + + /* Uncompress compressed packets */ + else if (type == SL_TYPE_COMPRESSED_TCP) { + data_decompressed_len = slhc_uncompress(comp, data_o, len); + return data_decompressed_len; + } + + /* Regular or unknown packets will not be touched */ + return len; +} + +/* Expand packet header */ +int gprs_sndcp_pcomp_expand(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t pcomp, + const struct llist_head *comp_entities) +{ + int rc; + uint8_t pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data_o); + OSMO_ASSERT(data_i); + OSMO_ASSERT(comp_entities); + + LOGP(DSNDCP, LOGL_DEBUG, "Compression entity list: comp_entities=%p\n", + comp_entities); + + LOGP(DSNDCP, LOGL_DEBUG, "Header compression mode: pcomp=%d\n", pcomp); + + /* Skip on pcomp=0 */ + if (pcomp == 0) { + memcpy(data_o, data_i, len); + return len; + } + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_comp(comp_entities, pcomp); + + /* Skip compression if no suitable compression entity can be found */ + if (!comp_entity) { + memcpy(data_o, data_i, len); + return len; + } + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION); + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144); + + /* Find pcomp_index */ + pcomp_index = gprs_sndcp_comp_get_idx(comp_entity, pcomp); + + /* Run decompression algo */ + rc = gprs_sndcp_pcomp_rfc1144_expand(data_o, data_i, len, pcomp_index, + comp_entity->state); + slhc_i_status(comp_entity->state); + slhc_o_status(comp_entity->state); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header expansion done, old length=%d, new length=%d, entity=%p\n", + len, rc, comp_entity); + + return rc; +} + +/* Compress packet header */ +int gprs_sndcp_pcomp_compress(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t *pcomp, + const struct llist_head *comp_entities, + uint8_t nsapi) +{ + int rc; + uint8_t pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data_o); + OSMO_ASSERT(data_i); + OSMO_ASSERT(pcomp); + OSMO_ASSERT(comp_entities); + + LOGP(DSNDCP, LOGL_DEBUG, "Compression entity list: comp_entities=%p\n", + comp_entities); + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_nsapi(comp_entities, nsapi); + + /* Skip compression if no suitable compression entity can be found */ + if (!comp_entity) { + *pcomp = 0; + memcpy(data_o, data_i, len); + return len; + } + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION); + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144); + + /* Run compression algo */ + rc = gprs_sndcp_pcomp_rfc1144_compress(&pcomp_index, data_o, data_i, + len, comp_entity->state); + slhc_i_status(comp_entity->state); + slhc_o_status(comp_entity->state); + + /* Find pcomp value */ + *pcomp = gprs_sndcp_comp_get_comp(comp_entity, pcomp_index); + + LOGP(DSNDCP, LOGL_DEBUG, "Header compression mode: pcomp=%d\n", *pcomp); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header expansion done, old length=%d, new length=%d, entity=%p\n", + len, rc, comp_entity); + return rc; +} diff --git a/openbsc/src/gprs/sgsn_libgtp.c b/openbsc/src/gprs/sgsn_libgtp.c index be7637a..6e6bbfd 100644 --- a/openbsc/src/gprs/sgsn_libgtp.c +++ b/openbsc/src/gprs/sgsn_libgtp.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -307,6 +308,8 @@ static int send_act_pdp_cont_acc(struct sgsn_pdp_ctx *pctx) { struct sgsn_signal_data sig_data; + int rc; + struct gprs_llc_lle *lle; /* Inform others about it */ memset(&sig_data, 0, sizeof(sig_data)); @@ -314,7 +317,17 @@ osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_ACT, &sig_data); /* Send PDP CTX ACT to MS */ - return gsm48_tx_gsm_act_pdp_acc(pctx); + rc = gsm48_tx_gsm_act_pdp_acc(pctx); + if(rc < 0) + return rc; + + /* Send SNDCP XID to MS */ + lle = &pctx->mm->gb.llme->lle[pctx->sapi]; + rc = sndcp_sn_xid_req(lle,pctx->nsapi); + if(rc < 0) + return rc; + + return 0; } /* The GGSN has confirmed the creation of a PDP Context */ diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c index e6dc68d..bc53743 100644 --- a/openbsc/src/gprs/sgsn_vty.c +++ b/openbsc/src/gprs/sgsn_vty.c @@ -269,6 +269,12 @@ vty_out(vty, " timer t3395 %d%s", g_cfg->timers.T3395, VTY_NEWLINE); vty_out(vty, " timer t3397 %d%s", g_cfg->timers.T3397, VTY_NEWLINE); + if (g_cfg->pcomp_rfc1144.enabled) { + vty_out(vty, " compression rfc1144 slots %d%s", + g_cfg->pcomp_rfc1144.s01+1, VTY_NEWLINE); + } else + vty_out(vty, " no compression rfc1144%s", VTY_NEWLINE); + return CMD_SUCCESS; } @@ -1074,6 +1080,28 @@ return CMD_SUCCESS; } +#define COMPRESSION_STR "Configure compression\n" +DEFUN(cfg_no_comp_rfc1144, cfg_no_comp_rfc1144_cmd, + "no compression rfc1144", + NO_STR COMPRESSION_STR + "disable rfc1144 TCP/IP header compression\n") +{ + g_cfg->pcomp_rfc1144.enabled = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_comp_rfc1144, cfg_comp_rfc1144_cmd, + "compression rfc1144 slots <1-256>", + COMPRESSION_STR + "RFC1144 Header compresion scheme\n" + "Number of compression state slots\n" + "Number of compression state slots\n") +{ + g_cfg->pcomp_rfc1144.enabled = 1; + g_cfg->pcomp_rfc1144.s01 = atoi(argv[0]) - 1; + return CMD_SUCCESS; +} + int sgsn_vty_init(void) { install_element_ve(&show_sgsn_cmd); @@ -1128,6 +1156,9 @@ install_element(SGSN_NODE, &cfg_sgsn_T3395_cmd); install_element(SGSN_NODE, &cfg_sgsn_T3397_cmd); + install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd); + install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd); + return 0; } diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 3e66978..1804280 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -33,6 +33,8 @@ $(top_builddir)/src/gprs/gprs_llc_xid.o \ $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ $(top_builddir)/src/gprs/slhc.o \ + $(top_builddir)/src/gprs/gprs_sndcp_comp.o \ + $(top_builddir)/src/gprs/gprs_sndcp_pcomp.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ -- To view, visit https://gerrit.osmocom.org/642 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 Gerrit-PatchSet: 24 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Fri Aug 26 16:11:57 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Fri, 26 Aug 2016 16:11:57 +0000 Subject: [PATCH] openbsc[master]: Adding V.42bis implementation In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/643 to look at the new patch set (#26). Adding V.42bis implementation V.42bis is a data compression method found in modems. It has also been specified for GPRS as data compression algorithm. The implementation has been taken from IAXmodem: https://sourceforge.net/p/iaxmodem/code/HEAD/tree/ svn checkout svn://svn.code.sf.net/p/iaxmodem/code/ iaxmodem-code Revision: r36 Change-Id: Iabedece9f97ca944a1e3f747bb073e532c4e9dca --- A openbsc/include/openbsc/v42bis.h A openbsc/include/openbsc/v42bis_private.h A openbsc/src/gprs/v42bis.c 3 files changed, 1,031 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/43/643/26 diff --git a/openbsc/include/openbsc/v42bis.h b/openbsc/include/openbsc/v42bis.h new file mode 100644 index 0000000..b947a61 --- /dev/null +++ b/openbsc/include/openbsc/v42bis.h @@ -0,0 +1,140 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * v42bis.h + * + * Written by Steve Underwood + * + * Copyright (C) 2005, 2011 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/*! \page v42bis_page V.42bis modem data compression +\section v42bis_page_sec_1 What does it do? +The v.42bis specification defines a data compression scheme, to work in +conjunction with the error correction scheme defined in V.42. + +\section v42bis_page_sec_2 How does it work? +*/ + +#if !defined(_SPANDSP_V42BIS_H_) +#define _SPANDSP_V42BIS_H_ + +#define V42BIS_MIN_STRING_SIZE 6 +#define V42BIS_MAX_STRING_SIZE 250 +#define V42BIS_MIN_DICTIONARY_SIZE 512 +#define V42BIS_MAX_BITS 12 +#define V42BIS_MAX_CODEWORDS 4096 /* 2^V42BIS_MAX_BITS */ +#define V42BIS_MAX_OUTPUT_LENGTH 1024 + +enum +{ + V42BIS_P0_NEITHER_DIRECTION = 0, + V42BIS_P0_INITIATOR_RESPONDER, + V42BIS_P0_RESPONDER_INITIATOR, + V42BIS_P0_BOTH_DIRECTIONS +}; + +enum +{ + V42BIS_COMPRESSION_MODE_DYNAMIC = 0, + V42BIS_COMPRESSION_MODE_ALWAYS, + V42BIS_COMPRESSION_MODE_NEVER +}; + +/*! + V.42bis compression/decompression descriptor. This defines the working state for a + single instance of V.42bis compress/decompression. +*/ +typedef struct v42bis_state_s v42bis_state_t; + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/*! Compress a block of octets. + \param s The V.42bis context. + \param buf The data to be compressed. + \param len The length of the data buffer. + \return 0 */ +SPAN_DECLARE(int) v42bis_compress(v42bis_state_t *s, const uint8_t buf[], int len); + +/*! Flush out any data remaining in a compression buffer. + \param s The V.42bis context. + \return 0 */ +SPAN_DECLARE(int) v42bis_compress_flush(v42bis_state_t *s); + +/*! Decompress a block of octets. + \param s The V.42bis context. + \param buf The data to be decompressed. + \param len The length of the data buffer. + \return 0 */ +SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *s, const uint8_t buf[], int len); + +/*! Flush out any data remaining in the decompression buffer. + \param s The V.42bis context. + \return 0 */ +SPAN_DECLARE(int) v42bis_decompress_flush(v42bis_state_t *s); + +/*! Set the compression mode. + \param s The V.42bis context. + \param mode One of the V.42bis compression modes - + V42BIS_COMPRESSION_MODE_DYNAMIC, + V42BIS_COMPRESSION_MODE_ALWAYS, + V42BIS_COMPRESSION_MODE_NEVER */ +SPAN_DECLARE(void) v42bis_compression_control(v42bis_state_t *s, int mode); + +/*! Initialise a V.42bis context. + \param s The V.42bis context. + \param negotiated_p0 The negotiated P0 parameter, from the V.42bis spec. + \param negotiated_p1 The negotiated P1 parameter, from the V.42bis spec. + \param negotiated_p2 The negotiated P2 parameter, from the V.42bis spec. + \param encode_handler Encode callback handler. + \param encode_user_data An opaque pointer passed to the encode callback handler. + \param max_encode_len The maximum length that should be passed to the encode handler. + \param decode_handler Decode callback handler. + \param decode_user_data An opaque pointer passed to the decode callback handler. + \param max_decode_len The maximum length that should be passed to the decode handler. + \return The V.42bis context. */ +SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, + int negotiated_p0, + int negotiated_p1, + int negotiated_p2, + put_msg_func_t encode_handler, + void *encode_user_data, + int max_encode_len, + put_msg_func_t decode_handler, + void *decode_user_data, + int max_decode_len); + +/*! Release a V.42bis context. + \param s The V.42bis context. + \return 0 if OK */ +SPAN_DECLARE(int) v42bis_release(v42bis_state_t *s); + +/*! Free a V.42bis context. + \param s The V.42bis context. + \return 0 if OK */ +SPAN_DECLARE(int) v42bis_free(v42bis_state_t *s); + +#if defined(__cplusplus) +} +#endif + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/openbsc/include/openbsc/v42bis_private.h b/openbsc/include/openbsc/v42bis_private.h new file mode 100644 index 0000000..2c801eb --- /dev/null +++ b/openbsc/include/openbsc/v42bis_private.h @@ -0,0 +1,127 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * private/v42bis.h + * + * Written by Steve Underwood + * + * Copyright (C) 2005 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#if !defined(_SPANDSP_PRIVATE_V42BIS_H_) +#define _SPANDSP_PRIVATE_V42BIS_H_ + +/*! + V.42bis dictionary node. + Note that 0 is not a valid node to point to (0 is always a control code), so 0 is used + as a "no such value" marker in this structure. +*/ +typedef struct +{ + /*! \brief The value of the octet represented by the current dictionary node */ + uint8_t node_octet; + /*! \brief The parent of this node */ + uint16_t parent; + /*! \brief The first child of this node */ + uint16_t child; + /*! \brief The next node at the same depth */ + uint16_t next; +} v42bis_dict_node_t; + +/*! + V.42bis compression or decompression. This defines the working state for a single instance + of V.42bis compression or decompression. +*/ +typedef struct +{ + /*! \brief Compression enabled. */ + int v42bis_parm_p0; + /*! \brief Compression mode. */ + int compression_mode; + /*! \brief Callback function to handle output data. */ + put_msg_func_t handler; + /*! \brief An opaque pointer passed in calls to the data handler. */ + void *user_data; + /*! \brief The maximum amount to be passed to the data handler. */ + int max_output_len; + + /*! \brief TRUE if we are in transparent (i.e. uncompressable) mode */ + int transparent; + /*! \brief Next empty dictionary entry */ + uint16_t v42bis_parm_c1; + /*! \brief Current codeword size */ + uint16_t v42bis_parm_c2; + /*! \brief Threshold for codeword size change */ + uint16_t v42bis_parm_c3; + /*! \brief The current update point in the dictionary */ + uint16_t update_at; + /*! \brief The last entry matched in the dictionary */ + uint16_t last_matched; + /*! \brief The last entry added to the dictionary */ + uint16_t last_added; + /*! \brief Total number of codewords in the dictionary */ + int v42bis_parm_n2; + /*! \brief Maximum permitted string length */ + int v42bis_parm_n7; + /*! \brief The dictionary */ + v42bis_dict_node_t dict[V42BIS_MAX_CODEWORDS]; + + /*! \brief The octet string in progress */ + uint8_t string[V42BIS_MAX_STRING_SIZE]; + /*! \brief The current length of the octet string in progress */ + int string_length; + /*! \brief The amount of the octet string in progress which has already + been flushed out of the buffer */ + int flushed_length; + + /*! \brief Compression performance metric */ + uint16_t compression_performance; + + /*! \brief Outgoing bit buffer (compression), or incoming bit buffer (decompression) */ + uint32_t bit_buffer; + /*! \brief Outgoing bit count (compression), or incoming bit count (decompression) */ + int bit_count; + + /*! \brief The output composition buffer */ + uint8_t output_buf[V42BIS_MAX_OUTPUT_LENGTH]; + /*! \brief The length of the contents of the output composition buffer */ + int output_octet_count; + + /*! \brief The current value of the escape code */ + uint8_t escape_code; + /*! \brief TRUE if we just hit an escape code, and are waiting for the following octet */ + int escaped; +} v42bis_comp_state_t; + +/*! + V.42bis compression/decompression descriptor. This defines the working state for a + single instance of V.42bis compress/decompression. +*/ +struct v42bis_state_s +{ + /*! \brief Compression state. */ + v42bis_comp_state_t compress; + /*! \brief Decompression state. */ + v42bis_comp_state_t decompress; + + /*! \brief Error and flow logging control */ + logging_state_t logging; +}; + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/openbsc/src/gprs/v42bis.c b/openbsc/src/gprs/v42bis.c new file mode 100644 index 0000000..d025ea9 --- /dev/null +++ b/openbsc/src/gprs/v42bis.c @@ -0,0 +1,764 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * v42bis.c + * + * Written by Steve Underwood + * + * Copyright (C) 2005, 2011 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* THIS IS A WORK IN PROGRESS. IT IS NOT FINISHED. + Currently it performs the core compression and decompression functions OK. + However, a number of the bells and whistles in V.42bis are incomplete. */ + +/*! \file */ + +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "spandsp/telephony.h" +#include "spandsp/logging.h" +#include "spandsp/bit_operations.h" +#include "spandsp/async.h" +#include "spandsp/v42bis.h" + +#include "spandsp/private/logging.h" +#include "spandsp/private/v42bis.h" + +/* Fixed parameters from the spec. */ +/* Character size (bits) */ +#define V42BIS_N3 8 +/* Number of characters in the alphabet */ +#define V42BIS_N4 256 +/* Index number of first dictionary entry used to store a string */ +#define V42BIS_N5 (V42BIS_N4 + V42BIS_N6) +/* Number of control codewords */ +#define V42BIS_N6 3 +/* V.42bis/9.2 */ +#define V42BIS_ESC_STEP 51 + +/* Compreeibility monitoring parameters for assessing automated switches between + transparent and compressed mode */ +#define COMPRESSIBILITY_MONITOR (256*V42BIS_N3) +#define COMPRESSIBILITY_MONITOR_HYSTERESIS 11 + +/* Control code words in compressed mode */ +enum +{ + V42BIS_ETM = 0, /* Enter transparent mode */ + V42BIS_FLUSH = 1, /* Flush data */ + V42BIS_STEPUP = 2 /* Step up codeword size */ +}; + +/* Command codes in transparent mode */ +enum +{ + V42BIS_ECM = 0, /* Enter compression mode */ + V42BIS_EID = 1, /* Escape character in data */ + V42BIS_RESET = 2 /* Force reinitialisation */ +}; + +static __inline__ void push_octet(v42bis_comp_state_t *s, int octet) +{ + s->output_buf[s->output_octet_count++] = (uint8_t) octet; + if (s->output_octet_count >= s->max_output_len) + { + s->handler(s->user_data, s->output_buf, s->output_octet_count); + s->output_octet_count = 0; + } +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ void push_octets(v42bis_comp_state_t *s, const uint8_t buf[], int len) +{ + int i; + int chunk; + + i = 0; + while ((s->output_octet_count + len - i) >= s->max_output_len) + { + chunk = s->max_output_len - s->output_octet_count; + memcpy(&s->output_buf[s->output_octet_count], &buf[i], chunk); + s->handler(s->user_data, s->output_buf, s->max_output_len); + s->output_octet_count = 0; + i += chunk; + } + chunk = len - i; + if (chunk > 0) + { + memcpy(&s->output_buf[s->output_octet_count], &buf[i], chunk); + s->output_octet_count += chunk; + } +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ void push_compressed_code(v42bis_comp_state_t *s, int code) +{ + s->bit_buffer |= code << s->bit_count; + s->bit_count += s->v42bis_parm_c2; + while (s->bit_count >= 8) + { + push_octet(s, s->bit_buffer & 0xFF); + s->bit_buffer >>= 8; + s->bit_count -= 8; + } +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ void push_octet_alignment(v42bis_comp_state_t *s) +{ + if ((s->bit_count & 7)) + { + s->bit_count += (8 - (s->bit_count & 7)); + while (s->bit_count >= 8) + { + push_octet(s, s->bit_buffer & 0xFF); + s->bit_buffer >>= 8; + s->bit_count -= 8; + } + } +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ void flush_octets(v42bis_comp_state_t *s) +{ + if (s->output_octet_count > 0) + { + s->handler(s->user_data, s->output_buf, s->output_octet_count); + s->output_octet_count = 0; + } +} +/*- End of function --------------------------------------------------------*/ + +static void dictionary_init(v42bis_comp_state_t *s) +{ + int i; + + memset(s->dict, 0, sizeof(s->dict)); + for (i = 0; i < V42BIS_N4; i++) + s->dict[i + V42BIS_N6].node_octet = i; + s->v42bis_parm_c1 = V42BIS_N5; + s->v42bis_parm_c2 = V42BIS_N3 + 1; + s->v42bis_parm_c3 = V42BIS_N4 << 1; + s->last_matched = 0; + s->update_at = 0; + s->last_added = 0; + s->bit_buffer = 0; + s->bit_count = 0; + s->flushed_length = 0; + s->string_length = 0; + s->escape_code = 0; + s->transparent = TRUE; + s->escaped = FALSE; + s->compression_performance = COMPRESSIBILITY_MONITOR; +} +/*- End of function --------------------------------------------------------*/ + +static uint16_t match_octet(v42bis_comp_state_t *s, uint16_t at, uint8_t octet) +{ + uint16_t e; + + if (at == 0) + return octet + V42BIS_N6; + e = s->dict[at].child; + while (e) + { + if (s->dict[e].node_octet == octet) + return e; + e = s->dict[e].next; + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static uint16_t add_octet_to_dictionary(v42bis_comp_state_t *s, uint16_t at, uint8_t octet) +{ + uint16_t newx; + uint16_t next; + uint16_t e; + + newx = s->v42bis_parm_c1; + s->dict[newx].node_octet = octet; + s->dict[newx].parent = at; + s->dict[newx].child = 0; + s->dict[newx].next = s->dict[at].child; + s->dict[at].child = newx; + next = newx; + /* 6.5 Recovering a dictionary entry to use next */ + do + { + /* 6.5(a) and (b) */ + if (++next == s->v42bis_parm_n2) + next = V42BIS_N5; + } + while (s->dict[next].child); + /* 6.5(c) We need to reuse a leaf node */ + if (s->dict[next].parent) + { + /* 6.5(d) Detach the leaf node from its parent, and re-use it */ + e = s->dict[next].parent; + if (s->dict[e].child == next) + { + s->dict[e].child = s->dict[next].next; + } + else + { + e = s->dict[e].child; + while (s->dict[e].next != next) + e = s->dict[e].next; + s->dict[e].next = s->dict[next].next; + } + } + s->v42bis_parm_c1 = next; + return newx; +} +/*- End of function --------------------------------------------------------*/ + +static void send_string(v42bis_comp_state_t *s) +{ + push_octets(s, s->string, s->string_length); + s->string_length = 0; + s->flushed_length = 0; +} +/*- End of function --------------------------------------------------------*/ + +static void expand_codeword_to_string(v42bis_comp_state_t *s, uint16_t code) +{ + int i; + uint16_t p; + + /* Work out the length */ + for (i = 0, p = code; p; i++) + p = s->dict[p].parent; + s->string_length += i; + /* Now expand the known length of string */ + i = s->string_length - 1; + for (p = code; p; ) + { + s->string[i--] = s->dict[p].node_octet; + p = s->dict[p].parent; + } +} +/*- End of function --------------------------------------------------------*/ + +static void send_encoded_data(v42bis_comp_state_t *s, uint16_t code) +{ + int i; + + /* Update compressibility metric */ + /* Integrate at the compressed bit rate, and leak at the pre-compression bit rate */ + s->compression_performance += (s->v42bis_parm_c2 - s->compression_performance*s->string_length*V42BIS_N3/COMPRESSIBILITY_MONITOR); + if (s->transparent) + { + for (i = 0; i < s->string_length; i++) + { + push_octet(s, s->string[i]); + if (s->string[i] == s->escape_code) + { + push_octet(s, V42BIS_EID); + s->escape_code += V42BIS_ESC_STEP; + } + } + } + else + { + /* Allow for any escape octets in the string */ + for (i = 0; i < s->string_length; i++) + { + if (s->string[i] == s->escape_code) + s->escape_code += V42BIS_ESC_STEP; + } + /* 7.4 Encoding - we now have the longest matchable string, and will need to output the code for it. */ + while (code >= s->v42bis_parm_c3) + { + /* We need to increase the codeword size */ + /* 7.4(a) */ + push_compressed_code(s, V42BIS_STEPUP); + /* 7.4(b) */ + s->v42bis_parm_c2++; + /* 7.4(c) */ + s->v42bis_parm_c3 <<= 1; + /* 7.4(d) this might need to be repeated, so we loop */ + } + /* 7.5 Transfer - output the last state of the string */ + push_compressed_code(s, code); + } + s->string_length = 0; + s->flushed_length = 0; +} +/*- End of function --------------------------------------------------------*/ + +static void go_compressed(v42bis_state_t *ss) +{ + v42bis_comp_state_t *s; + + s = &ss->compress; + if (!s->transparent) + return; + span_log(&ss->logging, SPAN_LOG_FLOW, "Changing to compressed mode\n"); + /* Switch out of transparent now, between codes. We need to send the octet which did not + match, just before switching. */ + if (s->last_matched) + { + s->update_at = s->last_matched; + send_encoded_data(s, s->last_matched); + s->last_matched = 0; + } + push_octet(s, s->escape_code); + push_octet(s, V42BIS_ECM); + s->bit_buffer = 0; + s->transparent = FALSE; +} +/*- End of function --------------------------------------------------------*/ + +static void go_transparent(v42bis_state_t *ss) +{ + v42bis_comp_state_t *s; + + s = &ss->compress; + if (s->transparent) + return; + span_log(&ss->logging, SPAN_LOG_FLOW, "Changing to transparent mode\n"); + /* Switch into transparent now, between codes, and the unmatched octet should + go out in transparent mode, just below */ + if (s->last_matched) + { + s->update_at = s->last_matched; + send_encoded_data(s, s->last_matched); + s->last_matched = 0; + } + s->last_added = 0; + push_compressed_code(s, V42BIS_ETM); + push_octet_alignment(s); + s->transparent = TRUE; +} +/*- End of function --------------------------------------------------------*/ + +static void monitor_for_mode_change(v42bis_state_t *ss) +{ + v42bis_comp_state_t *s; + + s = &ss->compress; + switch (s->compression_mode) + { + case V42BIS_COMPRESSION_MODE_DYNAMIC: + /* 7.8 Data compressibility test */ + if (s->transparent) + { + if (s->compression_performance < COMPRESSIBILITY_MONITOR - COMPRESSIBILITY_MONITOR_HYSTERESIS) + { + /* 7.8.1 Transition to compressed mode */ + go_compressed(ss); + } + } + else + { + if (s->compression_performance > COMPRESSIBILITY_MONITOR) + { + /* 7.8.2 Transition to transparent mode */ + go_transparent(ss); + } + } + /* 7.8.3 Reset function - TODO */ + break; + case V42BIS_COMPRESSION_MODE_ALWAYS: + if (s->transparent) + go_compressed(ss); + break; + case V42BIS_COMPRESSION_MODE_NEVER: + if (!s->transparent) + go_transparent(ss); + break; + } +} +/*- End of function --------------------------------------------------------*/ + +static int v42bis_comp_init(v42bis_comp_state_t *s, + int p1, + int p2, + put_msg_func_t handler, + void *user_data, + int max_output_len) +{ + memset(s, 0, sizeof(*s)); + s->v42bis_parm_n2 = p1; + s->v42bis_parm_n7 = p2; + s->handler = handler; + s->user_data = user_data; + s->max_output_len = (max_output_len < V42BIS_MAX_OUTPUT_LENGTH) ? max_output_len : V42BIS_MAX_OUTPUT_LENGTH; + s->output_octet_count = 0; + dictionary_init(s); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int comp_exit(v42bis_comp_state_t *s) +{ + s->v42bis_parm_n2 = 0; + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v42bis_compress(v42bis_state_t *ss, const uint8_t buf[], int len) +{ + v42bis_comp_state_t *s; + int i; + uint16_t code; + + s = &ss->compress; + if (!s->v42bis_parm_p0) + { + /* Compression is off - just push the incoming data out */ + push_octets(s, buf, len); + return 0; + } + for (i = 0; i < len; ) + { + /* 6.4 Add the string to the dictionary */ + if (s->update_at) + { + if (match_octet(s, s->update_at, buf[i]) == 0) + s->last_added = add_octet_to_dictionary(s, s->update_at, buf[i]); + s->update_at = 0; + } + /* Match string */ + while (i < len) + { + code = match_octet(s, s->last_matched, buf[i]); + if (code == 0) + { + s->update_at = s->last_matched; + send_encoded_data(s, s->last_matched); + s->last_matched = 0; + break; + } + if (code == s->last_added) + { + s->last_added = 0; + send_encoded_data(s, s->last_matched); + s->last_matched = 0; + break; + } + s->last_matched = code; + /* 6.3(b) If the string matches a dictionary entry, and the entry is not that entry + created by the last invocation of the string matching procedure, then the + next character shall be read and appended to the string and this step + repeated. */ + s->string[s->string_length++] = buf[i++]; + /* 6.4(a) The string must not exceed N7 in length */ + if (s->string_length + s->flushed_length == s->v42bis_parm_n7) + { + send_encoded_data(s, s->last_matched); + s->last_matched = 0; + break; + } + } + monitor_for_mode_change(ss); + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v42bis_compress_flush(v42bis_state_t *ss) +{ + v42bis_comp_state_t *s; + int len; + + s = &ss->compress; + if (s->update_at) + return 0; + if (s->last_matched) + { + len = s->string_length; + send_encoded_data(s, s->last_matched); + s->flushed_length += len; + } + if (!s->transparent) + { + s->update_at = s->last_matched; + s->last_matched = 0; + s->flushed_length = 0; + push_compressed_code(s, V42BIS_FLUSH); + push_octet_alignment(s); + } + flush_octets(s); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *ss, const uint8_t buf[], int len) +{ + v42bis_comp_state_t *s; + int i; + int j; + int yyy; + uint16_t code; + uint16_t p; + uint8_t ch; + uint8_t in; + + s = &ss->decompress; + if (!s->v42bis_parm_p0) + { + /* Compression is off - just push the incoming data out */ + push_octets(s, buf, len); + return 0; + } + for (i = 0; i < len; ) + { + if (s->transparent) + { + in = buf[i]; + if (s->escaped) + { + /* Command */ + s->escaped = FALSE; + switch (in) + { + case V42BIS_ECM: + /* Enter compressed mode */ + span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_ECM\n"); + send_string(s); + s->transparent = FALSE; + s->update_at = s->last_matched; + s->last_matched = 0; + i++; + continue; + case V42BIS_EID: + /* Escape symbol */ + span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_EID\n"); + in = s->escape_code; + s->escape_code += V42BIS_ESC_STEP; + break; + case V42BIS_RESET: + /* Reset dictionary */ + span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_RESET\n"); + /* TODO: */ + send_string(s); + dictionary_init(s); + i++; + continue; + default: + span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_???? - %" PRIu32 "\n", in); + return -1; + } + } + else if (in == s->escape_code) + { + s->escaped = TRUE; + i++; + continue; + } + + yyy = TRUE; + for (j = 0; j < 2 && yyy; j++) + { + if (s->update_at) + { + if (match_octet(s, s->update_at, in) == 0) + s->last_added = add_octet_to_dictionary(s, s->update_at, in); + s->update_at = 0; + } + + code = match_octet(s, s->last_matched, in); + if (code == 0) + { + s->update_at = s->last_matched; + send_string(s); + s->last_matched = 0; + } + else if (code == s->last_added) + { + s->last_added = 0; + send_string(s); + s->last_matched = 0; + } + else + { + s->last_matched = code; + s->string[s->string_length++] = in; + if (s->string_length + s->flushed_length == s->v42bis_parm_n7) + { + send_string(s); + s->last_matched = 0; + } + i++; + yyy = FALSE; + } + } + } + else + { + /* Get code from input */ + while (s->bit_count < s->v42bis_parm_c2 && i < len) + { + s->bit_buffer |= buf[i++] << s->bit_count; + s->bit_count += 8; + } + if (s->bit_count < s->v42bis_parm_c2) + continue; + code = s->bit_buffer & ((1 << s->v42bis_parm_c2) - 1); + s->bit_buffer >>= s->v42bis_parm_c2; + s->bit_count -= s->v42bis_parm_c2; + + if (code < V42BIS_N6) + { + /* We have a control code. */ + switch (code) + { + case V42BIS_ETM: + /* Enter transparent mode */ + span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_ETM\n"); + s->bit_count = 0; + s->transparent = TRUE; + s->last_matched = 0; + s->last_added = 0; + break; + case V42BIS_FLUSH: + /* Flush signal */ + span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_FLUSH\n"); + s->bit_count = 0; + break; + case V42BIS_STEPUP: + /* Increase code word size */ + span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_STEPUP\n"); + s->v42bis_parm_c2++; + s->v42bis_parm_c3 <<= 1; + if (s->v42bis_parm_c2 > (s->v42bis_parm_n2 >> 3)) + return -1; + break; + } + continue; + } + /* Regular codeword */ + if (code == s->v42bis_parm_c1) + return -1; + expand_codeword_to_string(s, code); + if (s->update_at) + { + ch = s->string[0]; + if ((p = match_octet(s, s->update_at, ch)) == 0) + { + s->last_added = add_octet_to_dictionary(s, s->update_at, ch); + if (code == s->v42bis_parm_c1) + return -1; + } + else if (p == s->last_added) + { + s->last_added = 0; + } + } + s->update_at = ((s->string_length + s->flushed_length) == s->v42bis_parm_n7) ? 0 : code; + /* Allow for any escapes which may be in this string */ + for (j = 0; j < s->string_length; j++) + { + if (s->string[j] == s->escape_code) + s->escape_code += V42BIS_ESC_STEP; + } + send_string(s); + } + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v42bis_decompress_flush(v42bis_state_t *ss) +{ + v42bis_comp_state_t *s; + int len; + + s = &ss->decompress; + len = s->string_length; + send_string(s); + s->flushed_length += len; + flush_octets(s); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(void) v42bis_compression_control(v42bis_state_t *s, int mode) +{ + s->compress.compression_mode = mode; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, + int negotiated_p0, + int negotiated_p1, + int negotiated_p2, + put_msg_func_t encode_handler, + void *encode_user_data, + int max_encode_len, + put_msg_func_t decode_handler, + void *decode_user_data, + int max_decode_len) +{ + int ret; + + if (negotiated_p1 < V42BIS_MIN_DICTIONARY_SIZE || negotiated_p1 > 65535) + return NULL; + if (negotiated_p2 < V42BIS_MIN_STRING_SIZE || negotiated_p2 > V42BIS_MAX_STRING_SIZE) + return NULL; + if (s == NULL) + { + if ((s = (v42bis_state_t *) malloc(sizeof(*s))) == NULL) + return NULL; + } + memset(s, 0, sizeof(*s)); + span_log_init(&s->logging, SPAN_LOG_NONE, NULL); + span_log_set_protocol(&s->logging, "V.42bis"); + + if ((ret = v42bis_comp_init(&s->compress, negotiated_p1, negotiated_p2, encode_handler, encode_user_data, max_encode_len))) + return NULL; + if ((ret = v42bis_comp_init(&s->decompress, negotiated_p1, negotiated_p2, decode_handler, decode_user_data, max_decode_len))) + { + comp_exit(&s->compress); + return NULL; + } + s->compress.v42bis_parm_p0 = negotiated_p0 & 2; + s->decompress.v42bis_parm_p0 = negotiated_p0 & 1; + + return s; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v42bis_release(v42bis_state_t *s) +{ + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v42bis_free(v42bis_state_t *s) +{ + comp_exit(&s->compress); + comp_exit(&s->decompress); + return 0; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ -- To view, visit https://gerrit.osmocom.org/643 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Iabedece9f97ca944a1e3f747bb073e532c4e9dca Gerrit-PatchSet: 26 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Fri Aug 26 16:11:57 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Fri, 26 Aug 2016 16:11:57 +0000 Subject: [PATCH] openbsc[master]: V.42bis integration and unit test In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/644 to look at the new patch set (#31). V.42bis integration and unit test The previously committed V.42bis implementation has been edited to function outside IAXmodem. Debug printf statements were changed into DEBUGP statements. Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d --- M openbsc/.gitignore M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/debug.h M openbsc/include/openbsc/v42bis.h M openbsc/include/openbsc/v42bis_private.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/sgsn_main.c M openbsc/src/gprs/v42bis.c M openbsc/tests/Makefile.am M openbsc/tests/testsuite.at A openbsc/tests/v42bis/Makefile.am A openbsc/tests/v42bis/v42bis_test.c A openbsc/tests/v42bis/v42bis_test.ok 14 files changed, 778 insertions(+), 29 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/44/644/31 diff --git a/openbsc/.gitignore b/openbsc/.gitignore index e75b9eb..6fbd463 100644 --- a/openbsc/.gitignore +++ b/openbsc/.gitignore @@ -84,6 +84,7 @@ tests/xid/xid_test tests/sndcp_xid/sndcp_xid_test tests/slhc/slhc_test +tests/v42bis/v42bis_test tests/atconfig tests/atlocal diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 18980b0..1df14fe 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -232,6 +232,7 @@ tests/xid/Makefile tests/sndcp_xid/Makefile tests/slhc/Makefile + tests/v42bis/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 88a7e2c..b3403dd 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,8 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ - slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h + slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h v42bis.h \ + v42bis_private.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 90ddca5..ca3d4ad 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -37,6 +37,7 @@ DGTPHUB, DRANAP, DSUA, + DV42BIS, Debug_LastEntry, }; diff --git a/openbsc/include/openbsc/v42bis.h b/openbsc/include/openbsc/v42bis.h index b947a61..607a58e 100644 --- a/openbsc/include/openbsc/v42bis.h +++ b/openbsc/include/openbsc/v42bis.h @@ -31,8 +31,12 @@ \section v42bis_page_sec_2 How does it work? */ +#include + #if !defined(_SPANDSP_V42BIS_H_) #define _SPANDSP_V42BIS_H_ + +#define SPAN_DECLARE(x) x #define V42BIS_MIN_STRING_SIZE 6 #define V42BIS_MAX_STRING_SIZE 250 @@ -55,6 +59,8 @@ V42BIS_COMPRESSION_MODE_ALWAYS, V42BIS_COMPRESSION_MODE_NEVER }; + +typedef void (*put_msg_func_t)(void *user_data, const uint8_t *msg, int len); /*! V.42bis compression/decompression descriptor. This defines the working state for a @@ -111,7 +117,8 @@ \param decode_user_data An opaque pointer passed to the decode callback handler. \param max_decode_len The maximum length that should be passed to the decode handler. \return The V.42bis context. */ -SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, +SPAN_DECLARE(v42bis_state_t *) v42bis_init(const void *ctx, + v42bis_state_t *s, int negotiated_p0, int negotiated_p1, int negotiated_p2, diff --git a/openbsc/include/openbsc/v42bis_private.h b/openbsc/include/openbsc/v42bis_private.h index 2c801eb..daa5ea3 100644 --- a/openbsc/include/openbsc/v42bis_private.h +++ b/openbsc/include/openbsc/v42bis_private.h @@ -120,7 +120,6 @@ v42bis_comp_state_t decompress; /*! \brief Error and flow logging control */ - logging_state_t logging; }; #endif diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 2910c02..f479d56 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -27,7 +27,7 @@ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ - slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c + slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c v42bis.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c index 894ce84..f01798b 100644 --- a/openbsc/src/gprs/sgsn_main.c +++ b/openbsc/src/gprs/sgsn_main.c @@ -297,6 +297,11 @@ .description = "RFC1144 TCP/IP Header compression (SLHC)", .enabled = 1, .loglevel = LOGL_DEBUG, }, + [DV42BIS] = { + .name = "DV42BIS", + .description = "V.42bis data compression (SNDCP)", + .enabled = 1, .loglevel = LOGL_DEBUG, + } }; static const struct log_info gprs_log_info = { diff --git a/openbsc/src/gprs/v42bis.c b/openbsc/src/gprs/v42bis.c index d025ea9..74c6db9 100644 --- a/openbsc/src/gprs/v42bis.c +++ b/openbsc/src/gprs/v42bis.c @@ -29,10 +29,6 @@ /*! \file */ -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - #include #include #include @@ -42,14 +38,13 @@ #include #include -#include "spandsp/telephony.h" -#include "spandsp/logging.h" -#include "spandsp/bit_operations.h" -#include "spandsp/async.h" -#include "spandsp/v42bis.h" +#include +#include +#include +#include -#include "spandsp/private/logging.h" -#include "spandsp/private/v42bis.h" +#define FALSE 0 +#define TRUE 1 /* Fixed parameters from the spec. */ /* Character size (bits) */ @@ -321,7 +316,7 @@ s = &ss->compress; if (!s->transparent) return; - span_log(&ss->logging, SPAN_LOG_FLOW, "Changing to compressed mode\n"); + DEBUGP(DV42BIS,"Changing to compressed mode\n"); /* Switch out of transparent now, between codes. We need to send the octet which did not match, just before switching. */ if (s->last_matched) @@ -344,7 +339,7 @@ s = &ss->compress; if (s->transparent) return; - span_log(&ss->logging, SPAN_LOG_FLOW, "Changing to transparent mode\n"); + DEBUGP(DV42BIS,"Changing to transparent mode\n"); /* Switch into transparent now, between codes, and the unmatched octet should go out in transparent mode, just below */ if (s->last_matched) @@ -543,7 +538,7 @@ { case V42BIS_ECM: /* Enter compressed mode */ - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_ECM\n"); + DEBUGP(DV42BIS,"Hit V42BIS_ECM\n"); send_string(s); s->transparent = FALSE; s->update_at = s->last_matched; @@ -552,20 +547,20 @@ continue; case V42BIS_EID: /* Escape symbol */ - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_EID\n"); + DEBUGP(DV42BIS,"Hit V42BIS_EID\n"); in = s->escape_code; s->escape_code += V42BIS_ESC_STEP; break; case V42BIS_RESET: /* Reset dictionary */ - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_RESET\n"); + DEBUGP(DV42BIS,"Hit V42BIS_RESET\n"); /* TODO: */ send_string(s); dictionary_init(s); i++; continue; default: - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_???? - %" PRIu32 "\n", in); + DEBUGP(DV42BIS,"Hit V42BIS_???? - %" PRIu32 "\n", in); return -1; } } @@ -634,7 +629,7 @@ { case V42BIS_ETM: /* Enter transparent mode */ - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_ETM\n"); + DEBUGP(DV42BIS,"Hit V42BIS_ETM\n"); s->bit_count = 0; s->transparent = TRUE; s->last_matched = 0; @@ -642,12 +637,12 @@ break; case V42BIS_FLUSH: /* Flush signal */ - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_FLUSH\n"); + DEBUGP(DV42BIS,"Hit V42BIS_FLUSH\n"); s->bit_count = 0; break; case V42BIS_STEPUP: /* Increase code word size */ - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_STEPUP\n"); + DEBUGP(DV42BIS,"Hit V42BIS_STEPUP\n"); s->v42bis_parm_c2++; s->v42bis_parm_c3 <<= 1; if (s->v42bis_parm_c2 > (s->v42bis_parm_n2 >> 3)) @@ -708,7 +703,8 @@ } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, +SPAN_DECLARE(v42bis_state_t *) v42bis_init(const void *ctx, + v42bis_state_t *s, int negotiated_p0, int negotiated_p1, int negotiated_p2, @@ -727,12 +723,10 @@ return NULL; if (s == NULL) { - if ((s = (v42bis_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (v42bis_state_t *) talloc_zero_size(ctx,sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); - span_log_init(&s->logging, SPAN_LOG_NONE, NULL); - span_log_set_protocol(&s->logging, "V.42bis"); if ((ret = v42bis_comp_init(&s->compress, negotiated_p1, negotiated_p2, encode_handler, encode_user_data, max_encode_len))) return NULL; @@ -758,6 +752,7 @@ { comp_exit(&s->compress); comp_exit(&s->decompress); + talloc_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index d5aa356..7acebc0 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid slhc +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid slhc v42bis if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index 5f37b8e..f18b734 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -141,3 +141,9 @@ cat $abs_srcdir/slhc/slhc_test.ok > expout AT_CHECK([$abs_top_builddir/tests/slhc/slhc_test], [], [expout], [ignore]) AT_CLEANUP + +AT_SETUP([v42bis]) +AT_KEYWORDS([v42bis]) +cat $abs_srcdir/v42bis/v42bis_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/v42bis/v42bis_test], [], [expout], [ignore]) +AT_CLEANUP diff --git a/openbsc/tests/v42bis/Makefile.am b/openbsc/tests/v42bis/Makefile.am new file mode 100644 index 0000000..9001c0f --- /dev/null +++ b/openbsc/tests/v42bis/Makefile.am @@ -0,0 +1,21 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) + +EXTRA_DIST = v42bis_test.ok + +noinst_PROGRAMS = v42bis_test + +v42bis_test_SOURCES = v42bis_test.c + +v42bis_test_LDADD = \ + $(top_builddir)/src/gprs/v42bis.o \ + $(top_builddir)/src/libcommon/libcommon.a \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOGB_LIBS) \ + $(LIBCARES_LIBS) \ + $(LIBCRYPTO_LIBS) \ + -lgtp -lrt -lm + + diff --git a/openbsc/tests/v42bis/v42bis_test.c b/openbsc/tests/v42bis/v42bis_test.c new file mode 100644 index 0000000..cee000e --- /dev/null +++ b/openbsc/tests/v42bis/v42bis_test.c @@ -0,0 +1,400 @@ +/* Test v42bis Compression/Decompression */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#define P0 3 +#define P1 512 +#define P2 20 + +#define BLOCK_SIZE 1024 +#define MAX_BLOCK_SIZE 1024 + +/* Sample packets to test with */ +#define COMPR_PACKETS_LEN 11 +char *compr_packets[] = { + "4500010268000700004006cefac0a80002550d93d740000050462c7ba7e4d1753a80184000aad500000101080a0001a670084dafb4474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992becf8918d0c9145465441939fcc6a1950a206b7e1fca38e1145eaebc129230aeb24f57bcab011c3c68829f5efe7bfcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0085a3a4e1c3466c6c649ea048d519d5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622e7fa7dac30ac602f9af40a9ef0236a54268247cd7f923946d0a8d1c3c68d1e35788c5002e54ad0a00100", + "4500010268000900004006cef8c0a80002550d93d740000050462c7ba7e4d1753a801840007e7f00000101080a0001d1cc084db0ae474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992becf8918d0c9145465441939fcc6a1950a206b7e1fca38e1145eaebc129230aeb24f57bcab011c3c68829f5efe7bfcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0085a3a4e1c3466c6c649ea048d519d5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622e7fa7dac30ac602f9af40a9ef0236a54268247cd7f923946d0a8d1c3c68d1e35788c5002e54ad0a00100", + "4500010268000b00004006cef6c0a80002550d93d740000050462c7ba7e4d1753b80193fff131c00000101080a00022884084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992be4e8918d8c9045465441939fcc6a1950a206b7e1dca38e1145eaebb929230aeb24f579cab011c3c68829f5efe7afcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0084a3a4e1c3466c6c649ea048dd19c5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622c7fa7dac30ac5c2f9af40a1ef0236a502682478dff913946d0a8d1c3c68d1e35788c5002e54ad0a00100", + "4500010268000c00004006cef5c0a80002550d93d740000050462c7ba7e4d1753b80193fff65ab00000101080a0002d5f4084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992be4e8918d8c9045465441939fcc6a1950a206b7e1dca38e1145eaebb929230aeb24f579cab011c3c68829f5efe7afcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0084a3a4e1c3466c6c649ea048dd19c5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622c7fa7dac30ac5c2f9af40a1ef0236a502682478dff913946d0a8d1c3c68d1e35788c5002e54ad0a00100", + "450001022d000f00004006ac5ec0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00", + "450001022d001000004006ac5dc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00", + "450001022d001100004006ac5cc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00", + "450001022d001200004006ac5bc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00", + "4500010268001300004006ceeec0a80002550d93d740000050462c7ba7e4d1753b80193fff7b4a00000101080a0003c054084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005bbb7e0d3b964dd9b369d7b6ddb3e60e9c372ef614beeb15ac58b2660513368cf8cdd63b68f65045ab96ed9cb58947b490d1422851a34861185923d50e9aa423f0dc490363c756d8b269e4d8cac68e9cd93b70f0804143376fe13372dcc801038f193b306a6cb5b2864d9a3b629a30b1b2b5081b353848173d7a07c6133271d4e021a3068d52347184ee81c119c69c3a72d2b079c37e4489c177e6f4902183730cde71f8a0a913d6cec21866e4c091818548fdfb329cec9831834d951a337e4e2e2174891c3baef5e8d113a38f1c336e2656148a85751d1844d6c7716da52c1f240f9b2fecf8918d0c9145465441a39f0c6b1950a40ab7f1fca38e1145ecebc129234aeb24f67bcab011c3c68829f6f1ebb7cbe4c894e731668c3052163ffa3a63d9949561e4c91123c263d0105a3a4e1c3466c8c651ea04cd519d60f3a0016f14290c2471289e61735ee9193469de8c45b3554d1fa84299c88622e73afeac30ac6037aaf40a9ef0236a54268247cd7f923946d0a8d1c3c68d1e35788c5002e58a50a10100", + "450001022d001400004006ac59c0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00", + "450001022d001500004006ac58c0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00", +}; + +#define UNCOMPR_PACKETS_LEN 6 +char *uncompr_packets[] = { + "45000236000700004006cf2cc0a80002550d93d7400000501e200da7c0c95a70801840002e3700000101080a000174140853d489474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a", + "4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27", + "4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0", + "4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01", + "4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01", + "4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a", + "4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20" +}; + +/* Calculate IP Header checksum */ +static uint16_t calc_ip_csum(uint8_t *data, int len) +{ + int i; + uint32_t accumulator = 0; + uint16_t *pointer = (uint16_t *) data; + + for (i = len; i > 1; i -= 2) { + accumulator += *pointer; + pointer++; + } + + if (len % 2) + accumulator += *pointer; + + accumulator = (accumulator & 0xffff) + ((accumulator >> 16) & 0xffff); + accumulator += (accumulator >> 16) & 0xffff; + return (~accumulator); +} + +/* Calculate TCP/IP checksum */ +static uint16_t calc_tcpip_csum(const void *ctx, uint8_t *packet, int len) +{ + uint8_t *buf; + uint16_t csum; + + buf = talloc_zero_size(ctx, len); + memset(buf, 0, len); + memcpy(buf, packet + 12, 8); + buf[9] = packet[9]; + buf[11] = (len - 20) & 0xFF; + buf[10] = (len - 20) >> 8 & 0xFF; + memcpy(buf + 12, packet + 20, len - 20); + csum = calc_ip_csum(buf, len - 20 + 12); + talloc_free(buf); + return csum; +} + +/* A simple function to show the ascii content of a packet */ +void show_packet(uint8_t *packet, int len) +{ + int i; + char c; + for (i = 0; i < len; i++) { + c = packet[i]; + if (c >= 0x20 && c <= 0x7E) + printf("%c", c); + else + printf("."); + } + printf("\n"); +} + +/* A struct to capture the output data of compressor and decompressor */ +struct v42bis_output_buffer { + uint8_t *buf; + uint8_t *buf_pointer; + int len; +}; + +/* A simple testpattern generator */ +static void gen_test_pattern(uint8_t *data, int len) +{ + int i; + for (i = 0; i < len; i++) + data[i] = i & 0xF0; +} + +/* Handler to capture the output data from the compressor */ +void tx_v42bis_frame_handler(void *user_data, const uint8_t *pkt, int len) +{ + struct v42bis_output_buffer *output_buffer = + (struct v42bis_output_buffer *)user_data; + memcpy(output_buffer->buf_pointer, pkt, len); + output_buffer->buf_pointer += len; + output_buffer->len += len; + return; +} + +/* Handler to capture the output data from the decompressor */ +void tx_v42bis_data_handler(void *user_data, const uint8_t *buf, int len) +{ + /* stub, never used */ + OSMO_ASSERT(false); + return; +} + +/* Handler to capture the output data from the compressor */ +void rx_v42bis_frame_handler(void *user_data, const uint8_t *pkt, int len) +{ + /* stub, never used */ + OSMO_ASSERT(false); + return; +} + +/* Handler to capture the output data from the decompressor */ +void rx_v42bis_data_handler(void *user_data, const uint8_t *buf, int len) +{ + struct v42bis_output_buffer *output_buffer = + (struct v42bis_output_buffer *)user_data; + memcpy(output_buffer->buf_pointer, buf, len); + output_buffer->buf_pointer += len; + output_buffer->len += len; + return; +} + +/* Test V.42bis compression and decompression */ +static void v42bis(const void *ctx, int mode, uint8_t *testvec, int len) +{ + v42bis_state_t *tx_state; + v42bis_state_t *rx_state; + uint8_t *uncompressed_original; + uint8_t *compressed; + uint8_t *uncompressed; + + uncompressed_original = talloc_zero_size(ctx, len); + uncompressed = talloc_zero_size(ctx, len); + + /* Note: We allocate double the size for the compressed buffer, + * because in some cases the compression may increase the amount. + * of data. */ + compressed = talloc_zero_size(ctx, len * 2); + + int rc; + int rc_sum = 0; + struct v42bis_output_buffer compressed_data; + struct v42bis_output_buffer uncompressed_data; + + /* Initalize */ + tx_state = + v42bis_init(ctx, NULL, P0, P1, P2, + &tx_v42bis_frame_handler, NULL, MAX_BLOCK_SIZE, + &tx_v42bis_data_handler, NULL, MAX_BLOCK_SIZE); + OSMO_ASSERT(tx_state); + rx_state = + v42bis_init(ctx, NULL, P0, P1, P2, + &rx_v42bis_frame_handler, NULL, MAX_BLOCK_SIZE, + &rx_v42bis_data_handler, NULL, MAX_BLOCK_SIZE); + OSMO_ASSERT(rx_state); + v42bis_compression_control(tx_state, mode); + + /* Setup input data */ + memcpy(uncompressed_original, testvec, len); + + /* Run compressor */ + compressed_data.buf = compressed; + compressed_data.buf_pointer = compressed; + compressed_data.len = 0; + tx_state->compress.user_data = (&compressed_data); + rc = v42bis_compress(tx_state, uncompressed_original, len); + printf("v42bis_compress() rc=%d\n", rc); + OSMO_ASSERT(rc == 0); + rc = v42bis_compress_flush(tx_state); + printf("v42bis_compress_flush() rc=%d\n", rc); + OSMO_ASSERT(rc == 0); + + /* Decompress again */ + uncompressed_data.buf = uncompressed; + uncompressed_data.buf_pointer = uncompressed; + uncompressed_data.len = 0; + rx_state->decompress.user_data = (&uncompressed_data); + rc = v42bis_decompress(rx_state, compressed_data.buf, + compressed_data.len); + printf("v42bis_decompress() rc=%d\n", rc); + rc = v42bis_decompress_flush(rx_state); + rc_sum += rc; + printf("v42bis_decompress_flush() rc=%d\n", rc); + rc_sum += rc; + + /* Check results */ + printf("Mode: %i\n", mode); + + printf("uncompressed_original= %s ASCII:", + osmo_hexdump_nospc(uncompressed_original, len)); + show_packet(uncompressed_original, len); + printf("uncompressed= %s ASCII:", + osmo_hexdump_nospc(uncompressed_data.buf, + uncompressed_data.len)); + show_packet(uncompressed_data.buf, uncompressed_data.len); + printf("compressed= %s ASCII:", + osmo_hexdump_nospc(compressed_data.buf, compressed_data.len)); + show_packet(compressed_data.buf, compressed_data.len); + + rc = memcmp(uncompressed, uncompressed_original, len); + printf("memcmp() rc=%d\n", rc); + rc_sum += rc; + OSMO_ASSERT(rc_sum == 0); + + /* Free buffers and exit */ + v42bis_free(tx_state); + v42bis_free(rx_state); + talloc_free(uncompressed_original); + talloc_free(compressed); + talloc_free(uncompressed); + printf("\n"); +} + +/* Test V.42bis compression and decompression with generated data*/ +static void test_v42bis(const void *ctx) +{ + printf("Testing compression/decompression with generated data:\n"); + uint8_t testvec[BLOCK_SIZE]; + int len = sizeof(testvec); + gen_test_pattern(testvec, len); + v42bis(ctx, V42BIS_COMPRESSION_MODE_DYNAMIC, testvec, len); + v42bis(ctx, V42BIS_COMPRESSION_MODE_NEVER, testvec, len); + v42bis(ctx, V42BIS_COMPRESSION_MODE_ALWAYS, testvec, len); +} + +/* Test V.42bis compression and decompression with some TCP/IP packets */ +static void test_v42bis_tcpip(const void *ctx, int packet_id) +{ + uint8_t *testvec; + int len; + printf("Testing compression/decompression with TCP/IP packet:\n"); + printf("Packet No.: %i\n", packet_id); + len = strlen(uncompr_packets[packet_id]); + testvec = talloc_zero_size(ctx, len); + len = osmo_hexparse(uncompr_packets[packet_id], testvec, len); + v42bis(ctx, V42BIS_COMPRESSION_MODE_DYNAMIC, testvec, len); + v42bis(ctx, V42BIS_COMPRESSION_MODE_NEVER, testvec, len); + v42bis(ctx, V42BIS_COMPRESSION_MODE_ALWAYS, testvec, len); + talloc_free(testvec); +} + +/* Test V.42bis decompression with real, sniffed packets */ +static void test_v42bis_tcpip_decompress(const void *ctx, int packet_id) +{ + uint8_t *compressed; + int compressed_len; + uint8_t *uncompressed; + v42bis_state_t *rx_state; + int rc; + int rc_sum = 0; + int len; + struct v42bis_output_buffer uncompressed_data; + + printf("Testing decompression with compressed TCP/IP packets:\n"); + printf("Packet No.: %i\n", packet_id); + len = strlen(compr_packets[packet_id]); + + uncompressed = talloc_zero_size(ctx, len); + compressed = talloc_zero_size(ctx, len); + + /* Initalize */ + rx_state = + v42bis_init(ctx, NULL, P0, P1, P2, + &rx_v42bis_frame_handler, NULL, MAX_BLOCK_SIZE, + &rx_v42bis_data_handler, NULL, MAX_BLOCK_SIZE); + OSMO_ASSERT(rx_state); + + /* Setup input data */ + compressed_len = + osmo_hexparse(compr_packets[packet_id], compressed, len); + + /* Decompress */ + uncompressed_data.buf = uncompressed; + uncompressed_data.buf_pointer = uncompressed; + uncompressed_data.len = 0; + rx_state->decompress.user_data = (&uncompressed_data); + rc = v42bis_decompress_flush(rx_state); + printf("v42bis_decompress_flush() rc=%d\n", rc); + rc_sum += rc; + rc = v42bis_decompress(rx_state, compressed, compressed_len); + printf("v42bis_decompress() rc=%d\n", rc); + rc_sum += rc; + rc = v42bis_decompress_flush(rx_state); + printf("v42bis_decompress_flush() rc=%d\n", rc); + rc_sum += rc; + + /* Check results */ + printf("compressed= %s ASCII:", + osmo_hexdump_nospc(compressed, compressed_len)); + show_packet(compressed, compressed_len); + printf("uncompressed= %s ASCII:", + osmo_hexdump_nospc(uncompressed_data.buf, + uncompressed_data.len)); + show_packet(uncompressed_data.buf, uncompressed_data.len); + + OSMO_ASSERT(calc_ip_csum(uncompressed_data.buf, 20) == 0); + OSMO_ASSERT(calc_tcpip_csum(ctx, uncompressed_data.buf, + uncompressed_data.len) == 0); + + /* Free buffers and exit */ + v42bis_free(rx_state); + talloc_free(uncompressed); + talloc_free(compressed); + printf("\n"); +} + +static struct log_info_cat gprs_categories[] = { + [DV42BIS] = { + .name = "DV42BIS", + .description = "V.42bis data compression (SNDCP)", + .enabled = 1,.loglevel = LOGL_DEBUG, + } +}; + +static struct log_info info = { + .cat = gprs_categories, + .num_cat = ARRAY_SIZE(gprs_categories), +}; + +int main(int argc, char **argv) +{ + void *v42bis_ctx; + int i; + + osmo_init_logging(&info); + + v42bis_ctx = talloc_named_const(NULL, 0, "v42bis_ctx"); + + test_v42bis(v42bis_ctx); + + for (i = 0; i < UNCOMPR_PACKETS_LEN; i++) + test_v42bis_tcpip(v42bis_ctx, i); + + for (i = 0; i < COMPR_PACKETS_LEN; i++) + test_v42bis_tcpip_decompress(v42bis_ctx, i); + + printf("Done\n"); + talloc_report_full(v42bis_ctx, stderr); + OSMO_ASSERT(talloc_total_blocks(v42bis_ctx) == 1); + return 0; +} + +/* stubs */ +struct osmo_prim_hdr; +int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) +{ + abort(); +} diff --git a/openbsc/tests/v42bis/v42bis_test.ok b/openbsc/tests/v42bis/v42bis_test.ok new file mode 100644 index 0000000..a00b9d5 --- /dev/null +++ b/openbsc/tests/v42bis/v42bis_test.ok @@ -0,0 +1,312 @@ +Testing compression/decompression with generated data: +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 0 +uncompressed_original= 00000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0 ASCII:................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................ +uncompressed= 00000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0 ASCII:................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................ +compressed= 000100000000000000003300040b4e9870f020428409478c58b89021c38633663c7c081162c42143264ea448b1e29429172f62c49871cc988d1b3972ec3867cec78f2041861c3468e44892244b4e9a74f2244a9429478d5ab99225cb96b366bd7c091366cc61c366cea449b3e6b469376fe2c49973dcb89d3b79f2ec396fdecf9f4081062d587028c184098d226cd83029c388119942ac58f129c58c19a562ecd8b12ac79021b1822c59722bc99429bda26cd9322ccb9831c9c2ac59f32ccd9c39d5e2ecd9b32dcfa041e102254ad4e0d1a348952a5ddab4a953a850a34e9d4ad5aad5ab59b36ae5cab5ebd7af60c58a1d5bb6ac59b468d3ae5dcbd6addbb771e3ca9d3b7740ddba07efde5d9837efc3bd7b27f6ed7bf1efdf8d81037f1c3c7864e1c2270f1f5e9938f1cbc58b67366e7cf3f1e39d9123ff0c00 ASCII:..........3...N.p. B..G.X..!..3f<|..b.!C&N.H...)./b..q....9r.8g... A..4h.H.$KN.t.$J.)G.Z..%...f.|..f.a.f..I...i7o...s...;y..9o... at ..-Xp(...."l.0)....B.X.)....b...*..!..,Yr+..)..l.2,..1...Y.,..9.....-..A..%J....H.*]...S.P.N.J....Y.j......`...[..Y.h..].....q...;w at .....].7...{'..{..........wb.......8....G..|.......\.xf..7.?..9... +memcmp() rc=0 + +Testing compression/decompression with TCP/IP packet: +Packet No.: 0 +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 0 +uncompressed_original= 45000236000700004006cf2cc0a80002550d93d7400000501e200da7c0c95a70801840002e3700000101080a000174140853d489474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..6.... at ..,....U... at ..P. ....Zp.. at ..7........t..S..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... +uncompressed= 45000236000700004006cf2cc0a80002550d93d7400000501e200da7c0c95a70801840002e3700000101080a000174140853d489474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..6.... at ..,....U... at ..P. ....Zp.. at ..7........t..S..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... +compressed= 4500010236000700004006cf2cc0a80002550d93d7400000501e200da7c0c95a70801840002e3700000101080a000174140853d489474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c6963330062d990358b562ddb3d6beec079e3620f61bb5dbf861d5b36f0e0c287df68bd8366cfd4b369d7ce518b78440b192d820e2d7a1486913551eda0413a02cf9d343076687d1d9b460ead6cecc891bd03070f183472ef0e3e23c78d1c30f098b103a386562b6bd8a4b923a609132b5a8bb05183633451a377603c2113470d1e326ad024451327e81e189b61cca923270d9b37eb4794107c674e0f193236c7d81d870f9a3a60ed288c61460e1c195888d0b72fc3c98e1933d854a931c3a7e4124197c8b1d35a8f1e3d31fac831e34622c5a05856d78141447d9cd656c8f241e290b9c28e1fd9c8105964441534f9c9ac9601256a701bce3fea1851a4be1e9c32a2b04e52bfa70c1b316c8c9852ff7efebb4c8e4c711e63c6082364ef9faf23960d5919469e1c31123c068da0a5e3c44163666c9ca44ed018d5f9350f9aef458fc2401267e21936e6939e4193e68d58345ad5f4791a346800 ASCII:E...6.... at ..,....U... at ..P. ....Zp.. at ..7........t..S..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, applic3.b..5.V-.=k..y.b.a.]...[6.....h..f...i..Q.xD..-..-z...5Q..A:...40vh}..F..l........4r..>#...0......V+k...#...+Z..Q.c4Q.w`r...H1(..u`.Q.....|.8d...G62D..Q.M~2.e at ......:F......(....).F..#.......#S...1.......eCV..'G...A#h.8q....'..4Fu~...{..0...x....g..y#..V5}..... +memcmp() rc=0 + +Testing compression/decompression with TCP/IP packet: +Packet No.: 1 +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 0 +uncompressed_original= 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E.. at F.@. at .....dn..dd...........M....*.........G....^..... ..#..' +uncompressed= 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E.. at F.@. at .....dn..dd...........M....*.........G....^..... ..#..' +compressed= 451000014046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E... at F.@. at .....dn..dd...........M....*.........G....^..... ..#..' +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 2 +uncompressed_original= 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E.. at F.@. at .....dn..dd...........M....*.........G....^..... ..#..' +uncompressed= 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E.. at F.@. at .....dn..dd...........M....*.........G....^..... ..#..' +compressed= 451000014046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E... at F.@. at .....dn..dd...........M....*.........G....^..... ..#..' +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 1 +uncompressed_original= 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E.. at F.@. at .....dn..dd...........M....*.........G....^..... ..#..' +uncompressed= 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E.. at F.@. at .....dn..dd...........M....*.........G....^..... ..#..' +compressed= 45000013060c49026e48c104ac540d5b75268ec33367066880e588d0260203ecbdda0465d08601e65a641830800081050d062450122e013561610402dc5073444d1335550400 ASCII:E.....I.nH...T.[u&..3g.h....&......e....Zd.0......$P...5aa...PsDM.5U.. +memcmp() rc=0 + +Testing compression/decompression with TCP/IP packet: +Packet No.: 2 +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 0 +uncompressed_original= 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E..[F. at .@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... +uncompressed= 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E..[F. at .@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... +compressed= 451000015b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E...[F. at .@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 2 +uncompressed_original= 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E..[F. at .@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... +uncompressed= 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E..[F. at .@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... +compressed= 451000015b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E...[F. at .@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 1 +uncompressed_original= 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E..[F. at .@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... +uncompressed= 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E..[F. at .@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... +compressed= 45000013067849126ec880210958391ab6ea4c9c8767ce0cd000cb11a14d041ed87bb509caa00d03cc25c233600001020b1a0c48a0445c026ac2c808f467402040113949080c58c2260281fd461010386fa809a348fba9583a74c3d200 ASCII:E....xI.n..!.X9...L..g.......M...{.......%.3`......H.D\.j....g@ @.9I..X.&...F..8o...H..X:t... +memcmp() rc=0 + +Testing compression/decompression with TCP/IP packet: +Packet No.: 3 +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 0 +uncompressed_original= 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E..7F. at .@.....dn..dd.......3........_.........G....c... +uncompressed= 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E..7F. at .@.....dn..dd.......3........_.........G....c... +compressed= 451000013746df40004006a9aec0a8646ec0a864640017ad8b8198013301f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E...7F. at .@.....dn..dd.......3........._.........G....c... +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 2 +uncompressed_original= 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E..7F. at .@.....dn..dd.......3........_.........G....c... +uncompressed= 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E..7F. at .@.....dn..dd.......3........_.........G....c... +compressed= 451000013746df40004006a9aec0a8646ec0a864640017ad8b8198013301f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E...7F. at .@.....dn..dd.......3........._.........G....c... +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 1 +uncompressed_original= 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E..7F. at .@.....dn..dd.......3........_.........G....c... +uncompressed= 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E..7F. at .@.....dn..dd.......3........_.........G....c... +compressed= 4500001306e848226ec880210958c51ab6ea4c9c8767ce0cd000cb11a14d046cd87bb549d4a00d03cc89d136600001020b1a0c48a0845c026ac2cc0804482000 ASCII:E.....H"n..!.X....L..g.......M.l.{.I.......6`......H..\.j....H . +memcmp() rc=0 + +Testing compression/decompression with TCP/IP packet: +Packet No.: 4 +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 0 +uncompressed_original= 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E..7F. at .@.....dn..dd.......6........_.........G....d... +uncompressed= 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E..7F. at .@.....dn..dd.......6........_.........G....d... +compressed= 451000013746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E...7F. at .@.....dn..dd.......6........_.........G....d... +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 2 +uncompressed_original= 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E..7F. at .@.....dn..dd.......6........_.........G....d... +uncompressed= 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E..7F. at .@.....dn..dd.......6........_.........G....d... +compressed= 451000013746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E...7F. at .@.....dn..dd.......6........_.........G....d... +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 1 +uncompressed_original= 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E..7F. at .@.....dn..dd.......6........_.........G....d... +uncompressed= 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E..7F. at .@.....dn..dd.......6........_.........G....d... +compressed= 4500001306e848326ec880210958c11ab6ea4c9c8767ce0cd000cb11a14d0472d87bb5a9d4a00d03cc89a936600001020b1a0c48a0845c026ac2ce08f4472000 ASCII:E.....H2n..!.X....L..g.......M.r.{.........6`......H..\.j....G . +memcmp() rc=0 + +Testing compression/decompression with TCP/IP packet: +Packet No.: 5 +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 0 +uncompressed_original= 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E..tF. at .@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... +uncompressed= 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E..tF. at .@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... +compressed= 451000017446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d3300386d6a41f3e68d193970d08cb82367c41c3940f1ecb1b97327549e0d6c0600 ASCII:E...tF. at .@..o..dn..dd.......9........{.........G....d..----------------3.8mjA....9p...#g..9 at ....s'T..l.. +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 2 +uncompressed_original= 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E..tF. at .@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... +uncompressed= 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E..tF. at .@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... +compressed= 451000017446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E...tF. at .@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 1 +uncompressed_original= 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E..tF. at .@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... +uncompressed= 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E..tF. at .@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... +compressed= 4500001306dc49426ec880210958c919b6ea4c9c8767ce0cd000cb11a14d0478d87bb509d5a00d03ccf9f134600001020b1a0c48a0a45c026ac2ce40680003064e9c3973eac469530b9a376fccc8818366c41d3923e6c8018a678fcd9d3ba1f26c603300 ASCII:E.....IBn..!.X....L..g.......M.x.{.........4`......H..\.j.. at h...N.9s..iS..7o....f..9#....g...;..l`3. +memcmp() rc=0 + +Testing decompression with compressed TCP/IP packets: +Packet No.: 0 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010268000700004006cefac0a80002550d93d740000050462c7ba7e4d1753a80184000aad500000101080a0001a670084dafb4474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992becf8918d0c9145465441939fcc6a1950a206b7e1fca38e1145eaebc129230aeb24f57bcab011c3c68829f5efe7bfcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0085a3a4e1c3466c6c649ea048d519d5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622e7fa7dac30ac602f9af40a9ef0236a54268247cd7f923946d0a8d1c3c68d1e35788c5002e54ad0a00100 ASCII:E...h.... at .......U...@..PF,{...u:.. at ............p.M..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed3.Z.z.+..Y.h.......7......k..e...|...;h.L=.v....G..."...Ga.Y.....#..I.c....i.......;p..A#...3r......;0jh...M.;b.0.....58F.5z...2q..!..MR4q.......:r..y.~D..w...!cs..q........f......}.2...1.M..3|J..t..;........3n$R..eu..D..im.,.$..+......EFTA...j.P........E...)#..$.{......).........1f.0B...:b...a...#.c..Z:N.4f..I...Q._...^.(.$q&.ac>..4i..E.UM..A..."..}.0.`/.....#jT&.G...9F.......5x.P..J.... +uncompressed= 45000268000700004006cefac0a80002550d93d740000050462c7ba7e4d1753a80184000aad500000101080a0001a670084dafb4474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a49662d4d6f6469666965642d53696e63653a205475652c2032332041756720323031362031323a33343a323920474d540d0a0d0a ASCII:E..h.... at .......U...@..PF,{...u:.. at ............p.M..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..If-Modified-Since: Tue, 23 Aug 2016 12:34:29 GMT.... + +Testing decompression with compressed TCP/IP packets: +Packet No.: 1 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010268000900004006cef8c0a80002550d93d740000050462c7ba7e4d1753a801840007e7f00000101080a0001d1cc084db0ae474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992becf8918d0c9145465441939fcc6a1950a206b7e1fca38e1145eaebc129230aeb24f57bcab011c3c68829f5efe7bfcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0085a3a4e1c3466c6c649ea048d519d5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622e7fa7dac30ac602f9af40a9ef0236a54268247cd7f923946d0a8d1c3c68d1e35788c5002e54ad0a00100 ASCII:E...h.... at .......U...@..PF,{...u:.. at .~............M..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed3.Z.z.+..Y.h.......7......k..e...|...;h.L=.v....G..."...Ga.Y.....#..I.c....i.......;p..A#...3r......;0jh...M.;b.0.....58F.5z...2q..!..MR4q.......:r..y.~D..w...!cs..q........f......}.2...1.M..3|J..t..;........3n$R..eu..D..im.,.$..+......EFTA...j.P........E...)#..$.{......).........1f.0B...:b...a...#.c..Z:N.4f..I...Q._...^.(.$q&.ac>..4i..E.UM..A..."..}.0.`/.....#jT&.G...9F.......5x.P..J.... +uncompressed= 45000268000900004006cef8c0a80002550d93d740000050462c7ba7e4d1753a801840007e7f00000101080a0001d1cc084db0ae474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a49662d4d6f6469666965642d53696e63653a205475652c2032332041756720323031362031323a33343a323920474d540d0a0d0a ASCII:E..h.... at .......U...@..PF,{...u:.. at .~............M..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..If-Modified-Since: Tue, 23 Aug 2016 12:34:29 GMT.... + +Testing decompression with compressed TCP/IP packets: +Packet No.: 2 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010268000b00004006cef6c0a80002550d93d740000050462c7ba7e4d1753b80193fff131c00000101080a00022884084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992be4e8918d8c9045465441939fcc6a1950a206b7e1dca38e1145eaebb929230aeb24f579cab011c3c68829f5efe7afcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0084a3a4e1c3466c6c649ea048dd19c5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622c7fa7dac30ac5c2f9af40a1ef0236a502682478dff913946d0a8d1c3c68d1e35788c5002e54ad0a00100 ASCII:E...h.... at .......U...@..PF,{...u;..?...........(..M.XGET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed3.Z.z.+..Y.h.......7......k..e...|...;h.L=.v....G..."...Ga.Y.....#..I.c....i.......;p..A#...3r......;0jh...M.;b.0.....58F.5z...2q..!..MR4q.......:r..y.~D..w...!cs..q........f......}.2...1.M..3|J..t..;........3n$R..eu..D..im.,.$..+......EFTA...j.P........E...)#..$.y......).........1f.0B...:b...a...#.c..J:N.4f..I....._...^.(.$q&.ac>..4i..E.UM..A..."..}.0.\/.....#jP&.G...9F.......5x.P..J.... +uncompressed= 45000268000b00004006cef6c0a80002550d93d740000050462c7ba7e4d1753b80193fff131c00000101080a00022884084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a49662d4d6f6469666965642d53696e63653a205475652c2032332041756720323031362031323a33343a323920474d540d0a0d0a ASCII:E..h.... at .......U...@..PF,{...u;..?...........(..M.XGET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..If-Modified-Since: Tue, 23 Aug 2016 12:34:29 GMT.... + +Testing decompression with compressed TCP/IP packets: +Packet No.: 3 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010268000c00004006cef5c0a80002550d93d740000050462c7ba7e4d1753b80193fff65ab00000101080a0002d5f4084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992be4e8918d8c9045465441939fcc6a1950a206b7e1dca38e1145eaebb929230aeb24f579cab011c3c68829f5efe7afcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0084a3a4e1c3466c6c649ea048dd19c5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622c7fa7dac30ac5c2f9af40a1ef0236a502682478dff913946d0a8d1c3c68d1e35788c5002e54ad0a00100 ASCII:E...h.... at .......U...@..PF,{...u;..?.e............M.XGET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed3.Z.z.+..Y.h.......7......k..e...|...;h.L=.v....G..."...Ga.Y.....#..I.c....i.......;p..A#...3r......;0jh...M.;b.0.....58F.5z...2q..!..MR4q.......:r..y.~D..w...!cs..q........f......}.2...1.M..3|J..t..;........3n$R..eu..D..im.,.$..+......EFTA...j.P........E...)#..$.y......).........1f.0B...:b...a...#.c..J:N.4f..I....._...^.(.$q&.ac>..4i..E.UM..A..."..}.0.\/.....#jP&.G...9F.......5x.P..J.... +uncompressed= 45000268000c00004006cef5c0a80002550d93d740000050462c7ba7e4d1753b80193fff65ab00000101080a0002d5f4084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a49662d4d6f6469666965642d53696e63653a205475652c2032332041756720323031362031323a33343a323920474d540d0a0d0a ASCII:E..h.... at .......U...@..PF,{...u;..?.e............M.XGET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..If-Modified-Since: Tue, 23 Aug 2016 12:34:29 GMT.... + +Testing decompression with compressed TCP/IP packets: +Packet No.: 4 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 450001022d000f00004006ac5ec0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00 ASCII:E...-.... at ..^........ at ..@F.......P. at ..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application3.\....g..8o\...vj..Y........w..I..k.9`..h!....;{.0....4>G........O......9.w........g......3v`..je..4w.4ab.j.6jpd.....'d...CF...h....#2.9u..a.&...x...!CF.....AS....1...#.....e8.1c..*5f.D\...9vF....G..:h..H.&..u`...g...|...._"E62...Q..{2.e at 9z..q.:F.Y....(....).F..#..o..-.#S...1......`e.U..'G...y.s.8h.d......1..AS}gO.H. <....3h.......>Eo... +uncompressed= 4500022d000f00004006ac5ec0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a2031302e392e312e3137313a383030300d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..-.... at ..^........ at ..@F.......P. at ..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: 10.9.1.171:8000..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... + +Testing decompression with compressed TCP/IP packets: +Packet No.: 5 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 450001022d001000004006ac5dc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00 ASCII:E...-.... at ..]........ at ..@F.......P. at ..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application3.\....g..8o\...vj..Y........w..I..k.9`..h!....;{.0....4>G........O......9.w........g......3v`..je..4w.4ab.j.6jpd.....'d...CF...h....#2.9u..a.&...x...!CF.....AS....1...#.....e8.1c..*5f.D\...9vF....G..:h..H.&..u`...g...|...._"E62...Q..{2.e at 9z..q.:F.Y....(....).F..#..o..-.#S...1......`e.U..'G...y.s.8h.d......1..AS}gO.H. <....3h.......>Eo... +uncompressed= 4500022d001000004006ac5dc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a2031302e392e312e3137313a383030300d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..-.... at ..]........ at ..@F.......P. at ..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: 10.9.1.171:8000..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... + +Testing decompression with compressed TCP/IP packets: +Packet No.: 6 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 450001022d001100004006ac5cc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00 ASCII:E...-.... at ..\........ at ..@F.......P. at ..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application3.\....g..8o\...vj..Y........w..I..k.9`..h!....;{.0....4>G........O......9.w........g......3v`..je..4w.4ab.j.6jpd.....'d...CF...h....#2.9u..a.&...x...!CF.....AS....1...#.....e8.1c..*5f.D\...9vF....G..:h..H.&..u`...g...|...._"E62...Q..{2.e at 9z..q.:F.Y....(....).F..#..o..-.#S...1......`e.U..'G...y.s.8h.d......1..AS}gO.H. <....3h.......>Eo... +uncompressed= 4500022d001100004006ac5cc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a2031302e392e312e3137313a383030300d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..-.... at ..\........ at ..@F.......P. at ..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: 10.9.1.171:8000..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... + +Testing decompression with compressed TCP/IP packets: +Packet No.: 7 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 450001022d001200004006ac5bc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00 ASCII:E...-.... at ..[........ at ..@F.......P. at ..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application3.\....g..8o\...vj..Y........w..I..k.9`..h!....;{.0....4>G........O......9.w........g......3v`..je..4w.4ab.j.6jpd.....'d...CF...h....#2.9u..a.&...x...!CF.....AS....1...#.....e8.1c..*5f.D\...9vF....G..:h..H.&..u`...g...|...._"E62...Q..{2.e at 9z..q.:F.Y....(....).F..#..o..-.#S...1......`e.U..'G...y.s.8h.d......1..AS}gO.H. <....3h.......>Eo... +uncompressed= 4500022d001200004006ac5bc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a2031302e392e312e3137313a383030300d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..-.... at ..[........ at ..@F.......P. at ..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: 10.9.1.171:8000..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... + +Testing decompression with compressed TCP/IP packets: +Packet No.: 8 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010268001300004006ceeec0a80002550d93d740000050462c7ba7e4d1753b80193fff7b4a00000101080a0003c054084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005bbb7e0d3b964dd9b369d7b6ddb3e60e9c372ef614beeb15ac58b2660513368cf8cdd63b68f65045ab96ed9cb58947b490d1422851a34861185923d50e9aa423f0dc490363c756d8b269e4d8cac68e9cd93b70f0804143376fe13372dcc801038f193b306a6cb5b2864d9a3b629a30b1b2b5081b353848173d7a07c6133271d4e021a3068d52347184ee81c119c69c3a72d2b079c37e4489c177e6f4902183730cde71f8a0a913d6cec21866e4c091818548fdfb329cec9831834d951a337e4e2e2174891c3baef5e8d113a38f1c336e2656148a85751d1844d6c7716da52c1f240f9b2fecf8918d0c9145465441a39f0c6b1950a40ab7f1fca38e1145ecebc129234aeb24f67bcab011c3c68829f6f1ebb7cbe4c894e731668c3052163ffa3a63d9949561e4c91123c263d0105a3a4e1c3466c8c651ea04cd519d60f3a0016f14290c2471289e61735ee9193469de8c45b3554d1fa84299c88622e73afeac30ac6037aaf40a9ef0236a54268247cd7f923946d0a8d1c3c68d1e35788c5002e58a50a10100 ASCII:E...h.... at .......U...@..PF,{...u;..?.{J.........T.M.XGET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed3.[.~.;.M..i.......7.......X.f..6....;h.PE......G...B(Q.Ha.Y#....#..I.c.V..i.......;p..AC7o.3r......;0jl...M.;b.0.....58H.=z...2q..!...R4q.......:r..y.~D..w...!.s..q........f.....H..2...1.M..3~N.!t..;........3n&V...u..D..qm.,.$../......EFTA...k.P........E...)#J.$.{......).........1f.0R.?.:c...a...#.c..Z:N.4f..Q...Q.`...o.).$q(.as^..4i..E.UM..B...".:..0.`7.....#jT&.G...9F.......5x.P...P... +uncompressed= 45000268001300004006ceeec0a80002550d93d740000050462c7ba7e4d1753b80193fff7b4a00000101080a0003c054084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a49662d4d6f6469666965642d53696e63653a205475652c2032332041756720323031362031323a33343a323920474d540d0a0d0a ASCII:E..h.... at .......U...@..PF,{...u;..?.{J.........T.M.XGET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..If-Modified-Since: Tue, 23 Aug 2016 12:34:29 GMT.... + +Testing decompression with compressed TCP/IP packets: +Packet No.: 9 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 450001022d001400004006ac59c0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00 ASCII:E...-.... at ..Y........@.. at F.......P.@..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application3.\....g..8o\...vj..Y........w..I..k.9`..h!....;{.0....4>G........O......9.w........g......3v`..je..4w.4ab.j.6jpd.....'d...CF...h....#2.9u..a.&...x...!CF.....AS....1...#.....e8.1c..*5f.D\...9vF....G..:h..H.&..u`...g...|...._"E62...Q..{2.e at 9z..q.:F.Y....(....).F..#..o..-.#S...1......`e.U..'G...y.s.8h.d......1..AS}gO.H. <....3h.......>Eo... +uncompressed= 4500022d001400004006ac59c0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a2031302e392e312e3137313a383030300d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..-.... at ..Y........@.. at F.......P.@..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: 10.9.1.171:8000..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... + +Testing decompression with compressed TCP/IP packets: +Packet No.: 10 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 450001022d001500004006ac58c0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00 ASCII:E...-.... at ..X........@.. at F.......P.@..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application3.\....g..8o\...vj..Y........w..I..k.9`..h!....;{.0....4>G........O......9.w........g......3v`..je..4w.4ab.j.6jpd.....'d...CF...h....#2.9u..a.&...x...!CF.....AS....1...#.....e8.1c..*5f.D\...9vF....G..:h..H.&..u`...g...|...._"E62...Q..{2.e at 9z..q.:F.Y....(....).F..#..o..-.#S...1......`e.U..'G...y.s.8h.d......1..AS}gO.H. <....3h.......>Eo... +uncompressed= 4500022d001500004006ac58c0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a2031302e392e312e3137313a383030300d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..-.... at ..X........@.. at F.......P.@..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: 10.9.1.171:8000..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... + +Done -- To view, visit https://gerrit.osmocom.org/644 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d Gerrit-PatchSet: 31 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Fri Aug 26 16:11:57 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Fri, 26 Aug 2016 16:11:57 +0000 Subject: [PATCH] openbsc[master]: SLHC (RFC1144 header compression) integration and unit-test In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/635 to look at the new patch set (#15). SLHC (RFC1144 header compression) integration and unit-test The previously pushed slhc implementation has been modified to compile and function outside of the kernel. Also debug log messages were added and datatypes ware matched. The implementation is now ready to be used Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 --- M openbsc/.gitignore M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/debug.h R openbsc/include/openbsc/slhc.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/sgsn_main.c M openbsc/src/gprs/slhc.c M openbsc/tests/Makefile.am M openbsc/tests/sgsn/Makefile.am A openbsc/tests/slhc/Makefile.am A openbsc/tests/slhc/slhc_test.c A openbsc/tests/slhc/slhc_test.ok M openbsc/tests/testsuite.at 14 files changed, 551 insertions(+), 91 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/35/635/15 diff --git a/openbsc/.gitignore b/openbsc/.gitignore index 8ce3b70..e75b9eb 100644 --- a/openbsc/.gitignore +++ b/openbsc/.gitignore @@ -83,6 +83,7 @@ tests/mm_auth/mm_auth_test tests/xid/xid_test tests/sndcp_xid/sndcp_xid_test +tests/slhc/slhc_test tests/atconfig tests/atlocal diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 53072bd..18980b0 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -231,6 +231,7 @@ tests/mm_auth/Makefile tests/xid/Makefile tests/sndcp_xid/Makefile + tests/slhc/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index e200b05..f402fea 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,8 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h + gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ + slhc.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 43ebb19..90ddca5 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -29,6 +29,7 @@ DBSSGP, DLLC, DSNDCP, + DSLHC, DNAT, DCTRL, DSMPP, diff --git a/openbsc/include/openbsc/slhc_vj.h b/openbsc/include/openbsc/slhc.h similarity index 97% rename from openbsc/include/openbsc/slhc_vj.h rename to openbsc/include/openbsc/slhc.h index 8716d59..cd5a47c 100644 --- a/openbsc/include/openbsc/slhc_vj.h +++ b/openbsc/include/openbsc/slhc.h @@ -171,7 +171,8 @@ #define NULLSLCOMPR (struct slcompress *)0 /* In slhc.c: */ -struct slcompress *slhc_init(int rslots, int tslots); +struct slcompress *slhc_init(const void *ctx, int rslots, int tslots); + void slhc_free(struct slcompress *comp); int slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, @@ -180,4 +181,7 @@ int slhc_remember(struct slcompress *comp, unsigned char *icp, int isize); int slhc_toss(struct slcompress *comp); +void slhc_i_status(struct slcompress *comp); +void slhc_o_status(struct slcompress *comp); + #endif /* _SLHC_H */ diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index fa4a3dd..245636b 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -26,7 +26,8 @@ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ - oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c + oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ + slhc.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c index 52fc985..894ce84 100644 --- a/openbsc/src/gprs/sgsn_main.c +++ b/openbsc/src/gprs/sgsn_main.c @@ -292,6 +292,11 @@ .description = "SCCP User Adaptation (SUA)", .enabled = 1, .loglevel = LOGL_DEBUG, }, + [DSLHC] = { + .name = "DSLHC", + .description = "RFC1144 TCP/IP Header compression (SLHC)", + .enabled = 1, .loglevel = LOGL_DEBUG, + }, }; static const struct log_info gprs_log_info = { diff --git a/openbsc/src/gprs/slhc.c b/openbsc/src/gprs/slhc.c index 27ed252..cbdf8db 100644 --- a/openbsc/src/gprs/slhc.c +++ b/openbsc/src/gprs/slhc.c @@ -50,61 +50,77 @@ * driver code belonging close to PPP and SLIP */ -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#ifdef CONFIG_INET -/* Entire module is for IP only */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#define ERR_PTR(x) x + static unsigned char *encode(unsigned char *cp, unsigned short n); static long decode(unsigned char **cpp); static unsigned char * put16(unsigned char *cp, unsigned short x); static unsigned short pull16(unsigned char **cpp); +/* Replacement for kernel space function ip_fast_csum() */ +static uint16_t ip_fast_csum(uint8_t *iph, int ihl) +{ + int i; + uint16_t temp; + uint32_t accumulator = 0xFFFF; + + for(i=0;i0xFFFF) + { + accumulator++; + accumulator&=0xFFFF; + } + } + + return (uint16_t)(htons(~accumulator)&0xFFFF); +} + +/* Replacement for kernel space function put_unaligned() */ +static void put_unaligned(uint16_t val, void *ptr) +{ + memcpy(ptr,&val,sizeof(val)); +} + + /* Allocate compression data structure * slots must be in range 0 to 255 (zero meaning no compression) * Returns pointer to structure or ERR_PTR() on error. */ struct slcompress * -slhc_init(int rslots, int tslots) +slhc_init(const void *ctx, int rslots, int tslots) { register short i; register struct cstate *ts; struct slcompress *comp; if (rslots < 0 || rslots > 255 || tslots < 0 || tslots > 255) - return ERR_PTR(-EINVAL); + return NULL; - comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL); + comp = (struct slcompress *)talloc_zero_size(ctx,sizeof(struct slcompress)); if (! comp) goto out_fail; if (rslots > 0) { size_t rsize = rslots * sizeof(struct cstate); - comp->rstate = kzalloc(rsize, GFP_KERNEL); + comp->rstate = (struct cstate *) talloc_zero_size(ctx, rsize); if (! comp->rstate) goto out_free; comp->rslot_limit = rslots - 1; @@ -112,7 +128,7 @@ if (tslots > 0) { size_t tsize = tslots * sizeof(struct cstate); - comp->tstate = kzalloc(tsize, GFP_KERNEL); + comp->tstate = (struct cstate *) talloc_zero_size(ctx, tsize); if (! comp->tstate) goto out_free2; comp->tslot_limit = tslots - 1; @@ -141,11 +157,11 @@ return comp; out_free2: - kfree(comp->rstate); + talloc_free(comp->rstate); out_free: - kfree(comp); + talloc_free(comp); out_fail: - return ERR_PTR(-ENOMEM); + return NULL; } @@ -153,16 +169,18 @@ void slhc_free(struct slcompress *comp) { + DEBUGP(DSLHC, "slhc_free(): Freeing compression states...\n"); + if ( comp == NULLSLCOMPR ) return; if ( comp->tstate != NULLSLSTATE ) - kfree( comp->tstate ); + talloc_free(comp->tstate ); if ( comp->rstate != NULLSLSTATE ) - kfree( comp->rstate ); + talloc_free( comp->rstate ); - kfree( comp ); + talloc_free( comp ); } @@ -187,6 +205,8 @@ } else { *cp++ = n; } + + DEBUGP(DSLHC, "encode(): n=%04x\n",n); return cp; } @@ -256,6 +276,7 @@ comp->sls_o_nontcp++; else comp->sls_o_tcp++; + DEBUGP(DSLHC, "slhc_compress(): Not a TCP packat, will not touch...\n"); return isize; } /* Extract TCP header */ @@ -271,6 +292,7 @@ ! (th->ack)){ /* TCP connection stuff; send as regular IP */ comp->sls_o_tcp++; + DEBUGP(DSLHC, "slhc_compress(): Packet is part of a TCP connection, will not touch...\n"); return isize; } /* @@ -287,6 +309,9 @@ * states via linear search. If we don't find a state * for the datagram, the oldest state is (re-)used. */ + + DEBUGP(DSLHC, "slhc_compress(): Compressible packet detected!\n"); + for ( ; ; ) { if( ip->saddr == cs->cs_ip.saddr && ip->daddr == cs->cs_ip.daddr @@ -310,11 +335,14 @@ * state points to the newest and we only need to set * xmit_oldest to update the lru linkage. */ + + DEBUGP(DSLHC, "slhc_compress(): Header not yet seen, will memorize header for the next turn...\n"); comp->sls_o_misses++; comp->xmit_oldest = lcs->cs_this; goto uncompressed; found: + DEBUGP(DSLHC, "slhc_compress(): Header already seen, trying to compress...\n"); /* * Found it -- move to the front on the connection list. */ @@ -344,6 +372,39 @@ */ oth = &cs->cs_tcp; + /* Display a little more debug information about which of the + * header fields changed unexpectedly */ + if(ip->version != cs->cs_ip.version) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->version != cs->cs_ip.version\n"); + if(ip->ihl != cs->cs_ip.ihl) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->ihl != cs->cs_ip.ihl\n"); + if(ip->tos != cs->cs_ip.tos) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->tos != cs->cs_ip.tos\n"); + if((ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))\n"); + if(ip->ttl != cs->cs_ip.ttl) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->ttl != cs->cs_ip.ttl\n"); + if(th->doff != cs->cs_tcp.doff) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: th->doff != cs->cs_tcp.doff\n"); + if(ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) { + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0)\n"); + DEBUGP(DSLHC, "slhc_compress(): ip->ihl = %i\n", ip->ihl); + DEBUGP(DSLHC, "slhc_compress(): ip+1 = %s\n", + osmo_hexdump_nospc((uint8_t*)(ip+1),((ip->ihl)-5)*4)); + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: cs->cs_ipopt = %s\n", + osmo_hexdump_nospc((uint8_t*)(cs->cs_ipopt),((ip->ihl)-5)*4)); + } + if(th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0) { + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)\n"); + DEBUGP(DSLHC, "slhc_compress(): th->doff = %i\n", th->doff); + DEBUGP(DSLHC, "slhc_compress(): th+1 = %s\n", + osmo_hexdump_nospc((uint8_t*)(th+1),((th->doff)-5)*4)); + DEBUGP(DSLHC, "slhc_compress(): cs->cs_tcpopt = %s\n", + osmo_hexdump_nospc((uint8_t*)cs->cs_tcpopt, + ((th->doff)-5)*4)); + } + + if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl || ip->tos != cs->cs_ip.tos || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000)) @@ -351,6 +412,7 @@ || th->doff != cs->cs_tcp.doff || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){ + DEBUGP(DSLHC, "slhc_compress(): The header contains unexpected changes, can't compress...\n"); goto uncompressed; } @@ -362,6 +424,7 @@ */ if(th->urg){ deltaS = ntohs(th->urg_ptr); + DEBUGP(DSLHC, "slhc_compress(): flag: Urgent Pointer (U) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_U; } else if(th->urg_ptr != oth->urg_ptr){ @@ -369,21 +432,29 @@ * implementation should never do this but RFC793 * doesn't prohibit the change so we have to deal * with it. */ + DEBUGP(DSLHC, "slhc_compress(): URG not set but urp changed, can't compress...\n"); goto uncompressed; } if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){ + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Window (W) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_W; } if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){ - if(deltaA > 0x0000ffff) + if(deltaA > 0x0000ffff) { + DEBUGP(DSLHC, "slhc_compress(): (deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L, can't compress...\n"); goto uncompressed; + } + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Ack (A) = 1\n"); cp = encode(cp,deltaA); changes |= NEW_A; } if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){ - if(deltaS > 0x0000ffff) + if(deltaS > 0x0000ffff) { + DEBUGP(DSLHC, "slhc_compress(): (deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L, can't compress...\n"); goto uncompressed; + } + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_S; } @@ -399,17 +470,21 @@ if(ip->tot_len != cs->cs_ip.tot_len && ntohs(cs->cs_ip.tot_len) == hlen) break; + DEBUGP(DSLHC, "slhc_compress(): Retransmitted packet detected, can't compress...\n"); goto uncompressed; case SPECIAL_I: case SPECIAL_D: /* actual changes match one of our special case encodings -- * send packet uncompressed. */ + DEBUGP(DSLHC, "slhc_compress(): Special case detected, can't compress...\n"); goto uncompressed; case NEW_S|NEW_A: if(deltaS == deltaA && deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ /* special case for echoed terminal traffic */ + DEBUGP(DSLHC, "slhc_compress(): Special case for echoed terminal traffic detected...\n"); + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1, Delta Window (W) = 1, Urgent Pointer (U) = 1\n"); changes = SPECIAL_I; cp = new_seq; } @@ -417,6 +492,8 @@ case NEW_S: if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ /* special case for data xfer */ + DEBUGP(DSLHC, "slhc_compress(): Special case for data xfer detected...\n"); + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1, Delta Ack (A) = 1, Delta Window (W) = 1, Urgent Pointer (U) = 1\n"); changes = SPECIAL_D; cp = new_seq; } @@ -424,11 +501,14 @@ } deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id); if(deltaS != 1){ + DEBUGP(DSLHC, "slhc_compress(): flag: Delta IP ID (I) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_I; } - if(th->psh) + if(th->psh) { + DEBUGP(DSLHC, "slhc_compress(): flag: Push (P) = 1\n"); changes |= TCP_PUSH_BIT; + } /* Grab the cksum before we overwrite it below. Then update our * state with this packet's header. */ @@ -445,6 +525,7 @@ if(compress_cid == 0 || comp->xmit_current != cs->cs_this){ cp = ocp; *cpp = ocp; + DEBUGP(DSLHC, "slhc_compress(): flag: Connection number (C) = 1\n"); *cp++ = changes | NEW_C; *cp++ = cs->cs_this; comp->xmit_current = cs->cs_this; @@ -456,6 +537,10 @@ *(__sum16 *)cp = csum; cp += 2; /* deltaS is now the size of the change section of the compressed header */ + + DEBUGP(DSLHC, "slhc_compress(): Delta-list length (deltaS) = %li\n",deltaS); + DEBUGP(DSLHC, "slhc_compress(): Original header len (hlen) = %i\n",hlen); + memcpy(cp,new_seq,deltaS); /* Write list of deltas */ memcpy(cp+deltaS,icp+hlen,isize-hlen); comp->sls_o_compressed++; @@ -467,6 +552,7 @@ * to use on future compressed packets in the protocol field). */ uncompressed: + DEBUGP(DSLHC, "slhc_compress(): Packet will be sent uncompressed...\n"); memcpy(&cs->cs_ip,ip,20); memcpy(&cs->cs_tcp,th,20); if (ip->ihl > 5) @@ -538,6 +624,8 @@ switch(changes & SPECIALS_MASK){ case SPECIAL_I: /* Echoed terminal traffic */ + DEBUGP(DSLHC, "slhc_uncompress(): Echoed terminal traffic detected\n"); + { register short i; i = ntohs(ip->tot_len) - hdrlen; @@ -547,11 +635,13 @@ break; case SPECIAL_D: /* Unidirectional data */ + DEBUGP(DSLHC, "slhc_uncompress(): Unidirectional data detected\n"); thp->seq = htonl( ntohl(thp->seq) + ntohs(ip->tot_len) - hdrlen); break; default: + DEBUGP(DSLHC, "slhc_uncompress(): default packet type detected\n"); if(changes & NEW_U){ thp->urg = 1; if((x = decode(&cp)) == -1) { @@ -601,6 +691,7 @@ ip->tot_len = htons(len); ip->check = 0; + DEBUGP(DSLHC, "slhc_uncompress(): making space for the reconstructed header...\n"); memmove(icp + hdrlen, cp, len - hdrlen); cp = icp; @@ -625,6 +716,7 @@ return len; bad: + DEBUGP(DSLHC, "slhc_uncompress(): bad packet detected!\n"); comp->sls_i_error++; return slhc_toss( comp ); } @@ -641,6 +733,7 @@ if(isize < 20) { /* The packet is shorter than a legal IP header */ comp->sls_i_runt++; + DEBUGP(DSLHC, "slhc_remember(): The packet is shorter than a legal IP header ==> slhc_toss()\n"); return slhc_toss( comp ); } /* Peek at the IP header's IHL field to find its length */ @@ -648,6 +741,7 @@ if(ihl < 20 / 4){ /* The IP header length field is too small */ comp->sls_i_runt++; + DEBUGP(DSLHC, "slhc_remember(): The IP header length field is too small ==> slhc_toss()\n"); return slhc_toss( comp ); } index = icp[9]; @@ -656,10 +750,12 @@ if (ip_fast_csum(icp, ihl)) { /* Bad IP header checksum; discard */ comp->sls_i_badcheck++; + DEBUGP(DSLHC, "slhc_remember(): Bad IP header checksum; discard ==> slhc_toss()\n"); return slhc_toss( comp ); } if(index > comp->rslot_limit) { comp->sls_i_error++; + DEBUGP(DSLHC, "slhc_remember(): index > comp->rslot_limit ==> slhc_toss()\n"); return slhc_toss(comp); } @@ -683,6 +779,7 @@ int slhc_toss(struct slcompress *comp) { + DEBUGP(DSLHC, "slhc_toss(): Reset compression state...\n"); if ( comp == NULLSLCOMPR ) return 0; @@ -690,55 +787,27 @@ return 0; } -#else /* CONFIG_INET */ - -int -slhc_toss(struct slcompress *comp) +void slhc_i_status(struct slcompress *comp) { - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss"); - return -EINVAL; -} -int -slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress"); - return -EINVAL; -} -int -slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, - unsigned char *ocp, unsigned char **cpp, int compress_cid) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress"); - return -EINVAL; + if (comp != NULLSLCOMPR) { + DEBUGP(DSLHC, "slhc_i_status(): %d Cmp, %d Uncmp, %d Bad, %d Tossed\n", + comp->sls_i_compressed, + comp->sls_i_uncompressed, + comp->sls_i_error, + comp->sls_i_tossed); + } } -int -slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +void slhc_o_status(struct slcompress *comp) { - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember"); - return -EINVAL; + if (comp != NULLSLCOMPR) { + DEBUGP(DSLHC, "slhc_o_status(): %d Cmp, %d Uncmp, %d AsIs, %d NotTCP %d Searches, %d Misses\n", + comp->sls_o_compressed, + comp->sls_o_uncompressed, + comp->sls_o_tcp, + comp->sls_o_nontcp, + comp->sls_o_searches, + comp->sls_o_misses); + } } -void -slhc_free(struct slcompress *comp) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free"); -} -struct slcompress * -slhc_init(int rslots, int tslots) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init"); - return NULL; -} - -#endif /* CONFIG_INET */ - -/* VJ header compression */ -EXPORT_SYMBOL(slhc_init); -EXPORT_SYMBOL(slhc_free); -EXPORT_SYMBOL(slhc_remember); -EXPORT_SYMBOL(slhc_compress); -EXPORT_SYMBOL(slhc_uncompress); -EXPORT_SYMBOL(slhc_toss); - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index 1debb2d..d5aa356 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid slhc if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 45d1780..3e66978 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -32,6 +32,7 @@ $(top_builddir)/src/gprs/oap_messages.o \ $(top_builddir)/src/gprs/gprs_llc_xid.o \ $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ + $(top_builddir)/src/gprs/slhc.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ diff --git a/openbsc/tests/slhc/Makefile.am b/openbsc/tests/slhc/Makefile.am new file mode 100644 index 0000000..d21990f --- /dev/null +++ b/openbsc/tests/slhc/Makefile.am @@ -0,0 +1,21 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) + +EXTRA_DIST = slhc_test.ok + +noinst_PROGRAMS = slhc_test + +slhc_test_SOURCES = slhc_test.c + +slhc_test_LDADD = \ + $(top_builddir)/src/gprs/slhc.o \ + $(top_builddir)/src/libcommon/libcommon.a \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOGB_LIBS) \ + $(LIBCARES_LIBS) \ + $(LIBCRYPTO_LIBS) \ + -lgtp -lrt -lm + + diff --git a/openbsc/tests/slhc/slhc_test.c b/openbsc/tests/slhc/slhc_test.c new file mode 100644 index 0000000..59a5425 --- /dev/null +++ b/openbsc/tests/slhc/slhc_test.c @@ -0,0 +1,298 @@ +/* Test SLHC/RFC1144 TCP/IP Header compression/decompression */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include +#include + +#include + +#include +#include +#include + +/* Number of compression slots (S0-1) */ +#define SLOTS 8 + +/* Maximum packet bytes to display */ +#define DISP_MAX_BYTES 100 + +/* Sample packets to test with */ +#define PACKETS_LEN 6 +char *packets[] = { + "4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27", + "4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0", + "4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01", + "4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01", + "4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a", + "4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20" +}; + +/* Compress a packet using Van Jacobson RFC1144 header compression */ +static int compress(uint8_t *data_o, uint8_t *data_i, int len, + struct slcompress *comp) +{ + uint8_t *comp_ptr; /* Not used */ + int compr_len; + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Run compressor */ + compr_len = slhc_compress(comp, data_i, len, data_o, &comp_ptr, 0); + return compr_len; +} + +/* Expand a packet using Van Jacobson RFC1144 header compression */ +static int expand(uint8_t *data_o, uint8_t *data_i, int len, + struct slcompress *comp) +{ + int data_decompressed_len; + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Handle an uncompressed packet (learn header information */ + if ((data_i[0] & SL_TYPE_UNCOMPRESSED_TCP) == SL_TYPE_UNCOMPRESSED_TCP) { + data_o[0] &= 0x4F; + data_decompressed_len = slhc_remember(comp, data_o, len); + return data_decompressed_len; + } + + /* Uncompress compressed packets */ + else if (data_o[0] & SL_TYPE_COMPRESSED_TCP) { + data_decompressed_len = slhc_uncompress(comp, data_o, len); + return data_decompressed_len; + } + + /* Regular or unknown packets will not be touched */ + return len; +} + +/* Calculate IP Header checksum */ +static uint16_t calc_ip_csum(uint8_t *data, int len) +{ + int i; + uint32_t accumulator = 0; + uint16_t *pointer = (uint16_t *) data; + + for (i = len; i > 1; i -= 2) { + accumulator += *pointer; + pointer++; + } + + if (len % 2) + accumulator += *pointer; + + accumulator = (accumulator & 0xffff) + ((accumulator >> 16) & 0xffff); + accumulator += (accumulator >> 16) & 0xffff; + return (~accumulator); +} + +/* Calculate TCP/IP checksum */ +static uint16_t calc_tcpip_csum(const void *ctx, uint8_t *packet, int len) +{ + uint8_t *buf; + uint16_t csum; + + buf = talloc_zero_size(ctx, len); + memset(buf, 0, len); + memcpy(buf, packet + 12, 8); + buf[9] = packet[9]; + buf[11] = (len - 20) & 0xFF; + buf[10] = (len - 20) >> 8 & 0xFF; + memcpy(buf + 12, packet + 20, len - 20); + csum = calc_ip_csum(buf, len - 20 + 12); + talloc_free(buf); + return csum; +} + +/* Check TCP/IP packet */ +static void check_packet(const void *ctx, uint8_t *packet, int len) +{ + /* Check IP header */ + OSMO_ASSERT(len > 20); + OSMO_ASSERT(calc_ip_csum(packet, 20) == 0); + + /* Check TCP packet */ + if (packet[9] != 0x06) + return; + OSMO_ASSERT(len > 40); + OSMO_ASSERT(calc_tcpip_csum(ctx, packet, len) == 0); +} + +/* Strip TCP options from TCP/IP packet */ +static int strip_tcp_options(const void *ctx, uint8_t *packet, int len) +{ + uint8_t doff; + uint16_t csum; + + /* Check if the packet can be handled here */ + if (len < 37) + return len; + if (packet[9] != 0x06) + return len; + + /* Strip TCP/IP options from packet */ + doff = ((packet[32] >> 4) & 0x0F) * 4; + memmove(packet + 40, packet + doff + 20, len - 40 - (doff - 20)); + len = len - (doff - 20); + + /* Repair data offset (TCP header length) */ + packet[32] &= 0x0F; + packet[32] |= 0x50; + + /* Repair checksum */ + packet[36] = 0; + packet[37] = 0; + csum = calc_tcpip_csum(ctx, packet, len); + packet[36] = csum & 0xFF; + packet[37] = csum >> 8 & 0xFF; + + /* Repair total length */ + packet[3] = len & 0xFF; + packet[2] = len >> 8 & 0xFF; + + /* Repair IP header checksum */ + packet[10] = 0; + packet[11] = 0; + csum = calc_ip_csum(packet, 20); + packet[10] = csum & 0xFF; + packet[11] = csum >> 8 & 0xFF; + printf("csum=%04x\n", csum); + + return len; +} + +/* Compress / Decompress packets */ +static void test_slhc(const void *ctx) +{ + char packet_ascii[2048]; + int i; + + struct slcompress *comp; + uint8_t packet[1024]; + int packet_len; + uint8_t packet_compr[1024]; + int packet_compr_len; + uint8_t packet_decompr[1024]; + int packet_decompr_len; + + printf("Allocating compression state...\n"); + comp = slhc_init(ctx, SLOTS, SLOTS); + OSMO_ASSERT(comp); + + for(i=0;i DISP_MAX_BYTES) + packet_compr_len = DISP_MAX_BYTES; + if (packet_len > DISP_MAX_BYTES) + packet_len = DISP_MAX_BYTES; + if (packet_decompr_len > DISP_MAX_BYTES) + packet_decompr_len = DISP_MAX_BYTES; + printf("Original Packet: (%i bytes) %s\n", packet_len, + osmo_hexdump_nospc(packet, packet_len)); + printf("DecompressedPacket: (%i bytes) %s\n", + packet_decompr_len, osmo_hexdump_nospc(packet_decompr, + packet_decompr_len)); + printf("CompressedPacket: (%i bytes) %s\n", packet_compr_len, + osmo_hexdump_nospc(packet_compr, packet_compr_len)); + slhc_o_status(comp); + slhc_o_status(comp); + + printf("\n"); + } + + printf("Freeing compression state...\n"); + slhc_free(comp); + printf("\n"); +} + +static struct log_info_cat gprs_categories[] = { + [DSNDCP] = { + .name = "DSNDCP", + .description = + "GPRS Sub-Network Dependent Control Protocol (SNDCP)", + .enabled = 1,.loglevel = LOGL_DEBUG, + }, + [DSLHC] = { + .name = "DSLHC", + .description = + "Van Jacobson RFC1144 TCP/IP header compression (SLHC)", + .enabled = 1,.loglevel = LOGL_DEBUG, + } +}; + +static struct log_info info = { + .cat = gprs_categories, + .num_cat = ARRAY_SIZE(gprs_categories), +}; + +int main(int argc, char **argv) +{ + void *ctx; + + osmo_init_logging(&info); + + ctx = talloc_named_const(NULL, 0, "slhc_ctx"); + + test_slhc(ctx); + + printf("Done\n"); + + talloc_report_full(ctx, stderr); + OSMO_ASSERT(talloc_total_blocks(ctx) == 1); + return 0; +} + +/* stubs */ +struct osmo_prim_hdr; +int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) +{ + abort(); +} diff --git a/openbsc/tests/slhc/slhc_test.ok b/openbsc/tests/slhc/slhc_test.ok new file mode 100644 index 0000000..636241d --- /dev/null +++ b/openbsc/tests/slhc/slhc_test.ok @@ -0,0 +1,52 @@ +Allocating compression state... +csum=b3a9 +Compressing... +Decompressing... +Results: +Original Packet: (52 bytes) 4510003446dd40004006a9b3c0a8646ec0a864640017ad8b81980100f3ac984d501800e371410000fffd18fffd20fffd23fffd27 +DecompressedPacket: (52 bytes) 4510003446dd40004006a9b3c0a8646ec0a864640017ad8b81980100f3ac984d501800e371410000fffd18fffd20fffd23fffd27 +CompressedPacket: (52 bytes) 7510003446dd40004000a9b3c0a8646ec0a864640017ad8b81980100f3ac984d501800e371410000fffd18fffd20fffd23fffd27 + +csum=97a9 +Compressing... +Decompressing... +Results: +Original Packet: (79 bytes) 4510004f46de40004006a997c0a8646ec0a864640017ad8b8198010cf3ac984d501800e3cda40000fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 +DecompressedPacket: (79 bytes) 4510004f46de40004006a997c0a8646ec0a864640017ad8b8198010cf3ac984d501800e3cda40000fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 +CompressedPacket: (43 bytes) df00cda4fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 + +csum=baa9 +Compressing... +Decompressing... +Results: +Original Packet: (43 bytes) 4510002b46df40004006a9bac0a8646ec0a864640017ad8b81980133f3ac989f501800e3a70a0000fffd01 +DecompressedPacket: (43 bytes) 4510002b46df40004006a9bac0a8646ec0a864640017ad8b81980133f3ac989f501800e3a70a0000fffd01 +CompressedPacket: (9 bytes) dc00a70a5227fffd01 + +csum=b9a9 +Compressing... +Decompressing... +Results: +Original Packet: (43 bytes) 4510002b46e040004006a9b9c0a8646ec0a864640017ad8b81980136f3ac98a2501800e3a7060000fffb01 +DecompressedPacket: (43 bytes) 4510002b46e040004006a9b9c0a8646ec0a864640017ad8b81980136f3ac98a2501800e3a7060000fffb01 +CompressedPacket: (7 bytes) db00a706fffb01 + +csum=7ba9 +Compressing... +Decompressing... +Results: +Original Packet: (100 bytes) 4510006846e140004006a97bc0a8646ec0a864640017ad8b81980139f3ac98a5501800e3c2d000000d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d +DecompressedPacket: (100 bytes) 4510006846e140004006a97bc0a8646ec0a864640017ad8b81980139f3ac98a5501800e3c2d000000d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d +CompressedPacket: (68 bytes) db00c2d00d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a + +csum=aca9 +Compressing... +Decompressing... +Results: +Original Packet: (54 bytes) 4510003646e240004006a9acc0a8646ec0a864640017ad8b81980179f3ac98a5501800e321fb0000706f6c6c7578206c6f67696e3a20 +DecompressedPacket: (54 bytes) 4510003646e240004006a9acc0a8646ec0a864640017ad8b81980179f3ac98a5501800e321fb0000706f6c6c7578206c6f67696e3a20 +CompressedPacket: (18 bytes) df0021fb706f6c6c7578206c6f67696e3a20 + +Freeing compression state... + +Done diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index 85a81d6..5f37b8e 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -136,3 +136,8 @@ AT_CHECK([$abs_top_builddir/tests/sndcp_xid/sndcp_xid_test], [], [expout], [ignore]) AT_CLEANUP +AT_SETUP([slhc]) +AT_KEYWORDS([slhc]) +cat $abs_srcdir/slhc/slhc_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/slhc/slhc_test], [], [expout], [ignore]) +AT_CLEANUP -- To view, visit https://gerrit.osmocom.org/635 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 Gerrit-PatchSet: 15 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Sat Aug 27 01:20:18 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 01:20:18 +0000 Subject: libosmocore[master]: vty: use VTY_BIND_ADDR_DEFAULT instead of "127.0.0.1" In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/722 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ice0688ac9847524cb546f6d41547090b6a3cb3d8 Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 01:20:24 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 01:20:24 +0000 Subject: [MERGED] libosmocore[master]: vty: use VTY_BIND_ADDR_DEFAULT instead of "127.0.0.1" In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: vty: use VTY_BIND_ADDR_DEFAULT instead of "127.0.0.1" ...................................................................... vty: use VTY_BIND_ADDR_DEFAULT instead of "127.0.0.1" Change-Id: Ice0688ac9847524cb546f6d41547090b6a3cb3d8 --- M src/vty/vty.c 1 file changed, 1 insertion(+), 1 deletion(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/src/vty/vty.c b/src/vty/vty.c index 8c0c73a..88ed937 100644 --- a/src/vty/vty.c +++ b/src/vty/vty.c @@ -1678,7 +1678,7 @@ vty_out(vty, " no login%s", VTY_NEWLINE); /* bind */ - if (vty_bind_addr && (strcmp(vty_bind_addr, "127.0.0.1") != 0)) + if (vty_bind_addr && (strcmp(vty_bind_addr, VTY_BIND_ADDR_DEFAULT) != 0)) vty_out(vty, " bind %s%s", vty_bind_addr, VTY_NEWLINE); vty_out(vty, "!%s", VTY_NEWLINE); -- To view, visit https://gerrit.osmocom.org/722 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ice0688ac9847524cb546f6d41547090b6a3cb3d8 Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Sat Aug 27 01:20:47 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 01:20:47 +0000 Subject: [MERGED] osmo-bts[master]: Change interface in osmo-bts for 11 bit RACH In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: Change interface in osmo-bts for 11 bit RACH ...................................................................... Change interface in osmo-bts for 11 bit RACH Interface structure between osmo-bts and osmo-pcu is updated with the parameters to differentiate the type of RACH and further support 11 bit RACH. The function prototype and definitions are changed accordingly. Interface version number is increased. Change-Id: I4f4c501b2d86d77c78de32a84b1804172ffb6f4d --- M include/osmo-bts/pcu_if.h M include/osmo-bts/pcuif_proto.h M src/common/l1sap.c M src/common/pcu_sock.c M src/osmo-bts-sysmo/l1_if.c 5 files changed, 22 insertions(+), 7 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/include/osmo-bts/pcu_if.h b/include/osmo-bts/pcu_if.h index efad0c5..a020c05 100644 --- a/include/osmo-bts/pcu_if.h +++ b/include/osmo-bts/pcu_if.h @@ -11,7 +11,8 @@ int pcu_tx_data_ind(struct gsm_bts_trx_ts *ts, uint8_t is_ptcch, uint32_t fn, uint16_t arfcn, uint8_t block_nr, uint8_t *data, uint8_t len, int8_t rssi, uint16_t ber10k, int16_t bto, int16_t lqual); -int pcu_tx_rach_ind(struct gsm_bts *bts, int16_t qta, uint8_t ra, uint32_t fn); +int pcu_tx_rach_ind(struct gsm_bts *bts, int16_t qta, uint16_t ra, uint32_t fn, + uint8_t is_11bit, enum ph_burst_type burst_type); int pcu_tx_time_ind(uint32_t fn); int pcu_tx_pag_req(const uint8_t *identity_lv, uint8_t chan_needed); int pcu_tx_pch_data_cnf(uint32_t fn, uint8_t *data, uint8_t len); diff --git a/include/osmo-bts/pcuif_proto.h b/include/osmo-bts/pcuif_proto.h index 07d35f8..5527238 100644 --- a/include/osmo-bts/pcuif_proto.h +++ b/include/osmo-bts/pcuif_proto.h @@ -1,7 +1,7 @@ #ifndef _PCUIF_PROTO_H #define _PCUIF_PROTO_H -#define PCU_IF_VERSION 0x06 +#define PCU_IF_VERSION 0x07 /* msg_type */ #define PCU_IF_MSG_DATA_REQ 0x00 /* send data to given channel */ @@ -67,10 +67,12 @@ struct gsm_pcu_if_rach_ind { uint8_t sapi; - uint8_t ra; + uint16_t ra; int16_t qta; uint32_t fn; uint16_t arfcn; + uint8_t is_11bit; + uint8_t burst_type; } __attribute__ ((packed)); struct gsm_pcu_if_info_trx { diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 6498103..2ab4055 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -288,7 +288,7 @@ *ss = L1SAP_CHAN2SS_SDCCH4(chan_nr); else if (L1SAP_IS_CHAN_SDCCH8(chan_nr)) *ss = L1SAP_CHAN2SS_SDCCH8(chan_nr); - *data = &l1sap->u.rach_ind.ra; + *data = (uint8_t *)&l1sap->u.rach_ind.ra; *len = 1; return 0; @@ -965,10 +965,13 @@ return l1sap_handover_rach(trx, l1sap, rach_ind); /* check for packet access */ - if (trx == bts->c0 && L1SAP_IS_PACKET_RACH(rach_ind->ra)) { + if ((trx == bts->c0 && L1SAP_IS_PACKET_RACH(rach_ind->ra)) || + (trx == bts->c0 && rach_ind->is_11bit)) { + LOGP(DL1P, LOGL_INFO, "RACH for packet access\n"); pcu_tx_rach_ind(bts, rach_ind->acc_delay << 2, - rach_ind->ra, rach_ind->fn); + rach_ind->ra, rach_ind->fn, + rach_ind->is_11bit, rach_ind->burst_type); return 0; } diff --git a/src/common/pcu_sock.c b/src/common/pcu_sock.c index fed464f..62f18a7 100644 --- a/src/common/pcu_sock.c +++ b/src/common/pcu_sock.c @@ -371,7 +371,8 @@ return pcu_sock_send(&bts_gsmnet, msg); } -int pcu_tx_rach_ind(struct gsm_bts *bts, int16_t qta, uint8_t ra, uint32_t fn) +int pcu_tx_rach_ind(struct gsm_bts *bts, int16_t qta, uint16_t ra, uint32_t fn, + uint8_t is_11bit, enum ph_burst_type burst_type) { struct msgb *msg; struct gsm_pcu_if *pcu_prim; @@ -390,6 +391,8 @@ rach_ind->ra = ra; rach_ind->qta = qta; rach_ind->fn = fn; + rach_ind->is_11bit = is_11bit; + rach_ind->burst_type = burst_type; return pcu_sock_send(&bts_gsmnet, msg); } diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index f70ccf5..fcd3a3e 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -970,6 +970,12 @@ l1sap->u.rach_ind.ra = ra; l1sap->u.rach_ind.acc_delay = acc_delay; l1sap->u.rach_ind.fn = fn; + + /* Initialising the parameters needs to be handled when 11 bit RACH */ + + l1sap->u.rach_ind.is_11bit = 0; + l1sap->u.rach_ind.burst_type = GSM_L1_BURST_TYPE_ACCESS_0; + if (!lchan || lchan->ts->pchan == GSM_PCHAN_CCCH || lchan->ts->pchan == GSM_PCHAN_CCCH_SDCCH4) l1sap->u.rach_ind.chan_nr = 0x88; -- To view, visit https://gerrit.osmocom.org/433 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I4f4c501b2d86d77c78de32a84b1804172ffb6f4d Gerrit-PatchSet: 6 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: bhargava_abhyankar From gerrit-no-reply at lists.osmocom.org Sat Aug 27 01:22:48 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 01:22:48 +0000 Subject: [MERGED] osmo-pcu[master]: Change interface in osmo-pcu for 11 bit RACH In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: Change interface in osmo-pcu for 11 bit RACH ...................................................................... Change interface in osmo-pcu for 11 bit RACH Interface structure between osmo-bts and osmo-pcu is updated with the parameters to differentiate the type of RACH and further support 11 bit RACH. The function prototype and definitions are changed accordingly. Interface version number is increased. Change-Id: I265c2d92d36d6cbcbeee60cdd8407dafe1da06a4 --- M src/bts.cpp M src/bts.h M src/pcu_l1_if.cpp M src/pcuif_proto.h M tests/tbf/TbfTest.cpp 5 files changed, 18 insertions(+), 9 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/src/bts.cpp b/src/bts.cpp index c53c92c..e65d608 100644 --- a/src/bts.cpp +++ b/src/bts.cpp @@ -467,7 +467,8 @@ return 0; } -int BTS::rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta) +int BTS::rcv_rach(uint16_t ra, uint32_t Fn, int16_t qta, uint8_t is_11bit, + enum ph_burst_type burst_type) { struct gprs_rlcmac_ul_tbf *tbf = NULL; uint8_t trx_no, ts_no = 0; diff --git a/src/bts.h b/src/bts.h index 38896c8..801342d 100644 --- a/src/bts.h +++ b/src/bts.h @@ -28,6 +28,7 @@ #include #include #include +#include } #include "poll_controller.h" @@ -289,7 +290,8 @@ int tfi_find_free(enum gprs_rlcmac_tbf_direction dir, uint8_t *_trx, int8_t use_trx); int rcv_imm_ass_cnf(const uint8_t *data, uint32_t fn); - int rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta); + int rcv_rach(uint16_t ra, uint32_t Fn, int16_t qta, uint8_t is_11bit, + enum ph_burst_type burst_type); void trigger_dl_ass(gprs_rlcmac_dl_tbf *tbf, gprs_rlcmac_tbf *old_tbf); void snd_dl_ass(gprs_rlcmac_tbf *tbf, uint8_t poll, const char *imsi); diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp index 1434213..f1c73c9 100644 --- a/src/pcu_l1_if.cpp +++ b/src/pcu_l1_if.cpp @@ -322,7 +322,8 @@ case PCU_IF_SAPI_RACH: rc = BTS::main_bts()->rcv_rach( rach_ind->ra, rach_ind->fn, - rach_ind->qta); + rach_ind->qta, rach_ind->is_11bit, + (ph_burst_type)rach_ind->burst_type); break; default: LOGP(DL1IF, LOGL_ERROR, "Received PCU rach request with " diff --git a/src/pcuif_proto.h b/src/pcuif_proto.h index d320380..944f364 100644 --- a/src/pcuif_proto.h +++ b/src/pcuif_proto.h @@ -1,7 +1,9 @@ #ifndef _PCUIF_PROTO_H #define _PCUIF_PROTO_H -#define PCU_IF_VERSION 0x06 +#include + +#define PCU_IF_VERSION 0x07 /* msg_type */ #define PCU_IF_MSG_DATA_REQ 0x00 /* send data to given channel */ @@ -67,10 +69,12 @@ struct gsm_pcu_if_rach_ind { uint8_t sapi; - uint8_t ra; + uint16_t ra; int16_t qta; uint32_t fn; uint16_t arfcn; + uint8_t is_11bit; + uint8_t burst_type; } __attribute__ ((packed)); struct gsm_pcu_if_info_trx { diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 5e40abc..2feb9c3 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -36,6 +36,7 @@ #include #include #include +#include } #include @@ -553,7 +554,7 @@ tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1); - the_bts->rcv_rach(0x03, *fn, qta); + the_bts->rcv_rach(0x03, *fn, qta, 0, GSM_L1_BURST_TYPE_ACCESS_0); ul_tbf = the_bts->ul_tbf_by_tfi(tfi, trx_no, ts_no); OSMO_ASSERT(ul_tbf != NULL); @@ -787,7 +788,7 @@ * simulate RACH, this sends an Immediate * Assignment Uplink on the AGCH */ - the_bts->rcv_rach(0x73, rach_fn, qta); + the_bts->rcv_rach(0x73, rach_fn, qta, 0, GSM_L1_BURST_TYPE_ACCESS_0); /* get next free TFI */ tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1); @@ -1232,8 +1233,8 @@ /* needed to set last_rts_fn in the PDCH object */ request_dl_rlc_block(bts, trx_no, ts_no, fn); - /* simulate RACH, this sends an Immediate Assignment Uplink on the AGCH */ - the_bts->rcv_rach(0x73, rach_fn, qta); + /* simulate RACH, sends an Immediate Assignment Uplink on the AGCH */ + the_bts->rcv_rach(0x73, rach_fn, qta, 0, GSM_L1_BURST_TYPE_ACCESS_0); /* get next free TFI */ tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1); -- To view, visit https://gerrit.osmocom.org/429 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I265c2d92d36d6cbcbeee60cdd8407dafe1da06a4 Gerrit-PatchSet: 6 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: bhargava_abhyankar From gerrit-no-reply at lists.osmocom.org Sat Aug 27 01:23:39 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 01:23:39 +0000 Subject: openbsc[master]: dyn TS: bts_chan_load: use correct nr of subslots for dyn ts In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/667 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I659acebca82dfb3e305433471be64e9d27439af8 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 01:23:42 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 01:23:42 +0000 Subject: openbsc[master]: chan_alloc.c: use ts_subslots() instead of subslots_per_pchan[] In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/668 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Icbea7dbd78abf6144e5291f531a97f96507d8cbf Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 01:23:49 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 01:23:49 +0000 Subject: [MERGED] openbsc[master]: chan_alloc.c: use ts_subslots() instead of subslots_per_pchan[] In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: chan_alloc.c: use ts_subslots() instead of subslots_per_pchan[] ...................................................................... chan_alloc.c: use ts_subslots() instead of subslots_per_pchan[] The array will move to gsm_data_shared.c; to prepare, use the function instead. Change-Id: Icbea7dbd78abf6144e5291f531a97f96507d8cbf --- M openbsc/src/libbsc/chan_alloc.c 1 file changed, 2 insertions(+), 2 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/openbsc/src/libbsc/chan_alloc.c b/openbsc/src/libbsc/chan_alloc.c index d9808f4..92a1358 100644 --- a/openbsc/src/libbsc/chan_alloc.c +++ b/openbsc/src/libbsc/chan_alloc.c @@ -170,13 +170,13 @@ /* The requested type matches the dynamic * timeslot's current mode. A channel may still * be available (think TCH/H). */ - check_subslots = subslots_per_pchan[ts->dyn.pchan_is]; + check_subslots = ts_subslots(ts); } else /* Otherwise this slot is not applicable. */ continue; } else { /* Not a dynamic channel, there is only one pchan kind: */ - check_subslots = subslots_per_pchan[pchan]; + check_subslots = ts_subslots(ts); } /* Is a sub-slot still available? */ -- To view, visit https://gerrit.osmocom.org/668 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: Icbea7dbd78abf6144e5291f531a97f96507d8cbf Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Sat Aug 27 01:23:49 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 01:23:49 +0000 Subject: [MERGED] openbsc[master]: dyn TS: bts_chan_load: use correct nr of subslots for dyn ts In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: dyn TS: bts_chan_load: use correct nr of subslots for dyn ts ...................................................................... dyn TS: bts_chan_load: use correct nr of subslots for dyn ts For TCH/F_TCH/H_PDCH dynamic timeslots, the ts->pchan does not lead to a meaningful value from the subslots_per_pchan[] array. Use the ts_subslots() function instead, which checks for dyn pchan. Change-Id: I659acebca82dfb3e305433471be64e9d27439af8 --- M openbsc/src/libbsc/chan_alloc.c 1 file changed, 3 insertions(+), 1 deletion(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/openbsc/src/libbsc/chan_alloc.c b/openbsc/src/libbsc/chan_alloc.c index c3a7e0f..d9808f4 100644 --- a/openbsc/src/libbsc/chan_alloc.c +++ b/openbsc/src/libbsc/chan_alloc.c @@ -555,12 +555,14 @@ struct gsm_bts_trx_ts *ts = &trx->ts[i]; struct load_counter *pl = &cl->pchan[ts->pchan]; int j; + int subslots; /* skip administratively deactivated timeslots */ if (!nm_is_running(&ts->mo.nm_state)) continue; - for (j = 0; j < subslots_per_pchan[ts->pchan]; j++) { + subslots = ts_subslots(ts); + for (j = 0; j < subslots; j++) { struct gsm_lchan *lchan = &ts->lchan[j]; pl->total++; -- To view, visit https://gerrit.osmocom.org/667 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I659acebca82dfb3e305433471be64e9d27439af8 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Sat Aug 27 01:23:49 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 01:23:49 +0000 Subject: [MERGED] openbsc[master]: move ts_sublots() to gsm_data_shared.c, it will be used by o... In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: move ts_sublots() to gsm_data_shared.c, it will be used by osmo-bts ...................................................................... move ts_sublots() to gsm_data_shared.c, it will be used by osmo-bts Change-Id: I8ba06d7dd6e0ceab3d8d18bb565354d6ed461f7e --- M openbsc/include/openbsc/chan_alloc.h M openbsc/include/openbsc/gsm_data_shared.h M openbsc/src/libbsc/chan_alloc.c M openbsc/src/libcommon/gsm_data_shared.c 4 files changed, 27 insertions(+), 27 deletions(-) Approvals: Jenkins Builder: Verified Holger Freyther: Looks good to me, approved diff --git a/openbsc/include/openbsc/chan_alloc.h b/openbsc/include/openbsc/chan_alloc.h index 3e03b97..78242e5 100644 --- a/openbsc/include/openbsc/chan_alloc.h +++ b/openbsc/include/openbsc/chan_alloc.h @@ -51,6 +51,4 @@ int trx_is_usable(struct gsm_bts_trx *trx); -uint8_t ts_subslots(struct gsm_bts_trx_ts *ts); - #endif /* _CHAN_ALLOC_H */ diff --git a/openbsc/include/openbsc/gsm_data_shared.h b/openbsc/include/openbsc/gsm_data_shared.h index 953bac6..ce2e9b7 100644 --- a/openbsc/include/openbsc/gsm_data_shared.h +++ b/openbsc/include/openbsc/gsm_data_shared.h @@ -853,4 +853,6 @@ struct gsm_lchan *rsl_lchan_lookup(struct gsm_bts_trx *trx, uint8_t chan_nr, int *rc); +uint8_t ts_subslots(struct gsm_bts_trx_ts *ts); + #endif diff --git a/openbsc/src/libbsc/chan_alloc.c b/openbsc/src/libbsc/chan_alloc.c index 92a1358..7b0c3e6 100644 --- a/openbsc/src/libbsc/chan_alloc.c +++ b/openbsc/src/libbsc/chan_alloc.c @@ -72,31 +72,6 @@ return 1; } -static const uint8_t subslots_per_pchan[] = { - [GSM_PCHAN_NONE] = 0, - [GSM_PCHAN_CCCH] = 0, - [GSM_PCHAN_CCCH_SDCCH4] = 4, - [GSM_PCHAN_TCH_F] = 1, - [GSM_PCHAN_TCH_H] = 2, - [GSM_PCHAN_SDCCH8_SACCH8C] = 8, - [GSM_PCHAN_TCH_F_PDCH] = 1, - [GSM_PCHAN_CCCH_SDCCH4_CBCH] = 4, - [GSM_PCHAN_SDCCH8_SACCH8C_CBCH] = 8, - /* - * GSM_PCHAN_TCH_F_TCH_H_PDCH should not be part of this, those TS are - * handled according to their ts->dyn state. - */ -}; - -/*! According to ts->pchan and possibly ts->dyn_pchan, return the number of - * logical channels available in the timeslot. */ -uint8_t ts_subslots(struct gsm_bts_trx_ts *ts) -{ - if (ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) - return subslots_per_pchan[ts->dyn.pchan_is]; - return subslots_per_pchan[ts->pchan]; -} - static struct gsm_lchan * _lc_find_trx(struct gsm_bts_trx *trx, enum gsm_phys_chan_config pchan, enum gsm_phys_chan_config dyn_as_pchan) diff --git a/openbsc/src/libcommon/gsm_data_shared.c b/openbsc/src/libcommon/gsm_data_shared.c index 2488c3a..c8c9e04 100644 --- a/openbsc/src/libcommon/gsm_data_shared.c +++ b/openbsc/src/libcommon/gsm_data_shared.c @@ -708,3 +708,28 @@ return &ts->lchan[lch_idx]; } + +static const uint8_t subslots_per_pchan[] = { + [GSM_PCHAN_NONE] = 0, + [GSM_PCHAN_CCCH] = 0, + [GSM_PCHAN_CCCH_SDCCH4] = 4, + [GSM_PCHAN_TCH_F] = 1, + [GSM_PCHAN_TCH_H] = 2, + [GSM_PCHAN_SDCCH8_SACCH8C] = 8, + [GSM_PCHAN_TCH_F_PDCH] = 1, + [GSM_PCHAN_CCCH_SDCCH4_CBCH] = 4, + [GSM_PCHAN_SDCCH8_SACCH8C_CBCH] = 8, + /* + * GSM_PCHAN_TCH_F_TCH_H_PDCH should not be part of this, those TS are + * handled according to their ts->dyn state. + */ +}; + +/*! According to ts->pchan and possibly ts->dyn_pchan, return the number of + * logical channels available in the timeslot. */ +uint8_t ts_subslots(struct gsm_bts_trx_ts *ts) +{ + if (ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) + return subslots_per_pchan[ts->dyn.pchan_is]; + return subslots_per_pchan[ts->pchan]; +} -- To view, visit https://gerrit.osmocom.org/669 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I8ba06d7dd6e0ceab3d8d18bb565354d6ed461f7e Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Sat Aug 27 01:24:26 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 01:24:26 +0000 Subject: libosmo-abis[master]: Change API to convey marker bit In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/688 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I3c2b6365d8a51bf98805614e07344d2639875fde Gerrit-PatchSet: 1 Gerrit-Project: libosmo-abis Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 01:26:03 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 01:26:03 +0000 Subject: libosmocore[master]: Add Marker to ph_tch_param In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/690 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ic664902630b9d335ff9abc7a9ca7249eaf80e05f Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 01:26:58 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 01:26:58 +0000 Subject: osmo-bts[master]: Check Marker bit to send ONSET primitive to L1 In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/691 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I88c41568bcb0d82699f617adc4ad192603dd1bb6 Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Max Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 01:27:40 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 01:27:40 +0000 Subject: openbsc[master]: sgsn: add statistics counter for LLC packets In-Reply-To: References: Message-ID: Patch Set 6: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/459 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I068376d35e84283cb98523cd3097a12c55cdb709 Gerrit-PatchSet: 6 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: lynxis lazus Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 01:27:43 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 01:27:43 +0000 Subject: [MERGED] openbsc[master]: sgsn: add statistics counter for LLC packets In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: sgsn: add statistics counter for LLC packets ...................................................................... sgsn: add statistics counter for LLC packets new counters are: llc.dl_bytes llc.ul_bytes llc.dl_packets llc.ul_packets The ip payload bytes are waiting for payload compression because those data are known then. Change-Id: I068376d35e84283cb98523cd3097a12c55cdb709 --- M openbsc/include/openbsc/sgsn.h M openbsc/src/gprs/gprs_llc.c M openbsc/src/gprs/gprs_sgsn.c 3 files changed, 15 insertions(+), 0 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified Holger Freyther: Looks good to me, but someone else must approve diff --git a/openbsc/include/openbsc/sgsn.h b/openbsc/include/openbsc/sgsn.h index 59126fe..19496cb 100644 --- a/openbsc/include/openbsc/sgsn.h +++ b/openbsc/include/openbsc/sgsn.h @@ -22,6 +22,10 @@ enum sgsn_rate_ctr_keys { + CTR_LLC_DL_BYTES, + CTR_LLC_UL_BYTES, + CTR_LLC_DL_PACKETS, + CTR_LLC_UL_PACKETS, CTR_GPRS_ATTACH_REQUEST, CTR_GPRS_ATTACH_ACKED, CTR_GPRS_ATTACH_REJECTED, diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c index 7724ebb..c77fc05 100644 --- a/openbsc/src/gprs/gprs_llc.c +++ b/openbsc/src/gprs/gprs_llc.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -330,6 +331,9 @@ fcs[2] = (fcs_calc >> 16) & 0xff; /* Identifiers passed down: (BVCI, NSEI) */ + + rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_LLC_DL_PACKETS]); + rate_ctr_add(&sgsn->rate_ctrs->ctr[CTR_LLC_DL_BYTES], msg->len); /* Send BSSGP-DL-UNITDATA.req */ return _bssgp_tx_dl_ud(msg, NULL); @@ -673,6 +677,9 @@ if (rc < 0) return rc; + rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_LLC_UL_PACKETS]); + rate_ctr_add(&sgsn->rate_ctrs->ctr[CTR_LLC_UL_BYTES], msg->len); + /* llhp.data is only set when we need to send LL_[UNIT]DATA_IND up */ if (llhp.cmd == GPRS_LLC_UI && llhp.data && llhp.data_len) { msgb_gmmh(msg) = llhp.data; diff --git a/openbsc/src/gprs/gprs_sgsn.c b/openbsc/src/gprs/gprs_sgsn.c index 502ba4a..038e6f0 100644 --- a/openbsc/src/gprs/gprs_sgsn.c +++ b/openbsc/src/gprs/gprs_sgsn.c @@ -91,6 +91,10 @@ }; static const struct rate_ctr_desc sgsn_ctr_description[] = { + { "llc.dl_bytes", "Count sent LLC bytes before giving it to the bssgp layer" }, + { "llc.ul_bytes", "Count sucessful received LLC bytes (encrypt & fcs correct)" }, + { "llc.dl_packets", "Count sucessful sent LLC packets before giving it to the bssgp layer" }, + { "llc.ul_packets", "Count sucessful received LLC packets (encrypt & fcs correct)" }, { "gprs.attach_requested", "Received attach requests" }, { "gprs.attach_accepted", "Sent attach accepts" }, { "gprs.attach_rejected", "Sent attach rejects" }, -- To view, visit https://gerrit.osmocom.org/459 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I068376d35e84283cb98523cd3097a12c55cdb709 Gerrit-PatchSet: 7 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: lynxis lazus From gerrit-no-reply at lists.osmocom.org Sat Aug 27 01:55:21 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 01:55:21 +0000 Subject: openbsc[master]: sms: change rp err cause of smpp_try_deliver errors In-Reply-To: References: Message-ID: Patch Set 1: (1 comment) https://gerrit.osmocom.org/#/c/551/1/openbsc/src/libmsc/gsm_04_11.c File openbsc/src/libmsc/gsm_04_11.c: Line 298: LOGP(DLSMS, LOGL_ERROR, "While trying to deliver a SMS the error code %d received. Sending rp err cause 41 to ms\n", rc); > we should create a dump of all fields. do we want to log the everything inc we generally don't mind logging the payload of SMS so far (we do it in other places), so we could do it here, too. But at the very least it should include the sender/recipient identities of the affected message. -- To view, visit https://gerrit.osmocom.org/551 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia03e50ce2bd9a7d1054cc5a6000fd73bd3497c03 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: lynxis lazus Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Sat Aug 27 01:57:44 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 01:57:44 +0000 Subject: openbsc[master]: libbsc/libmsc: convert old osmo counter into rate_ctrgs In-Reply-To: References: Message-ID: Patch Set 8: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/500 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ie749cebd53a0bb618d0e23d375885712078bf8dd Gerrit-PatchSet: 8 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: lynxis lazus Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 01:58:19 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 01:58:19 +0000 Subject: [MERGED] openbsc[master]: libbsc/libmsc: convert old osmo counter into rate_ctrgs In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: libbsc/libmsc: convert old osmo counter into rate_ctrgs ...................................................................... libbsc/libmsc: convert old osmo counter into rate_ctrgs rate counters support the export to statsd and can have a delta value. Change-Id: Ie749cebd53a0bb618d0e23d375885712078bf8dd --- M openbsc/include/openbsc/gsm_data.h M openbsc/src/libbsc/abis_rsl.c M openbsc/src/libbsc/bsc_init.c M openbsc/src/libbsc/bsc_vty.c M openbsc/src/libbsc/gsm_04_08_utils.c M openbsc/src/libbsc/handover_logic.c M openbsc/src/libbsc/net_init.c M openbsc/src/libbsc/paging.c M openbsc/src/libmsc/gsm_04_08.c M openbsc/src/libmsc/gsm_04_11.c M openbsc/src/libmsc/vty_interface_layer3.c 11 files changed, 152 insertions(+), 140 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index b9cb48d..6168a6b 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -7,7 +7,10 @@ #include #include +#include #include +#include + #include #include @@ -148,55 +151,79 @@ /* Some statistics of our network */ -struct gsmnet_stats { - struct { - struct osmo_counter *total; - struct osmo_counter *no_channel; - } chreq; - struct { - struct osmo_counter *attempted; - struct osmo_counter *no_channel; /* no channel available */ - struct osmo_counter *timeout; /* T3103 timeout */ - struct osmo_counter *completed; /* HO COMPL received */ - struct osmo_counter *failed; /* HO FAIL received */ - } handover; - struct { - struct osmo_counter *attach; - struct osmo_counter *normal; - struct osmo_counter *periodic; - struct osmo_counter *detach; - } loc_upd_type; - struct { - struct osmo_counter *reject; - struct osmo_counter *accept; - } loc_upd_resp; - struct { - struct osmo_counter *attempted; - struct osmo_counter *detached; - struct osmo_counter *completed; - struct osmo_counter *expired; - } paging; - struct { - struct osmo_counter *submitted; /* MO SMS submissions */ - struct osmo_counter *no_receiver; - struct osmo_counter *delivered; /* MT SMS deliveries */ - struct osmo_counter *rp_err_mem; - struct osmo_counter *rp_err_other; - } sms; - struct { - struct osmo_counter *mo_setup; - struct osmo_counter *mo_connect_ack; - struct osmo_counter *mt_setup; - struct osmo_counter *mt_connect; - } call; - struct { - struct osmo_counter *rf_fail; - struct osmo_counter *rll_err; - } chan; - struct { - struct osmo_counter *oml_fail; - struct osmo_counter *rsl_fail; - } bts; +enum { + MSC_CTR_CHREQ_TOTAL, + MSC_CTR_CHREQ_NO_CHANNEL, + MSC_CTR_HANDOVER_ATTEMPTED, + MSC_CTR_HANDOVER_NO_CHANNEL, + MSC_CTR_HANDOVER_TIMEOUT, + MSC_CTR_HANDOVER_COMPLETED, + MSC_CTR_HANDOVER_FAILED, + MSC_CTR_LOC_UPDATE_TYPE_ATTACH, + MSC_CTR_LOC_UPDATE_TYPE_NORMAL, + MSC_CTR_LOC_UPDATE_TYPE_PERIODIC, + MSC_CTR_LOC_UPDATE_TYPE_DETACH, + MSC_CTR_LOC_UPDATE_RESP_REJECT, + MSC_CTR_LOC_UPDATE_RESP_ACCEPT, + MSC_CTR_PAGING_ATTEMPTED, + MSC_CTR_PAGING_DETACHED, + MSC_CTR_PAGING_COMPLETED, + MSC_CTR_PAGING_EXPIRED, + MSC_CTR_SMS_SUBMITTED, + MSC_CTR_SMS_NO_RECEIVER, + MSC_CTR_SMS_DELIVERED, + MSC_CTR_SMS_RP_ERR_MEM, + MSC_CTR_SMS_RP_ERR_OTHER, + MSC_CTR_CALL_MO_SETUP, + MSC_CTR_CALL_MO_CONNECT_ACK, + MSC_CTR_CALL_MT_SETUP, + MSC_CTR_CALL_MT_CONNECT, + MSC_CTR_CHAN_RF_FAIL, + MSC_CTR_CHAN_RLL_ERR, + MSC_CTR_BTS_OML_FAIL, + MSC_CTR_BTS_RSL_FAIL, +}; + +static const struct rate_ctr_desc msc_ctr_description[] = { + [MSC_CTR_CHREQ_TOTAL] = {"chreq.total", "Received channel requests."}, + [MSC_CTR_CHREQ_NO_CHANNEL] = {"chreq.no_channel", "Sent to MS no channel available."}, + [MSC_CTR_HANDOVER_ATTEMPTED] = {"handover.attempted", "Received handover attempts."}, + [MSC_CTR_HANDOVER_NO_CHANNEL] = {"handover.no_channel", "Sent no channel available responses."}, + [MSC_CTR_HANDOVER_TIMEOUT] = {"handover.timeout", "Count the amount of timeouts of timer T3103."}, + [MSC_CTR_HANDOVER_COMPLETED] = {"handover.completed", "Received handover completed."}, + [MSC_CTR_HANDOVER_FAILED] = {"handover.failed", "Receive HO FAIL messages."}, + [MSC_CTR_LOC_UPDATE_TYPE_ATTACH] = {"loc_update_type.attach", "Received location update imsi attach requests."}, + [MSC_CTR_LOC_UPDATE_TYPE_NORMAL] = {"loc_update_type.normal", "Received location update normal requests."}, + [MSC_CTR_LOC_UPDATE_TYPE_PERIODIC] = {"loc_update_type.periodic", "Received location update periodic requests."}, + [MSC_CTR_LOC_UPDATE_TYPE_DETACH] = {"loc_update_type.detach", "Received location update detach indication."}, + [MSC_CTR_LOC_UPDATE_RESP_REJECT] = {"loc_update_resp.reject", "Sent location update reject responses."}, + [MSC_CTR_LOC_UPDATE_RESP_ACCEPT] = {"loc_update_resp.accept", "Sent location update accept responses."}, + [MSC_CTR_PAGING_ATTEMPTED] = {"paging.attempted", "Paging attempts for a MS."}, + [MSC_CTR_PAGING_DETACHED] = {"paging.detached", "Counts the amount of paging attempts which couldn't sent out any paging request because no responsible bts found."}, + [MSC_CTR_PAGING_COMPLETED] = {"paging.completed", "Paging successful completed."}, + [MSC_CTR_PAGING_EXPIRED] = {"paging.expired", "Paging Request expired because of timeout T3113."}, + [MSC_CTR_SMS_SUBMITTED] = {"sms.submitted", "Received a RPDU from a MS (MO)."}, + [MSC_CTR_SMS_NO_RECEIVER] = {"sms.no_receiver", "Counts SMS which couldn't routed because no receiver found."}, + [MSC_CTR_SMS_DELIVERED] = {"sms.delivered", "Global SMS Deliver attempts."}, + [MSC_CTR_SMS_RP_ERR_MEM] = {"sms.rp_err_mem", "CAUSE_MT_MEM_EXCEEDED errors of MS responses on a sms deliver attempt."}, + [MSC_CTR_SMS_RP_ERR_OTHER] = {"sms.rp_err_other", "Other error of MS responses on a sms delive attempt."}, + /* FIXME: count also sms delivered */ + [MSC_CTR_CALL_MO_SETUP] = {"call.mo_setup", "Received setup requests from a MS to init a MO call."}, + [MSC_CTR_CALL_MO_CONNECT_ACK] = {"call.mo_connect_ack", "Received a connect ack from MS of a MO call. Call is now succesful connected up."}, + [MSC_CTR_CALL_MT_SETUP] = {"call.mt_setup", "Sent setup requests to the MS (MT)."}, + [MSC_CTR_CALL_MT_CONNECT] = {"call.mt_connect", "Sent a connect to the MS (MT)."}, + [MSC_CTR_CHAN_RF_FAIL] = {"chan.rf_fail", "Received a RF failure indication from BTS."}, + [MSC_CTR_CHAN_RLL_ERR] = {"chan.rll_err", "Received a RLL failure with T200 cause from BTS."}, + [MSC_CTR_BTS_OML_FAIL] = {"bts.oml_fail", "Received a TEI down on a OML link."}, + [MSC_CTR_BTS_RSL_FAIL] = {"bts.rsl_fail", "Received a TEI down on a OML link."}, +}; + +static const struct rate_ctr_group_desc msc_ctrg_desc = { + "msc", + "mobile switching center", + OSMO_STATS_CLASS_GLOBAL, + ARRAY_SIZE(msc_ctr_description), + msc_ctr_description, }; enum gsm_auth_policy { @@ -241,7 +268,8 @@ unsigned int max_distance; /* TA values */ } handover; - struct gsmnet_stats stats; + struct rate_ctr_group *ratectrs; + /* layer 4 */ struct mncc_sock_state *mncc_state; diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index b84a0b5..092ec4e 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -1207,7 +1207,7 @@ TLVP_LEN(&tp, RSL_IE_CAUSE)); LOGPC(DRSL, LOGL_NOTICE, "\n"); - osmo_counter_inc(msg->lchan->ts->trx->bts->network->stats.chan.rf_fail); + rate_ctr_inc(&msg->lchan->ts->trx->bts->network->ratectrs->ctr[MSC_CTR_CHAN_RF_FAIL]); return rsl_rf_chan_release_err(msg->lchan); } @@ -1641,7 +1641,7 @@ lctype = get_ctype_by_chreq(bts->network, rqd_ref->ra); chreq_reason = get_reason_by_chreq(rqd_ref->ra, bts->network->neci); - osmo_counter_inc(bts->network->stats.chreq.total); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_CHREQ_TOTAL]); /* * We want LOCATION UPDATES to succeed and will assign a TCH @@ -1654,7 +1654,7 @@ if (!lchan) { LOGP(DRSL, LOGL_NOTICE, "BTS %d CHAN RQD: no resources for %s 0x%x\n", msg->lchan->ts->trx->bts->nr, gsm_lchant_name(lctype), rqd_ref->ra); - osmo_counter_inc(bts->network->stats.chreq.no_channel); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_CHREQ_NO_CHANNEL]); /* FIXME gather multiple CHAN RQD and reject up to 4 at the same time */ if (bts->network->T3122) rsl_send_imm_ass_rej(bts, 1, rqd_ref, bts->network->T3122 & 0xff); @@ -1837,7 +1837,7 @@ rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_ERR_IND); if (rlm_cause == RLL_CAUSE_T200_EXPIRED) { - osmo_counter_inc(msg->lchan->ts->trx->bts->network->stats.chan.rll_err); + rate_ctr_inc(&msg->lchan->ts->trx->bts->network->ratectrs->ctr[MSC_CTR_CHAN_RLL_ERR]); return rsl_rf_chan_release_err(msg->lchan); } diff --git a/openbsc/src/libbsc/bsc_init.c b/openbsc/src/libbsc/bsc_init.c index 5c27862..5ea85d0 100644 --- a/openbsc/src/libbsc/bsc_init.c +++ b/openbsc/src/libbsc/bsc_init.c @@ -340,9 +340,9 @@ LOGP(DLMI, LOGL_ERROR, "Lost some E1 TEI link: %d %p\n", isd->link_type, trx); if (isd->link_type == E1INP_SIGN_OML) - osmo_counter_inc(trx->bts->network->stats.bts.oml_fail); + rate_ctr_inc(&trx->bts->network->ratectrs->ctr[MSC_CTR_BTS_OML_FAIL]); else if (isd->link_type == E1INP_SIGN_RSL) - osmo_counter_inc(trx->bts->network->stats.bts.rsl_fail); + rate_ctr_inc(&trx->bts->network->ratectrs->ctr[MSC_CTR_BTS_RSL_FAIL]); /* * free all allocated channels. change the nm_state so the diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c index 6584cf0..fbaf06b 100644 --- a/openbsc/src/libbsc/bsc_vty.c +++ b/openbsc/src/libbsc/bsc_vty.c @@ -3784,18 +3784,22 @@ void openbsc_vty_print_statistics(struct vty *vty, struct gsm_network *net) { vty_out(vty, "Channel Requests : %lu total, %lu no channel%s", - osmo_counter_get(net->stats.chreq.total), - osmo_counter_get(net->stats.chreq.no_channel), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_CHREQ_TOTAL].current, + net->ratectrs->ctr[MSC_CTR_CHREQ_NO_CHANNEL].current, + VTY_NEWLINE); vty_out(vty, "Channel Failures : %lu rf_failures, %lu rll failures%s", - osmo_counter_get(net->stats.chan.rf_fail), - osmo_counter_get(net->stats.chan.rll_err), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_CHAN_RF_FAIL].current, + net->ratectrs->ctr[MSC_CTR_CHAN_RLL_ERR].current, + VTY_NEWLINE); vty_out(vty, "Paging : %lu attempted, %lu complete, %lu expired%s", - osmo_counter_get(net->stats.paging.attempted), - osmo_counter_get(net->stats.paging.completed), - osmo_counter_get(net->stats.paging.expired), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_PAGING_ATTEMPTED].current, + net->ratectrs->ctr[MSC_CTR_PAGING_COMPLETED].current, + net->ratectrs->ctr[MSC_CTR_PAGING_EXPIRED].current, + VTY_NEWLINE); vty_out(vty, "BTS failures : %lu OML, %lu RSL%s", - osmo_counter_get(net->stats.bts.oml_fail), - osmo_counter_get(net->stats.bts.rsl_fail), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_BTS_OML_FAIL].current, + net->ratectrs->ctr[MSC_CTR_BTS_RSL_FAIL].current, + VTY_NEWLINE); } DEFUN(drop_bts, diff --git a/openbsc/src/libbsc/gsm_04_08_utils.c b/openbsc/src/libbsc/gsm_04_08_utils.c index 635665a..d4eca4a 100644 --- a/openbsc/src/libbsc/gsm_04_08_utils.c +++ b/openbsc/src/libbsc/gsm_04_08_utils.c @@ -304,7 +304,7 @@ subscr = conn->subscr; } - osmo_counter_inc(bts->network->stats.paging.completed); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_PAGING_COMPLETED]); /* Stop paging on the bts we received the paging response */ paging_request_stop(conn->bts, subscr, conn, msg); diff --git a/openbsc/src/libbsc/handover_logic.c b/openbsc/src/libbsc/handover_logic.c index 52fa4af..5424e27 100644 --- a/openbsc/src/libbsc/handover_logic.c +++ b/openbsc/src/libbsc/handover_logic.c @@ -103,7 +103,7 @@ DEBUGP(DHO, "(old_lchan on BTS %u, new BTS %u)\n", old_lchan->ts->trx->bts->nr, bts->nr); - osmo_counter_inc(bts->network->stats.handover.attempted); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_HANDOVER_ATTEMPTED]); if (!old_lchan->conn) { LOGP(DHO, LOGL_ERROR, "Old lchan lacks connection data.\n"); @@ -113,7 +113,7 @@ new_lchan = lchan_alloc(bts, old_lchan->type, 0); if (!new_lchan) { LOGP(DHO, LOGL_NOTICE, "No free channel\n"); - osmo_counter_inc(bts->network->stats.handover.no_channel); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_HANDOVER_NO_CHANNEL]); return -ENOSPC; } @@ -188,7 +188,7 @@ struct gsm_network *net = ho->new_lchan->ts->trx->bts->network; DEBUGP(DHO, "HO T3103 expired\n"); - osmo_counter_inc(net->stats.handover.timeout); + rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_HANDOVER_TIMEOUT]); ho->new_lchan->conn->ho_lchan = NULL; ho->new_lchan->conn = NULL; @@ -265,7 +265,7 @@ ho->old_lchan->ts->trx->bts->nr, new_lchan->ts->trx->bts->nr, ho->old_lchan->ts->trx->arfcn, new_lchan->ts->trx->arfcn); - osmo_counter_inc(net->stats.handover.completed); + rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_HANDOVER_COMPLETED]); osmo_timer_del(&ho->T3103); @@ -303,7 +303,7 @@ return -ENODEV; } - osmo_counter_inc(net->stats.handover.failed); + rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_HANDOVER_FAILED]); new_lchan = ho->new_lchan; diff --git a/openbsc/src/libbsc/net_init.c b/openbsc/src/libbsc/net_init.c index 6d03ee4..b99f3d2 100644 --- a/openbsc/src/libbsc/net_init.c +++ b/openbsc/src/libbsc/net_init.c @@ -80,36 +80,8 @@ INIT_LLIST_HEAD(&net->upqueue); INIT_LLIST_HEAD(&net->bts_list); - net->stats.chreq.total = osmo_counter_alloc("net.chreq.total"); - net->stats.chreq.no_channel = osmo_counter_alloc("net.chreq.no_channel"); - net->stats.handover.attempted = osmo_counter_alloc("net.handover.attempted"); - net->stats.handover.no_channel = osmo_counter_alloc("net.handover.no_channel"); - net->stats.handover.timeout = osmo_counter_alloc("net.handover.timeout"); - net->stats.handover.completed = osmo_counter_alloc("net.handover.completed"); - net->stats.handover.failed = osmo_counter_alloc("net.handover.failed"); - net->stats.loc_upd_type.attach = osmo_counter_alloc("net.loc_upd_type.attach"); - net->stats.loc_upd_type.normal = osmo_counter_alloc("net.loc_upd_type.normal"); - net->stats.loc_upd_type.periodic = osmo_counter_alloc("net.loc_upd_type.periodic"); - net->stats.loc_upd_type.detach = osmo_counter_alloc("net.imsi_detach.count"); - net->stats.loc_upd_resp.reject = osmo_counter_alloc("net.loc_upd_resp.reject"); - net->stats.loc_upd_resp.accept = osmo_counter_alloc("net.loc_upd_resp.accept"); - net->stats.paging.attempted = osmo_counter_alloc("net.paging.attempted"); - net->stats.paging.detached = osmo_counter_alloc("net.paging.detached"); - net->stats.paging.completed = osmo_counter_alloc("net.paging.completed"); - net->stats.paging.expired = osmo_counter_alloc("net.paging.expired"); - net->stats.sms.submitted = osmo_counter_alloc("net.sms.submitted"); - net->stats.sms.no_receiver = osmo_counter_alloc("net.sms.no_receiver"); - net->stats.sms.delivered = osmo_counter_alloc("net.sms.delivered"); - net->stats.sms.rp_err_mem = osmo_counter_alloc("net.sms.rp_err_mem"); - net->stats.sms.rp_err_other = osmo_counter_alloc("net.sms.rp_err_other"); - net->stats.call.mo_setup = osmo_counter_alloc("net.call.mo_setup"); - net->stats.call.mo_connect_ack = osmo_counter_alloc("net.call.mo_connect_ack"); - net->stats.call.mt_setup = osmo_counter_alloc("net.call.mt_setup"); - net->stats.call.mt_connect = osmo_counter_alloc("net.call.mt_connect"); - net->stats.chan.rf_fail = osmo_counter_alloc("net.chan.rf_fail"); - net->stats.chan.rll_err = osmo_counter_alloc("net.chan.rll_err"); - net->stats.bts.oml_fail = osmo_counter_alloc("net.bts.oml_fail"); - net->stats.bts.rsl_fail = osmo_counter_alloc("net.bts.rsl_fail"); + /* init statistics */ + net->ratectrs = rate_ctr_group_alloc(net, &msc_ctrg_desc, 0); net->mncc_recv = mncc_recv; net->ext_min = GSM_MIN_EXTEN; diff --git a/openbsc/src/libbsc/paging.c b/openbsc/src/libbsc/paging.c index 9ae28e0..03c91fd 100644 --- a/openbsc/src/libbsc/paging.c +++ b/openbsc/src/libbsc/paging.c @@ -260,7 +260,7 @@ req, req->subscr->imsi); /* must be destroyed before calling cbfn, to prevent double free */ - osmo_counter_inc(req->bts->network->stats.paging.expired); + rate_ctr_inc(&req->bts->network->ratectrs->ctr[MSC_CTR_PAGING_EXPIRED]); cbfn_param = req->cbfn_param; cbfn = req->cbfn; @@ -330,7 +330,7 @@ struct gsm_bts *bts = NULL; int num_pages = 0; - osmo_counter_inc(network->stats.paging.attempted); + rate_ctr_inc(&network->ratectrs->ctr[MSC_CTR_PAGING_ATTEMPTED]); /* start paging subscriber on all BTS within Location Area */ do { @@ -349,7 +349,7 @@ } while (1); if (num_pages == 0) - osmo_counter_inc(network->stats.paging.detached); + rate_ctr_inc(&network->ratectrs->ctr[MSC_CTR_PAGING_DETACHED]); return num_pages; } diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c index 1b02efe..c4ecf1c 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/src/libmsc/gsm_04_08.c @@ -457,7 +457,7 @@ struct gsm_bts *bts = conn->bts; struct msgb *msg; - osmo_counter_inc(bts->network->stats.loc_upd_resp.reject); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_REJECT]); msg = gsm48_create_loc_upd_rej(cause); if (!msg) { @@ -506,7 +506,7 @@ DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n"); - osmo_counter_inc(bts->network->stats.loc_upd_resp.accept); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_ACCEPT]); return gsm48_conn_sendmsg(msg, conn, NULL); } @@ -637,13 +637,13 @@ switch (lu->type) { case GSM48_LUPD_NORMAL: - osmo_counter_inc(bts->network->stats.loc_upd_type.normal); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_NORMAL]); break; case GSM48_LUPD_IMSI_ATT: - osmo_counter_inc(bts->network->stats.loc_upd_type.attach); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_ATTACH]); break; case GSM48_LUPD_PERIODIC: - osmo_counter_inc(bts->network->stats.loc_upd_type.periodic); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_PERIODIC]); break; } @@ -1063,7 +1063,7 @@ DEBUGP(DMM, "IMSI DETACH INDICATION: MI(%s)=%s", gsm48_mi_type_name(mi_type), mi_string); - osmo_counter_inc(bts->network->stats.loc_upd_type.detach); + rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_DETACH]); switch (mi_type) { case GSM_MI_TYPE_TMSI: @@ -2002,7 +2002,7 @@ subscr_name(trans->subscr), trans->subscr->extension, setup.called.number); - osmo_counter_inc(trans->net->stats.call.mo_setup); + rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MO_SETUP]); /* indicate setup to MNCC */ mncc_recvmsg(trans->net, trans, MNCC_SETUP_IND, &setup); @@ -2080,7 +2080,7 @@ new_cc_state(trans, GSM_CSTATE_CALL_PRESENT); - osmo_counter_inc(trans->net->stats.call.mt_setup); + rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MT_SETUP]); return gsm48_conn_sendmsg(msg, trans->conn, trans); } @@ -2306,7 +2306,7 @@ } new_cc_state(trans, GSM_CSTATE_CONNECT_REQUEST); - osmo_counter_inc(trans->net->stats.call.mt_connect); + rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MT_CONNECT]); return mncc_recvmsg(trans->net, trans, MNCC_SETUP_CNF, &connect); } @@ -2319,7 +2319,7 @@ gsm48_stop_cc_timer(trans); new_cc_state(trans, GSM_CSTATE_ACTIVE); - osmo_counter_inc(trans->net->stats.call.mo_connect_ack); + rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MO_CONNECT_ACK]); memset(&connect_ack, 0, sizeof(struct gsm_mncc)); connect_ack.callref = trans->callref; diff --git a/openbsc/src/libmsc/gsm_04_11.c b/openbsc/src/libmsc/gsm_04_11.c index 20d18a9..fba5208 100644 --- a/openbsc/src/libmsc/gsm_04_11.c +++ b/openbsc/src/libmsc/gsm_04_11.c @@ -315,14 +315,14 @@ rc = smpp_try_deliver(gsms, conn); if (rc == 1) { rc = 1; /* cause 1: unknown subscriber */ - osmo_counter_inc(conn->bts->network->stats.sms.no_receiver); + rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); } else if (rc < 0) { rc = 21; /* cause 21: short message transfer rejected */ /* FIXME: handle the error somehow? */ } #else rc = 1; /* cause 1: unknown subscriber */ - osmo_counter_inc(conn->bts->network->stats.sms.no_receiver); + rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); #endif return rc; } @@ -363,7 +363,7 @@ uint8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */ int rc = 0; - osmo_counter_inc(conn->bts->network->stats.sms.submitted); + rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_SUBMITTED]); gsms = sms_alloc(); if (!gsms) @@ -633,10 +633,10 @@ * to store this in our database and wait for a SMMA message */ /* FIXME */ send_signal(S_SMS_MEM_EXCEEDED, trans, sms, 0); - osmo_counter_inc(net->stats.sms.rp_err_mem); + rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_MEM]); } else { send_signal(S_SMS_UNKNOWN_ERROR, trans, sms, 0); - osmo_counter_inc(net->stats.sms.rp_err_other); + rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_OTHER]); } sms_free(sms); @@ -932,7 +932,7 @@ DEBUGP(DLSMS, "TX: SMS DELIVER\n"); - osmo_counter_inc(conn->bts->network->stats.sms.delivered); + rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_DELIVERED]); db_sms_inc_deliver_attempts(trans->sms.sms); return gsm411_rp_sendmsg(&trans->sms.smr_inst, msg, diff --git a/openbsc/src/libmsc/vty_interface_layer3.c b/openbsc/src/libmsc/vty_interface_layer3.c index 74da1d7..d1041b3 100644 --- a/openbsc/src/libmsc/vty_interface_layer3.c +++ b/openbsc/src/libmsc/vty_interface_layer3.c @@ -795,34 +795,42 @@ openbsc_vty_print_statistics(vty, net); vty_out(vty, "Location Update : %lu attach, %lu normal, %lu periodic%s", - osmo_counter_get(net->stats.loc_upd_type.attach), - osmo_counter_get(net->stats.loc_upd_type.normal), - osmo_counter_get(net->stats.loc_upd_type.periodic), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_ATTACH].current, + net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_NORMAL].current, + net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_PERIODIC].current, + VTY_NEWLINE); vty_out(vty, "IMSI Detach Indications : %lu%s", - osmo_counter_get(net->stats.loc_upd_type.detach), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_DETACH].current, + VTY_NEWLINE); vty_out(vty, "Location Update Response: %lu accept, %lu reject%s", - osmo_counter_get(net->stats.loc_upd_resp.accept), - osmo_counter_get(net->stats.loc_upd_resp.reject), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_ACCEPT].current, + net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_REJECT].current, + VTY_NEWLINE); vty_out(vty, "Handover : %lu attempted, %lu no_channel, %lu timeout, " "%lu completed, %lu failed%s", - osmo_counter_get(net->stats.handover.attempted), - osmo_counter_get(net->stats.handover.no_channel), - osmo_counter_get(net->stats.handover.timeout), - osmo_counter_get(net->stats.handover.completed), - osmo_counter_get(net->stats.handover.failed), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_HANDOVER_ATTEMPTED].current, + net->ratectrs->ctr[MSC_CTR_HANDOVER_NO_CHANNEL].current, + net->ratectrs->ctr[MSC_CTR_HANDOVER_TIMEOUT].current, + net->ratectrs->ctr[MSC_CTR_HANDOVER_COMPLETED].current, + net->ratectrs->ctr[MSC_CTR_HANDOVER_FAILED].current, + VTY_NEWLINE); vty_out(vty, "SMS MO : %lu submitted, %lu no receiver%s", - osmo_counter_get(net->stats.sms.submitted), - osmo_counter_get(net->stats.sms.no_receiver), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_SMS_SUBMITTED].current, + net->ratectrs->ctr[MSC_CTR_SMS_NO_RECEIVER].current, + VTY_NEWLINE); vty_out(vty, "SMS MT : %lu delivered, %lu no memory, %lu other error%s", - osmo_counter_get(net->stats.sms.delivered), - osmo_counter_get(net->stats.sms.rp_err_mem), - osmo_counter_get(net->stats.sms.rp_err_other), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_SMS_DELIVERED].current, + net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_MEM].current, + net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_OTHER].current, + VTY_NEWLINE); vty_out(vty, "MO Calls : %lu setup, %lu connect ack%s", - osmo_counter_get(net->stats.call.mo_setup), - osmo_counter_get(net->stats.call.mo_connect_ack), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_CALL_MO_SETUP].current, + net->ratectrs->ctr[MSC_CTR_CALL_MO_CONNECT_ACK].current, + VTY_NEWLINE); vty_out(vty, "MT Calls : %lu setup, %lu connect%s", - osmo_counter_get(net->stats.call.mt_setup), - osmo_counter_get(net->stats.call.mt_connect), VTY_NEWLINE); + net->ratectrs->ctr[MSC_CTR_CALL_MT_SETUP].current, + net->ratectrs->ctr[MSC_CTR_CALL_MT_CONNECT].current, + VTY_NEWLINE); return CMD_SUCCESS; } -- To view, visit https://gerrit.osmocom.org/500 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ie749cebd53a0bb618d0e23d375885712078bf8dd Gerrit-PatchSet: 9 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: lynxis lazus From gerrit-no-reply at lists.osmocom.org Sat Aug 27 01:58:20 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 01:58:20 +0000 Subject: [MERGED] openbsc[master]: libmsc: add missing count of sms no receiver when using smpp... In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: libmsc: add missing count of sms no receiver when using smpp_first ...................................................................... libmsc: add missing count of sms no receiver when using smpp_first Change-Id: I20ecb3299d67dbaa7b016620685997db49970ffb --- M openbsc/src/libmsc/gsm_04_11.c 1 file changed, 3 insertions(+), 1 deletion(-) Approvals: Jenkins Builder: Verified Holger Freyther: Looks good to me, approved diff --git a/openbsc/src/libmsc/gsm_04_11.c b/openbsc/src/libmsc/gsm_04_11.c index fba5208..840d4d4 100644 --- a/openbsc/src/libmsc/gsm_04_11.c +++ b/openbsc/src/libmsc/gsm_04_11.c @@ -309,8 +309,10 @@ if (!gsms->receiver) { #ifdef BUILD_SMPP /* Avoid a second look-up */ - if (smpp_first) + if (smpp_first) { + rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); return 1; /* cause 1: unknown subscriber */ + } rc = smpp_try_deliver(gsms, conn); if (rc == 1) { -- To view, visit https://gerrit.osmocom.org/501 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I20ecb3299d67dbaa7b016620685997db49970ffb Gerrit-PatchSet: 4 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: lynxis lazus From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:01:16 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:01:16 +0000 Subject: libosmocore[master]: osmo_sock_init(): include host and port in error messages In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 Actually, the library should perror/fprintf directly anyway. This code is ancient legacy. It should use the libosmocore logging API instead. However, as the patch doesn't make it any worse, let's merge it. -- To view, visit https://gerrit.osmocom.org/725 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I8d0343f51310699b78fcb83fd76fd93764acf3dc Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:01:20 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:01:20 +0000 Subject: [MERGED] libosmocore[master]: osmo_sock_init(): include host and port in error messages In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: osmo_sock_init(): include host and port in error messages ...................................................................... osmo_sock_init(): include host and port in error messages For programs like osmo-hnbgw with numerous sockets, the message that some unspecified connection was refused is not very helpful. Also output the host and port where an error occured. Instead of perror, use fprintf(stderr, ..., strerror()) to be able to include a format string and print host and port as passed to osmo_sock_init(). Change-Id: I8d0343f51310699b78fcb83fd76fd93764acf3dc --- M src/socket.c 1 file changed, 16 insertions(+), 5 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/src/socket.c b/src/socket.c index 7e610bf..a36aee7 100644 --- a/src/socket.c +++ b/src/socket.c @@ -71,8 +71,11 @@ char portbuf[16]; if ((flags & (OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT)) == - (OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT)) + (OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT)) { + fprintf(stderr, "invalid: both bind and connect flags set:" + " %s:%u: %s\n", host, port); return -EINVAL; + } sprintf(portbuf, "%u", port); memset(&hints, 0, sizeof(struct addrinfo)); @@ -93,7 +96,8 @@ rc = getaddrinfo(host, portbuf, &hints, &result); if (rc != 0) { - perror("getaddrinfo returned NULL"); + fprintf(stderr, "getaddrinfo returned NULL: %s:%u: %s\n", + host, port, strerror(errno)); return -EINVAL; } @@ -109,7 +113,10 @@ continue; if (flags & OSMO_SOCK_F_NONBLOCK) { if (ioctl(sfd, FIONBIO, (unsigned char *)&on) < 0) { - perror("cannot set this socket unblocking"); + fprintf(stderr, + "cannot set this socket unblocking:" + " %s:%u: %s\n", + host, port, strerror(errno)); close(sfd); return -EINVAL; } @@ -122,7 +129,10 @@ rc = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); if (rc < 0) { - perror("cannot setsockopt socket"); + fprintf(stderr, + "cannot setsockopt socket:" + " %s:%u: %s\n", + host, port, strerror(errno)); break; } if (bind(sfd, rp->ai_addr, rp->ai_addrlen) != -1) @@ -133,7 +143,8 @@ freeaddrinfo(result); if (rp == NULL) { - perror("unable to connect/bind socket"); + fprintf(stderr, "unable to connect/bind socket: %s:%u: %s\n", + host, port, strerror(errno)); return -ENODEV; } -- To view, visit https://gerrit.osmocom.org/725 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I8d0343f51310699b78fcb83fd76fd93764acf3dc Gerrit-PatchSet: 2 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:02:09 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:02:09 +0000 Subject: openbsc[master]: add libiu In-Reply-To: References: Message-ID: Patch Set 7: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/192 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Iffc26f9c73cb15463948f7435b72ac1747aabdb3 Gerrit-PatchSet: 7 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:02:45 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:02:45 +0000 Subject: openbsc[master]: cosmetic: gprs_sgsn.c: move pdp.h include to top In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/726 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I9a9b34d714235462ba72cdb65b7c8c9824dfa9c6 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:03:09 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:03:09 +0000 Subject: openbsc[master]: gprs_gmm: Fix bit mask when determining update/attach type In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/727 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: If1dff960c406060e257dafc54132687ffc42ad8f Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: daniel Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:03:25 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:03:25 +0000 Subject: openbsc[master]: IuPS: track msg->dst aka ue_conn_ctx, comment In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/728 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I90c7ca6c3655d447aaca958e0086ae6ce6f6045a Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: daniel Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:05:40 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:05:40 +0000 Subject: openbsc[master]: IuPS: osmo-sgsn: add core IuPS impl, call iu_init() In-Reply-To: References: Message-ID: Patch Set 1: Code-Review-1 (1 comment) https://gerrit.osmocom.org/#/c/729/1/openbsc/src/gprs/sgsn_main.c File openbsc/src/gprs/sgsn_main.c: Line 305: int asn_debug; I think this at the very least deserves some explanation. Somebody who hasn't read the source code of (our modified version?) of libasn1c will probably have no idea what this is about and how to use it. Also, a VTY parameter or command line argument to set it would probably be a good idea ;) -- To view, visit https://gerrit.osmocom.org/729 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I469ae6ca9ef254d04ee0d2d79bdd65aebcd027b5 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: daniel Gerrit-Reviewer: neels_test_account Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:06:20 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:06:20 +0000 Subject: openbsc[master]: IuPS: redirect Iu in various places In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/731 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia47ffbfa6fa0f5a0cd76a379c57ef42faa0d80e3 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: daniel Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:06:48 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:06:48 +0000 Subject: openbsc[master]: IuPS: add Iu response to create_pdp_conf() In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/732 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Iad65ca9b77c3166d4df9a58af527e6aef7e589ee Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: daniel Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:07:09 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:07:09 +0000 Subject: openbsc[master]: IuPS: add Iu response to delete_pdp_conf() In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/733 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I6d601586101c0a004b2243633fab48db82b44b7c Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: daniel Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:07:29 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:07:29 +0000 Subject: openbsc[master]: IuPS: send Security Mode Command, track the new_key flag. In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/735 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I0b2593c2df13b79eb36975b0d302e31cfdf8bb09 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:07:54 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:07:54 +0000 Subject: openbsc[master]: IuPS: add GMM Service Request rx and tx In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/737 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ib935de22d23a15f449927840d4d59497ce22abbd Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:09:44 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:09:44 +0000 Subject: openbsc[master]: IuPS: GMM Service Request: add local gsm_04_08_gprs.h and .c In-Reply-To: References: Message-ID: Patch Set 1: Code-Review-1 (2 comments) https://gerrit.osmocom.org/#/c/736/1/openbsc/include/openbsc/gsm_04_08_gprs.h File openbsc/include/openbsc/gsm_04_08_gprs.h: Line 5: /* TODO: Move this to osmocom/gsm/protocol/gsm_04_08_gprs.h ? */ please let's move it into libosmocore, this clearly doens't belong to the openbsc repo. Whether or not it should use a new header file (gsm_04_08_gprs.h instead of gsm_04_08.h), I'm not entirely sure. https://gerrit.osmocom.org/#/c/736/1/openbsc/src/gprs/gsm_04_08_gprs.c File openbsc/src/gprs/gsm_04_08_gprs.c: Line 29: { GPRS_SERVICE_T_SIGNALLING, "signalling" }, this value_string should also go to libosmocore, rather libosmogsm, like the header file. -- To view, visit https://gerrit.osmocom.org/736 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Iaf9316f07d21280b6e090d65892c338f9555313a Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:09:58 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:09:58 +0000 Subject: openbsc[master]: IuPS: RA UPD: make sure to authorize, for Iu Integrity Prote... In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/738 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I2ea2089895f8a8e125ef39d9bef70dafb2b1ce69 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:10:16 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:10:16 +0000 Subject: openbsc[master]: IuPS: sgsn_mm_ctx: add enum gprs_pmm_state field, track PMM ... In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/739 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Id37778cb9a0328a21c8e8246998ecdb43dd687d8 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:10:26 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:10:26 +0000 Subject: openbsc[master]: IuPS: GMM Attach: reset MM ctx pending_req In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/740 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I0df0f3d88085939eb617405e2013ad164eed477b Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:11:01 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:11:01 +0000 Subject: openbsc[master]: IuPS: Introduce function to change PMM state In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/741 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I7c2cd1abc1805659b01dffffff31c49fe5161086 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: daniel Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:11:33 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:11:33 +0000 Subject: openbsc[master]: IuPS: Change GTP-U endpoint to SGSN in PMM_IDLE and page UE ... In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/742 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I47b73a40cbdda6b7c31fb2767f74f9f93d84056b Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: daniel Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:12:16 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:12:16 +0000 Subject: osmo-bts[master]: log: l1sap: add 0x to hex output of chan_nr, 5 times In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/745 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I187a74fd255dbdfb9bfb1e32786031a66f013efb Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:18:51 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:18:51 +0000 Subject: osmo-bts[master]: heed VTY 'line vty'/'bind' command In-Reply-To: References: Message-ID: Patch Set 1: Code-Review-1 (1 comment) https://gerrit.osmocom.org/#/c/754/1/src/common/main.c File src/common/main.c: Line 308: rc = telnet_init_dynif(tall_bts_ctx, NULL, vty_get_bind_addr(), it might be much better to log this inside libosmocore/libosmovty, so every application automatically logs the telnet interface it binds to. -- To view, visit https://gerrit.osmocom.org/754 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ic4ab32aee08d8a779adeb9943892de0c828c7b3d Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:19:32 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:19:32 +0000 Subject: osmo-pcu[master]: heed VTY 'line vty'/'bind' command In-Reply-To: References: Message-ID: Patch Set 1: Code-Review-1 should be in libosmocore/vty -- To view, visit https://gerrit.osmocom.org/753 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I4cca05a212ec0d493b906014dc3a83e687ebbb1d Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:19:43 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:19:43 +0000 Subject: osmo-pcu[master]: vty: use OSMO_VTY_PORT_PCU instead of number In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/752 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I9c5b7683f76994c539da5551f40df32379dc685e Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:19:48 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:19:48 +0000 Subject: [MERGED] osmo-pcu[master]: vty: use OSMO_VTY_PORT_PCU instead of number In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: vty: use OSMO_VTY_PORT_PCU instead of number ...................................................................... vty: use OSMO_VTY_PORT_PCU instead of number Include vty/ports.h and use the proper constant. Change-Id: I9c5b7683f76994c539da5551f40df32379dc685e --- M src/pcu_main.cpp 1 file changed, 2 insertions(+), 1 deletion(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index e34d534..afdfdc7 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -32,6 +32,7 @@ #include "pcu_vty.h" #include #include +#include #include #include #include @@ -250,7 +251,7 @@ fprintf(stderr, "No config file: '%s' Using default config.\n", config_file); - rc = telnet_init(tall_pcu_ctx, NULL, 4240); + rc = telnet_init(tall_pcu_ctx, NULL, OSMO_VTY_PORT_PCU); if (rc < 0) { fprintf(stderr, "Error initializing telnet\n"); exit(1); -- To view, visit https://gerrit.osmocom.org/752 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I9c5b7683f76994c539da5551f40df32379dc685e Gerrit-PatchSet: 2 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:20:38 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:20:38 +0000 Subject: openbsc[master]: dyn TS: move check whether to switch to PDCH to separate fun... In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/756 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I8abfa964631040f798212cc3e360f67f9e09b7c5 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:20:58 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:20:58 +0000 Subject: openbsc[master]: dyn TS: fix error recovery: switch to PDCH after lchan error... In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/757 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ie82dec9c9fefc476fdf5b5afdad2246b9d6fe304 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:22:04 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:22:04 +0000 Subject: openbsc[master]: dyn TS: clearly use lchan[0], fixing minor confusion In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/758 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I3f5d48a9bdaa49a42a1908d4a03744638c59796a Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:22:16 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:22:16 +0000 Subject: openbsc[master]: dyn TS: fix: properly run an lchan activation timeout In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/759 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ibf50d13ba10298464a8b07e34716763161438990 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:22:30 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:22:30 +0000 Subject: openbsc[master]: dyn TS: fix OS#1798: on late RF CHAN REL ACK, activate PDCH In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/760 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I87e07e1d54882f8f3d667fa300c6e3679f5c920d Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:22:51 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:22:51 +0000 Subject: openbsc[master]: dyn TS: debug log 'switchover complete' only when there was ... In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/761 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I7ddcb41edce1cd7b22fe91e33bdcaedb21856222 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:23:06 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:23:06 +0000 Subject: openbsc[master]: dyn TS: debug log: if still in use, also log lchan type and ... In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/762 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ifbf31cde24b2d1022b7a472966c17959c96e6dda Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:23:32 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:23:32 +0000 Subject: openbsc[master]: log: improve for rsl_lchan_mark_broken() In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/763 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I54ae9bbd3f193bae7b1bda1fef3e33e62b353bf5 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:23:44 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:23:44 +0000 Subject: openbsc[master]: log: rsl notice: tiny tweak for readability In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/764 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I57c3b7d27d857c96e3fa3dacf7b766bc43100fc3 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:23:48 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:23:48 +0000 Subject: [MERGED] openbsc[master]: log: rsl notice: tiny tweak for readability In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: log: rsl notice: tiny tweak for readability ...................................................................... log: rsl notice: tiny tweak for readability Change-Id: I57c3b7d27d857c96e3fa3dacf7b766bc43100fc3 --- M openbsc/src/libbsc/abis_rsl.c 1 file changed, 1 insertion(+), 1 deletion(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index d9ca550..9af986a 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -790,7 +790,7 @@ osmo_timer_del(&lchan->T3109); if (lchan->state == LCHAN_S_REL_ERR) { - LOGP(DRSL, LOGL_NOTICE, "%s is in error state not sending release.\n", + LOGP(DRSL, LOGL_NOTICE, "%s is in error state, not sending release.\n", gsm_lchan_name(lchan)); return -1; } -- To view, visit https://gerrit.osmocom.org/764 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I57c3b7d27d857c96e3fa3dacf7b766bc43100fc3 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:23:48 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:23:48 +0000 Subject: [MERGED] openbsc[master]: log: improve for rsl_lchan_mark_broken() In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: log: improve for rsl_lchan_mark_broken() ...................................................................... log: improve for rsl_lchan_mark_broken() In rsl_lchan_mark_broken(), call rsl_lchan_set_state() so the state transition gets logged in the debug log. Remove logging for the broken channel at the callers, instead log the error actually in rsl_lchan_mark_broken() itself, with the reason message passed by the caller anyway. (Removes code dup and ensures it's always logged.) Change-Id: I54ae9bbd3f193bae7b1bda1fef3e33e62b353bf5 --- M openbsc/src/libbsc/abis_rsl.c 1 file changed, 3 insertions(+), 9 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index 5a53d19..d9ca550 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -179,10 +179,6 @@ { struct gsm_lchan *lchan = data; - LOGP(DRSL, LOGL_ERROR, - "%s Timeout during activation. Marked as broken.\n", - gsm_lchan_name(lchan)); - rsl_lchan_mark_broken(lchan, "activation timeout"); lchan_free(lchan); } @@ -190,10 +186,6 @@ static void lchan_deact_tmr_cb(void *data) { struct gsm_lchan *lchan = data; - - LOGP(DRSL, LOGL_ERROR, - "%s Timeout during deactivation! Marked as broken.\n", - gsm_lchan_name(lchan)); rsl_lchan_mark_broken(lchan, "de-activation timeout"); lchan_free(lchan); @@ -1121,7 +1113,9 @@ int rsl_lchan_mark_broken(struct gsm_lchan *lchan, const char *reason) { - lchan->state = LCHAN_S_BROKEN; + LOGP(DRSL, LOGL_ERROR, "%s %s lchan broken: %s\n", + gsm_lchan_name(lchan), gsm_lchant_name(lchan->type), reason); + rsl_lchan_set_state(lchan, LCHAN_S_BROKEN); lchan->broken_reason = reason; return 0; } -- To view, visit https://gerrit.osmocom.org/763 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I54ae9bbd3f193bae7b1bda1fef3e33e62b353bf5 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:23:48 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:23:48 +0000 Subject: [MERGED] openbsc[master]: dyn TS: debug log: if still in use, also log lchan type and ... In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: dyn TS: debug log: if still in use, also log lchan type and state ...................................................................... dyn TS: debug log: if still in use, also log lchan type and state Change-Id: Ifbf31cde24b2d1022b7a472966c17959c96e6dda --- M openbsc/src/libbsc/abis_rsl.c 1 file changed, 5 insertions(+), 3 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index 0acff21..5a53d19 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -746,9 +746,11 @@ for (ss = 0; ss < ts_subslots(ts); ss++) { struct gsm_lchan *lc = &ts->lchan[ss]; if (lc->state != LCHAN_S_NONE) { - DEBUGP(DRSL, "%s lchan %u still in use\n", - gsm_ts_and_pchan_name(ts), - lc->nr); + DEBUGP(DRSL, "%s lchan %u still in use" + " (type=%s,state=%s)\n", + gsm_ts_and_pchan_name(ts), lc->nr, + gsm_lchant_name(lc->type), + gsm_lchans_name(lc->state)); /* An lchan is still used. */ return false; } -- To view, visit https://gerrit.osmocom.org/762 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ifbf31cde24b2d1022b7a472966c17959c96e6dda Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:23:48 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:23:48 +0000 Subject: [MERGED] openbsc[master]: dyn TS: debug log 'switchover complete' only when there was ... In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: dyn TS: debug log 'switchover complete' only when there was a switchover ...................................................................... dyn TS: debug log 'switchover complete' only when there was a switchover Change-Id: I7ddcb41edce1cd7b22fe91e33bdcaedb21856222 --- M openbsc/src/libbsc/abis_rsl.c 1 file changed, 3 insertions(+), 2 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index 3cf1b25..0acff21 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -2538,8 +2538,9 @@ pchan_was = ts->dyn.pchan_is; ts->dyn.pchan_is = ts->dyn.pchan_want = pchan_act; - LOGP(DRSL, LOGL_INFO, "%s switchover from %s complete.\n", - gsm_ts_and_pchan_name(ts), gsm_pchan_name(pchan_was)); + if (pchan_was != ts->dyn.pchan_is) + LOGP(DRSL, LOGL_INFO, "%s switchover from %s complete.\n", + gsm_ts_and_pchan_name(ts), gsm_pchan_name(pchan_was)); } /* Entry-point where L2 RSL from BTS enters */ -- To view, visit https://gerrit.osmocom.org/761 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I7ddcb41edce1cd7b22fe91e33bdcaedb21856222 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:23:49 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:23:49 +0000 Subject: [MERGED] openbsc[master]: dyn TS: fix OS#1798: on late RF CHAN REL ACK, activate PDCH In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: dyn TS: fix OS#1798: on late RF CHAN REL ACK, activate PDCH ...................................................................... dyn TS: fix OS#1798: on late RF CHAN REL ACK, activate PDCH Tested by hacking a REL ACK delay of a couple of seconds into osmo-bts' rsl.c for the first TCH_H lchan: [[[ diff --git a/include/osmo-bts/rsl.h b/include/osmo-bts/rsl.h index 093e9cb..b35c3bb 100644 --- a/include/osmo-bts/rsl.h +++ b/include/osmo-bts/rsl.h @@ -22,6 +22,7 @@ int rsl_tx_est_ind(struct gsm_lchan *lchan, uint8_t link_id, uint8_t *data, int int rsl_tx_chan_act_acknack(struct gsm_lchan *lchan, uint8_t cause); int rsl_tx_conn_fail(struct gsm_lchan *lchan, uint8_t cause); int rsl_tx_rf_rel_ack(struct gsm_lchan *lchan); +int rsl_tx_rf_rel_ack_later(struct gsm_lchan *lchan); int rsl_tx_hando_det(struct gsm_lchan *lchan, uint8_t *ho_delay); /* call-back for LAPDm code, called when it wants to send msgs UP */ diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 3802e25..1f92b0d 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -491,7 +491,16 @@ static int l1sap_info_rel_cnf(struct gsm_bts_trx *trx, lchan = get_lchan_by_chan_nr(trx, info_act_cnf->chan_nr); - rsl_tx_rf_rel_ack(lchan); + static int yyy = 0; + + DEBUGP(DRSL, "%s YYYYYYYYYYYYYYYYYYYYY %d %s\n", + gsm_lchan_name(lchan), yyy, gsm_lchant_name(lchan->type)); + + if (lchan->type == GSM_LCHAN_TCH_H && !yyy) { + yyy ++; + rsl_tx_rf_rel_ack_later(lchan); + } else + rsl_tx_rf_rel_ack(lchan); /* During PDCH DEACT, this marks the deactivation of the PDTCH as * requested by the PCU. Next up, we disconnect the TS completely and diff --git a/src/common/rsl.c b/src/common/rsl.c index 3c97af9..7926f21 100644 --- a/src/common/rsl.c +++ b/src/common/rsl.c @@ -534,6 +534,22 @@ int rsl_tx_rf_rel_ack(struct gsm_lchan *lchan) return abis_bts_rsl_sendmsg(msg); } +struct osmo_timer_list yyy_timer; + +static void yyy_timer_cb(void *data) +{ + rsl_tx_rf_rel_ack(data); +} + +int rsl_tx_rf_rel_ack_later(struct gsm_lchan *lchan) +{ + yyy_timer.cb = yyy_timer_cb; + yyy_timer.data = lchan; + osmo_timer_schedule(&yyy_timer, 10, 0); + return 0; +} + + /* 8.4.2 sending CHANnel ACTIVation ACKnowledge */ static int rsl_tx_chan_act_ack(struct gsm_lchan *lchan) { ]]] Change-Id: I87e07e1d54882f8f3d667fa300c6e3679f5c920d Fixes: OS#1798 --- M openbsc/src/libbsc/abis_rsl.c 1 file changed, 2 insertions(+), 0 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index edc28a7..3cf1b25 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -887,6 +887,8 @@ do_free ? "Releasing it" : "Keeping it broken"); if (do_free) do_lchan_free(lchan); + if (dyn_ts_should_switch_to_pdch(lchan->ts)) + dyn_ts_switchover_start(lchan->ts, GSM_PCHAN_PDCH); return 0; } -- To view, visit https://gerrit.osmocom.org/760 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I87e07e1d54882f8f3d667fa300c6e3679f5c920d Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:23:49 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:23:49 +0000 Subject: [MERGED] openbsc[master]: dyn TS: fix: properly run an lchan activation timeout In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: dyn TS: fix: properly run an lchan activation timeout ...................................................................... dyn TS: fix: properly run an lchan activation timeout Actually schedule an activation timer for the activation part of a dyn TS switchover. It needs to be restarted because the channel release procedure in the first part of a switchover actually removes the activation timer. Change-Id: Ibf50d13ba10298464a8b07e34716763161438990 --- M openbsc/src/libbsc/abis_rsl.c 1 file changed, 7 insertions(+), 0 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index 42281ba..edc28a7 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -2487,6 +2487,13 @@ lchan->dyn.rqd_ref = NULL; lchan->dyn.rqd_ta = 0; + /* During switchover, we have received a release ack, which means that + * the act_timer has been stopped. Start the timer again so we mark + * this channel broken if the activation ack comes too late. */ + lchan->act_timer.cb = lchan_act_tmr_cb; + lchan->act_timer.data = lchan; + osmo_timer_schedule(&lchan->act_timer, 4, 0); + rc = rsl_chan_activate_lchan(lchan, act_type, ho_ref); if (rc) { LOGP(DRSL, LOGL_ERROR, -- To view, visit https://gerrit.osmocom.org/759 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ibf50d13ba10298464a8b07e34716763161438990 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:23:49 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:23:49 +0000 Subject: [MERGED] openbsc[master]: dyn TS: clearly use lchan[0], fixing minor confusion In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: dyn TS: clearly use lchan[0], fixing minor confusion ...................................................................... dyn TS: clearly use lchan[0], fixing minor confusion The dyn_ts_switchover_*() functions made the impression that they act on a specific lchan of a timeslot. The assumption that we would remember to use e.g. lchan[1] across a PDCH deactivation is brain damaged to begin with; and factually we always use lchan[0] anyway (the only case for using lchan[1] would be when switching to TCH/H, but the channel allocator will always return lchan[0] for that). Instead of the brain damaged lchan args, use a ts arg across all dyn_ts_switchover_*() functions, with one exception: The dyn_ts_switchover_complete() actually receives an RSL activation ack message on a specific lchan and needs to evaluate its lchan type. This will always be lchan[0] as it is now, but we should stick with the lchan the message was sent for. For PDCH, a check to use lchan[0] already existed, when composing the ACT message in rsl_chan_activate_lchan_as_pdch(). Replace with an assertion. Adjust all callers to pass ts instead of lchan. In dyn_ts_switchover_start(), there was a dead code check that jumps to switchover_complete() in case the pchan already matches. This never hits, because we only call dyn_ts_switchover_start() when pchans mismatch. So avoid guessing at passing lchan[0] to dyn_ts_switchover_complete() by not calling it at all but logging an error instead. In rsl_chan_activate_lchan(), we remember some values before going into switchover from PDCH. Explicitly store them in lchan[0], because after a PDCH release we have always and will activate no other than lchan[0]. In dyn_ts_switchover_continue(), move the check for any existing lchan->rqd_ref further above, and more correctly check all lchans that were so far valid on the TS, instead of just one. This partly prepares for a subsequent commit to fix the act_timer use for dyn TS: with the old lchan arg, we might schedule an activation timer on lchan[1] but receive an ack on lchan[0] (for PDCH), leading to an act_timer expiry. Change-Id: I3f5d48a9bdaa49a42a1908d4a03744638c59796a --- M openbsc/include/openbsc/abis_rsl.h M openbsc/src/libbsc/abis_rsl.c M openbsc/src/libbsc/bsc_dyn_ts.c 3 files changed, 56 insertions(+), 42 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/openbsc/include/openbsc/abis_rsl.h b/openbsc/include/openbsc/abis_rsl.h index 8313f48..758c555 100644 --- a/openbsc/include/openbsc/abis_rsl.h +++ b/openbsc/include/openbsc/abis_rsl.h @@ -108,7 +108,7 @@ int rsl_direct_rf_release(struct gsm_lchan *lchan); void dyn_ts_init(struct gsm_bts_trx_ts *ts); -int dyn_ts_switchover_start(struct gsm_lchan *lchan, +int dyn_ts_switchover_start(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config to_pchan); #endif /* RSL_MT_H */ diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index d04b707..42281ba 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -55,8 +55,8 @@ static int rsl_send_imm_assignment(struct gsm_lchan *lchan); static void error_timeout_cb(void *data); -static int dyn_ts_switchover_continue(struct gsm_lchan *lchan); -static int dyn_ts_switchover_failed(struct gsm_lchan *lchan, int rc); +static int dyn_ts_switchover_continue(struct gsm_bts_trx_ts *ts); +static int dyn_ts_switchover_failed(struct gsm_bts_trx_ts *ts, int rc); static void dyn_ts_switchover_complete(struct gsm_lchan *lchan); static void send_lchan_signal(int sig_no, struct gsm_lchan *lchan, @@ -460,9 +460,9 @@ struct abis_rsl_dchan_hdr *dh; /* This might be called after release of the second lchan of a TCH/H, - * but PDCH activation should always happen on the first lchan. So - * switch to lchan->nr == 0. */ - lchan = lchan->ts->lchan; + * but PDCH activation must always happen on the first lchan. Make sure + * the calling code passes the correct lchan. */ + OSMO_ASSERT(lchan == lchan->ts->lchan); rsl_lchan_set_state(lchan, LCHAN_S_ACT_REQ); @@ -521,16 +521,21 @@ enum gsm_phys_chan_config pchan_want; pchan_want = pchan_for_lchant(lchan->type); if (lchan->ts->dyn.pchan_is != pchan_want) { - lchan->dyn.act_type = act_type, - lchan->dyn.ho_ref = ho_ref; - lchan->dyn.rqd_ref = lchan->rqd_ref; - lchan->dyn.rqd_ta = lchan->rqd_ta; + /* + * Make sure to record on lchan[0] so that we'll find + * it after the PDCH release. + */ + struct gsm_lchan *lchan0 = lchan->ts->lchan; + lchan0->dyn.act_type = act_type, + lchan0->dyn.ho_ref = ho_ref; + lchan0->dyn.rqd_ref = lchan->rqd_ref; + lchan0->dyn.rqd_ta = lchan->rqd_ta; lchan->rqd_ref = NULL; lchan->rqd_ta = 0; DEBUGP(DRSL, "%s saved rqd_ref=%p ta=%u\n", - gsm_lchan_name(lchan), lchan->rqd_ref, - lchan->rqd_ta); - return dyn_ts_switchover_start(lchan, pchan_want); + gsm_lchan_name(lchan0), lchan0->rqd_ref, + lchan0->rqd_ta); + return dyn_ts_switchover_start(lchan->ts, pchan_want); } } @@ -774,7 +779,7 @@ rsl_ipacc_pdch_activate(lchan->ts, 1); if (dyn_ts_should_switch_to_pdch(lchan->ts)) - dyn_ts_switchover_start(lchan, GSM_PCHAN_PDCH); + dyn_ts_switchover_start(lchan->ts, GSM_PCHAN_PDCH); } static int rsl_rx_rf_chan_rel_ack(struct gsm_lchan *lchan); @@ -910,11 +915,11 @@ /* (a) */ if (ts->dyn.pchan_is != ts->dyn.pchan_want) - return dyn_ts_switchover_continue(lchan); + return dyn_ts_switchover_continue(ts); /* (b) */ if (dyn_ts_should_switch_to_pdch(ts)) - return dyn_ts_switchover_start(lchan, GSM_PCHAN_PDCH); + return dyn_ts_switchover_start(ts, GSM_PCHAN_PDCH); } /* @@ -2338,11 +2343,10 @@ return rc; } -int dyn_ts_switchover_start(struct gsm_lchan *lchan, +int dyn_ts_switchover_start(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config to_pchan) { int ss; - struct gsm_bts_trx_ts *ts = lchan->ts; int rc = -EIO; OSMO_ASSERT(ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH); @@ -2360,15 +2364,14 @@ if (ts->dyn.pchan_is == to_pchan) { LOGP(DRSL, LOGL_INFO, - "%s %s Already is in %s mode, skipping switchover.\n", + "%s %s Already is in %s mode, cannot switchover.\n", gsm_ts_name(ts), gsm_pchan_name(ts->pchan), gsm_pchan_name(to_pchan)); - dyn_ts_switchover_complete(lchan); - return 0; + return -EINVAL; } /* Paranoia: let's make sure all is indeed released. */ - for (ss = 0; ss < ts_subslots(lchan->ts); ss++) { + for (ss = 0; ss < ts_subslots(ts); ss++) { struct gsm_lchan *lc = &ts->lchan[ss]; if (lc->state != LCHAN_S_NONE) { LOGP(DRSL, LOGL_ERROR, @@ -2386,16 +2389,16 @@ /* * To switch from PDCH, we need to initiate the release from the BSC * side. dyn_ts_switchover_continue() will be called from - * rsl_rx_rf_chan_rel_ack(). + * rsl_rx_rf_chan_rel_ack(). PDCH is always on lchan[0]. */ if (ts->dyn.pchan_is == GSM_PCHAN_PDCH) { - rsl_lchan_set_state(lchan, LCHAN_S_REL_REQ); - rc = rsl_rf_chan_release(lchan, 0, SACCH_NONE); + rsl_lchan_set_state(ts->lchan, LCHAN_S_REL_REQ); + rc = rsl_rf_chan_release(ts->lchan, 0, SACCH_NONE); if (rc) { LOGP(DRSL, LOGL_ERROR, "%s RSL RF Chan Release failed\n", gsm_ts_and_pchan_name(ts)); - return dyn_ts_switchover_failed(lchan, rc); + return dyn_ts_switchover_failed(ts, rc); } return 0; } @@ -2405,15 +2408,16 @@ * rsl_rx_rf_chan_rel_ack(), i.e. release is complete. Go ahead and * activate as new type. This will always be PDCH. */ - return dyn_ts_switchover_continue(lchan); + return dyn_ts_switchover_continue(ts); } -static int dyn_ts_switchover_continue(struct gsm_lchan *lchan) +static int dyn_ts_switchover_continue(struct gsm_bts_trx_ts *ts) { int rc; uint8_t act_type; uint8_t ho_ref; - struct gsm_bts_trx_ts *ts = lchan->ts; + int ss; + struct gsm_lchan *lchan; OSMO_ASSERT(ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH); DEBUGP(DRSL, "%s switchover: release complete," @@ -2427,6 +2431,25 @@ gsm_ts_and_pchan_name(ts)); return 0; } + + for (ss = 0; ss < ts_subslots(ts); ss++) { + lchan = &ts->lchan[ss]; + if (lchan->rqd_ref) { + LOGP(DRSL, LOGL_ERROR, + "%s During dyn TS switchover, expecting no" + " Request Reference to be pending. Discarding!\n", + gsm_lchan_name(lchan)); + talloc_free(lchan->rqd_ref); + lchan->rqd_ref = NULL; + } + } + + /* + * When switching pchan modes, all lchans are unused. So always + * activate whatever wants to be activated on the first lchan. (We + * wouldn't remember to use lchan[1] across e.g. a PDCH deact anyway) + */ + lchan = ts->lchan; /* * For TCH/x, the lchan->type has been set in lchan_alloc(), but it may @@ -2459,14 +2482,6 @@ : lchan->dyn.ho_ref; /* Fetch the rqd_ref back from before switchover started. */ - if (lchan->rqd_ref) { - LOGP(DRSL, LOGL_ERROR, - "%s During dyn TS switchover, expecting no" - " Request Reference to be pending. Discarding!\n", - gsm_lchan_name(lchan)); - talloc_free(lchan->rqd_ref); - lchan->rqd_ref = NULL; - } lchan->rqd_ref = lchan->dyn.rqd_ref; lchan->rqd_ta = lchan->dyn.rqd_ta; lchan->dyn.rqd_ref = NULL; @@ -2477,14 +2492,13 @@ LOGP(DRSL, LOGL_ERROR, "%s RSL Chan Activate failed\n", gsm_ts_and_pchan_name(ts)); - return dyn_ts_switchover_failed(lchan, rc); + return dyn_ts_switchover_failed(ts, rc); } return 0; } -static int dyn_ts_switchover_failed(struct gsm_lchan *lchan, int rc) +static int dyn_ts_switchover_failed(struct gsm_bts_trx_ts *ts, int rc) { - struct gsm_bts_trx_ts *ts = lchan->ts; ts->dyn.pchan_want = ts->dyn.pchan_is; LOGP(DRSL, LOGL_ERROR, "%s Error %d during dynamic channel switchover." " Going back to previous pchan.\n", gsm_ts_and_pchan_name(ts), @@ -2510,7 +2524,7 @@ LOGP(DRSL, LOGL_ERROR, "%s Requested transition does not match lchan type %s\n", gsm_ts_and_pchan_name(ts), - gsm_lchant_name(ts->lchan[0].type)); + gsm_lchant_name(lchan->type)); pchan_was = ts->dyn.pchan_is; ts->dyn.pchan_is = ts->dyn.pchan_want = pchan_act; diff --git a/openbsc/src/libbsc/bsc_dyn_ts.c b/openbsc/src/libbsc/bsc_dyn_ts.c index 456500a..e5422fc 100644 --- a/openbsc/src/libbsc/bsc_dyn_ts.c +++ b/openbsc/src/libbsc/bsc_dyn_ts.c @@ -52,7 +52,7 @@ return; } - dyn_ts_switchover_start(ts->lchan, GSM_PCHAN_PDCH); + dyn_ts_switchover_start(ts, GSM_PCHAN_PDCH); } void dyn_ts_init(struct gsm_bts_trx_ts *ts) -- To view, visit https://gerrit.osmocom.org/758 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I3f5d48a9bdaa49a42a1908d4a03744638c59796a Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:23:49 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:23:49 +0000 Subject: [MERGED] openbsc[master]: dyn TS: fix error recovery: switch to PDCH after lchan error... In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: dyn TS: fix error recovery: switch to PDCH after lchan error state ...................................................................... dyn TS: fix error recovery: switch to PDCH after lchan error state Tested by hacking a CHAN ACT ACK delay of a couple of seconds into osmo-bts' rsl.c for the first TCH_H lchan: [[[ diff --git a/src/common/rsl.c b/src/common/rsl.c index 3c97af9..4bfd27a 100644 --- a/src/common/rsl.c +++ b/src/common/rsl.c @@ -559,6 +559,22 @@ static int rsl_tx_chan_act_ack(struct gsm_lchan *lchan) return abis_bts_rsl_sendmsg(msg); } +struct osmo_timer_list xxx_timer; + +static void xxx_timer_cb(void *data) +{ + rsl_tx_chan_act_ack(data); +} + +static int rsl_tx_chan_act_ack_later(struct gsm_lchan *lchan) +{ + xxx_timer.cb = xxx_timer_cb; + xxx_timer.data = lchan; + osmo_timer_schedule(&xxx_timer, 10, 0); + return 0; +} + + /* 8.4.7 sending HANDOver DETection */ int rsl_tx_hando_det(struct gsm_lchan *lchan, uint8_t *ho_delay) { @@ -614,6 +630,18 @@ int rsl_tx_chan_act_acknack(struct gsm_lchan *lchan, uint8_t cause) if (cause) return rsl_tx_chan_act_nack(lchan, cause); + + static int xxx = 0; + + DEBUGP(DRSL, "%s XXXXXXXXXXXXXXXXXXXXX %d %s\n", + gsm_lchan_name(lchan), xxx, gsm_lchant_name(lchan->type)); + + if (lchan->type == GSM_LCHAN_TCH_H) { + if (!xxx) { + xxx ++; + return rsl_tx_chan_act_ack_later(lchan); + } + } return rsl_tx_chan_act_ack(lchan); } ]]] Change-Id: Ie82dec9c9fefc476fdf5b5afdad2246b9d6fe304 --- M openbsc/src/libbsc/abis_rsl.c 1 file changed, 3 insertions(+), 0 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index 2752c0d..d04b707 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -772,6 +772,9 @@ if (lchan->ts->pchan == GSM_PCHAN_TCH_F_PDCH && lchan->ts->trx->bts->gprs.mode != BTS_GPRS_NONE) rsl_ipacc_pdch_activate(lchan->ts, 1); + + if (dyn_ts_should_switch_to_pdch(lchan->ts)) + dyn_ts_switchover_start(lchan, GSM_PCHAN_PDCH); } static int rsl_rx_rf_chan_rel_ack(struct gsm_lchan *lchan); -- To view, visit https://gerrit.osmocom.org/757 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ie82dec9c9fefc476fdf5b5afdad2246b9d6fe304 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Sat Aug 27 02:23:50 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 02:23:50 +0000 Subject: [MERGED] openbsc[master]: dyn TS: move check whether to switch to PDCH to separate fun... In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: dyn TS: move check whether to switch to PDCH to separate function ...................................................................... dyn TS: move check whether to switch to PDCH to separate function Prepares for an upcoming commit using the same check in error_timeout_cb(). Change-Id: I8abfa964631040f798212cc3e360f67f9e09b7c5 --- M openbsc/src/libbsc/abis_rsl.c 1 file changed, 33 insertions(+), 17 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index 092ec4e..2752c0d 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -723,6 +723,38 @@ return abis_rsl_sendmsg(msg); } +static bool dyn_ts_should_switch_to_pdch(struct gsm_bts_trx_ts *ts) +{ + int ss; + + if (ts->pchan != GSM_PCHAN_TCH_F_TCH_H_PDCH) + return false; + + if (ts->trx->bts->gprs.mode == BTS_GPRS_NONE) + return false; + + /* Already in PDCH mode? */ + if (ts->dyn.pchan_is == GSM_PCHAN_PDCH) + return false; + + /* See if all lchans are released. */ + for (ss = 0; ss < ts_subslots(ts); ss++) { + struct gsm_lchan *lc = &ts->lchan[ss]; + if (lc->state != LCHAN_S_NONE) { + DEBUGP(DRSL, "%s lchan %u still in use\n", + gsm_ts_and_pchan_name(ts), + lc->nr); + /* An lchan is still used. */ + return false; + } + } + + /* All channels are released, go to PDCH mode. */ + DEBUGP(DRSL, "%s back to PDCH\n", + gsm_ts_and_pchan_name(ts)); + return true; +} + static void error_timeout_cb(void *data) { struct gsm_lchan *lchan = data; @@ -824,7 +856,6 @@ static int rsl_rx_rf_chan_rel_ack(struct gsm_lchan *lchan) { - int ss; struct gsm_bts_trx_ts *ts = lchan->ts; DEBUGP(DRSL, "%s RF CHANNEL RELEASE ACK\n", gsm_lchan_name(lchan)); @@ -879,23 +910,8 @@ return dyn_ts_switchover_continue(lchan); /* (b) */ - if (ts->dyn.pchan_is != GSM_PCHAN_PDCH - && ts->trx->bts->gprs.mode != BTS_GPRS_NONE) { - for (ss = 0; ss < ts_subslots(ts); ss++) { - struct gsm_lchan *lc = &ts->lchan[ss]; - if (lc->state != LCHAN_S_NONE) { - DEBUGP(DRSL, "%s lchan %u still in use\n", - gsm_ts_and_pchan_name(ts), - lc->nr); - /* An lchan is still used. */ - return 0; - } - } - /* All channels are released, go to PDCH mode. */ - DEBUGP(DRSL, "%s back to PDCH\n", - gsm_ts_and_pchan_name(ts)); + if (dyn_ts_should_switch_to_pdch(ts)) return dyn_ts_switchover_start(lchan, GSM_PCHAN_PDCH); - } } /* -- To view, visit https://gerrit.osmocom.org/756 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I8abfa964631040f798212cc3e360f67f9e09b7c5 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Sat Aug 27 04:43:41 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 04:43:41 +0000 Subject: openbsc[master]: Adding LLC-XID encoder / decoder and unit test In-Reply-To: References: Message-ID: Patch Set 10: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/638 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia06e4cb08bf9b48c2a4682606d1b1a91d19a9d37 Gerrit-PatchSet: 10 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 04:44:37 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 04:44:37 +0000 Subject: openbsc[master]: Adding LLC-XID related modifications in LLC In-Reply-To: References: Message-ID: Patch Set 14: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/652 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I65b9d625e72d3d61c99abdc7041773701d694d52 Gerrit-PatchSet: 14 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 04:45:48 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 04:45:48 +0000 Subject: openbsc[master]: Adding SNDCP-XID encoder / decoder and unit test In-Reply-To: References: Message-ID: Patch Set 13: Code-Review+1 therre's still neels' comment regarding s01 as uint8_t. -- To view, visit https://gerrit.osmocom.org/641 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e Gerrit-PatchSet: 13 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 04:45:55 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 04:45:55 +0000 Subject: [MERGED] openbsc[master]: Adding LLC-XID related modifications in LLC In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: Adding LLC-XID related modifications in LLC ...................................................................... Adding LLC-XID related modifications in LLC With this commit the already existing XID mechanism has been modified to suit the needs for the upcomming SNDCP-XID patches. This commit should not break anything since it does not alter the current behaviour (incoming XID is still just echoed, on GMM-Reset a basic XID message is still echoed) Change-Id: I65b9d625e72d3d61c99abdc7041773701d694d52 --- M openbsc/include/openbsc/gprs_llc.h M openbsc/src/gprs/gprs_llc.c M openbsc/tests/sgsn/Makefile.am 3 files changed, 315 insertions(+), 57 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h index 0e497a0..c3b82b1 100644 --- a/openbsc/include/openbsc/gprs_llc.h +++ b/openbsc/include/openbsc/gprs_llc.h @@ -4,6 +4,7 @@ #include #include #include +#include /* Section 4.7 LLC Layer Structure */ enum gprs_llc_sapi { @@ -166,6 +167,13 @@ uint16_t nsei; struct gprs_llc_lle lle[NUM_SAPIS]; + /* Copy of the XID fields we have sent with the last + * network originated XID-Request. Since the phone + * may strip the optional fields in the confirmation + * we need to remeber those fields in order to be + * able to create the compression entity. */ + struct llist_head *xid; + /* Internal management */ uint32_t age_timestamp; }; @@ -219,6 +227,10 @@ int gprs_llgmm_reset_oldmsg(struct msgb* oldmsg, uint8_t sapi, struct gprs_llc_llme *llme); +/* Set of LL-XID negotiation (See also: TS 101 351, Section 7.2.2.4) */ +int gprs_ll_xid_req(struct gprs_llc_lle *lle, + struct gprs_llc_xid_field *l3_xid_field); + /* 04.64 Chapter 7.2.1.1 LLGMM-ASSIGN */ int gprs_llgmm_assign(struct gprs_llc_llme *llme, uint32_t old_tlli, uint32_t new_tlli); diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c index c77fc05..32920da 100644 --- a/openbsc/src/gprs/gprs_llc.c +++ b/openbsc/src/gprs/gprs_llc.c @@ -39,8 +39,286 @@ #include #include #include +#include +#include static struct gprs_llc_llme *llme_alloc(uint32_t tlli); +static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg, + int command); +static int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi, + int command, enum gprs_llc_u_cmd u_cmd, int pf_bit); + +/* BEGIN XID RELATED */ + +/* Generate XID message */ +static int gprs_llc_generate_xid(uint8_t *bytes, int bytes_len, + struct gprs_llc_xid_field *l3_xid_field, + struct gprs_llc_llme *llme) +{ + /* Note: Called by gprs_ll_xid_req() */ + + LLIST_HEAD(xid_fields); + + struct gprs_llc_xid_field xid_version; + struct gprs_llc_xid_field xid_n201u; + struct gprs_llc_xid_field xid_n201i; + + xid_version.type = GPRS_LLC_XID_T_VERSION; + xid_version.data = (uint8_t *) "\x00"; + xid_version.data_len = 1; + + xid_n201u.type = GPRS_LLC_XID_T_N201_U; + xid_n201u.data = (uint8_t *) "\x05\xf0"; + xid_n201u.data_len = 2; + + xid_n201i.type = GPRS_LLC_XID_T_N201_I; + xid_n201i.data = (uint8_t *) "\x05\xf0"; + xid_n201i.data_len = 2; + + /* Add locally managed XID Fields */ + llist_add(&xid_n201i.list, &xid_fields); + llist_add(&xid_n201u.list, &xid_fields); + llist_add(&xid_version.list, &xid_fields); + + /* Append layer 3 XID field (if present) */ + if (l3_xid_field) { + /* Enforce layer 3 XID type (just to be sure) */ + l3_xid_field->type = GPRS_LLC_XID_T_L3_PAR; + + /* Add Layer 3 XID field to the list */ + llist_add(&l3_xid_field->list, &xid_fields); + } + + /* Store generated XID for later reference */ + talloc_free(llme->xid); + llme->xid = gprs_llc_copy_xid(llme, &xid_fields); + + return gprs_llc_compile_xid(bytes, bytes_len, &xid_fields); +} + +/* Generate XID message that will cause the GMM to reset */ +static int gprs_llc_generate_xid_for_gmm_reset(uint8_t *bytes, + int bytes_len, uint32_t iov_ui, + struct gprs_llc_llme *llme) +{ + /* Called by gprs_llgmm_reset() and + * gprs_llgmm_reset_oldmsg() */ + + LLIST_HEAD(xid_fields); + + struct gprs_llc_xid_field xid_reset; + struct gprs_llc_xid_field xid_iovui; + + /* First XID component must be RESET */ + xid_reset.type = GPRS_LLC_XID_T_RESET; + xid_reset.data = NULL; + xid_reset.data_len = 0; + + /* Add new IOV-UI */ + xid_iovui.type = GPRS_LLC_XID_T_IOV_UI; + xid_iovui.data = (uint8_t *) & iov_ui; + xid_iovui.data_len = 4; + + /* Add locally managed XID Fields */ + llist_add(&xid_iovui.list, &xid_fields); + llist_add(&xid_reset.list, &xid_fields); + + /* Store generated XID for later reference */ + talloc_free(llme->xid); + llme->xid = gprs_llc_copy_xid(llme, &xid_fields); + + return gprs_llc_compile_xid(bytes, bytes_len, &xid_fields); +} + +/* Process an incoming XID confirmation */ +static int gprs_llc_process_xid_conf(uint8_t *bytes, int bytes_len, + struct gprs_llc_lle *lle) +{ + /* Note: This function handles the response of a network originated + * XID-Request. There XID messages reflected by the phone are analyzed + * and processed here. The caller is called by rx_llc_xid(). */ + + struct llist_head *xid_fields; + struct gprs_llc_xid_field *xid_field; + + /* Parse and analyze XID-Response */ + xid_fields = gprs_llc_parse_xid(NULL, bytes, bytes_len); + + if (xid_fields) { + + gprs_llc_dump_xid_fields(xid_fields, LOGL_DEBUG); + llist_for_each_entry(xid_field, xid_fields, list) { + + /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { + LOGP(DLLC, LOGL_NOTICE, + "Ignoring SNDCP-XID-Field: XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + osmo_hexdump_nospc(xid_field->data, + xid_field->data_len)); + } + + /* Process LLC-XID fields: */ + else { + + /* FIXME: Do something more useful with the + * echoed XID-Information. Currently we + * just ignore the response completely and + * by doing so we blindly accept any changes + * the MS might have done to the our XID + * inquiry. There is a remainig risk of + * malfunction! */ + LOGP(DLLC, LOGL_NOTICE, + "Ignoring XID-Field: XID: type=%d, data_len=%d, data=%s\n", + xid_field->type, xid_field->data_len, + osmo_hexdump_nospc(xid_field->data, + xid_field->data_len)); + } + } + talloc_free(xid_fields); + } + + /* Flush pending XID fields */ + talloc_free(lle->llme->xid); + lle->llme->xid = NULL; + + return 0; +} + +/* Process an incoming XID indication and generate an appropiate response */ +static int gprs_llc_process_xid_ind(uint8_t *bytes_request, + int bytes_request_len, + uint8_t *bytes_response, + int bytes_response_maxlen, + struct gprs_llc_lle *lle) +{ + /* Note: This function computes the response that is sent back to the + * phone when a phone originated XID is received. The function is + * called by rx_llc_xid() */ + + int rc = -EINVAL; + + struct llist_head *xid_fields; + struct llist_head *xid_fields_response; + + struct gprs_llc_xid_field *xid_field; + struct gprs_llc_xid_field *xid_field_response; + + /* Flush eventually pending XID fields */ + talloc_free(lle->llme->xid); + lle->llme->xid = NULL; + + /* Parse and analyze XID-Request */ + xid_fields = + gprs_llc_parse_xid(lle->llme, bytes_request, bytes_request_len); + if (xid_fields) { + xid_fields_response = talloc_zero(lle->llme, struct llist_head); + INIT_LLIST_HEAD(xid_fields_response); + gprs_llc_dump_xid_fields(xid_fields, LOGL_DEBUG); + + /* Process LLC-XID fields: */ + llist_for_each_entry(xid_field, xid_fields, list) { + + if (xid_field->type != GPRS_LLC_XID_T_L3_PAR) { + /* FIXME: Check the incoming XID parameters for + * for validity. Currently we just blindly + * accept all XID fields by just echoing them. + * There is a remaining risk of malfunction + * when a phone submits values which defer from + * the default! */ + LOGP(DLLC, LOGL_NOTICE, + "Echoing XID-Field: XID: type=%d, data_len=%d, data=%s\n", + xid_field->type, xid_field->data_len, + osmo_hexdump_nospc(xid_field->data, + xid_field->data_len)); + xid_field_response = + gprs_llc_dup_xid_field + (lle->llme, xid_field); + llist_add(&xid_field_response->list, + xid_fields_response); + } + } + + rc = gprs_llc_compile_xid(bytes_response, + bytes_response_maxlen, + xid_fields_response); + talloc_free(xid_fields_response); + talloc_free(xid_fields); + } + + return rc; +} + +/* Dispatch XID indications and responses comming from the Phone */ +static void rx_llc_xid(struct gprs_llc_lle *lle, + struct gprs_llc_hdr_parsed *gph) +{ + uint8_t response[1024]; + int response_len; + + /* FIXME: 8.5.3.3: check if XID is invalid */ + if (gph->is_cmd) { + LOGP(DLLC, LOGL_NOTICE, + "Received XID indication from phone.\n"); + + struct msgb *resp; + uint8_t *xid; + resp = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + + response_len = + gprs_llc_process_xid_ind(gph->data, gph->data_len, + response, sizeof(response), + lle); + xid = msgb_put(resp, response_len); + memcpy(xid, response, response_len); + + gprs_llc_tx_xid(lle, resp, 0); + } else { + LOGP(DLLC, LOGL_NOTICE, + "Received XID confirmation from phone.\n"); + gprs_llc_process_xid_conf(gph->data, gph->data_len, lle); + /* FIXME: if we had sent a XID reset, send + * LLGMM-RESET.conf to GMM */ + } +} + + +/* Set of LL-XID negotiation (See also: TS 101 351, Section 7.2.2.4) */ +int gprs_ll_xid_req(struct gprs_llc_lle *lle, + struct gprs_llc_xid_field *l3_xid_field) +{ + /* Note: This functions is calle from gprs_sndcp.c */ + + uint8_t xid_bytes[1024];; + int xid_bytes_len; + uint8_t *xid; + struct msgb *msg; + + /* Generate XID */ + xid_bytes_len = + gprs_llc_generate_xid(xid_bytes, sizeof(xid_bytes), + l3_xid_field, lle->llme); + + /* Only perform XID sending if the XID message contains something */ + if (xid_bytes_len > 0) { + /* Transmit XID bytes */ + msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); + LOGP(DLLC, LOGL_NOTICE, "Sending XID request to phone...\n"); + gprs_llc_tx_xid(lle, msg, 1); + } else { + LOGP(DLLC, LOGL_ERROR, + "XID-Message generation failed, XID not sent!\n"); + return -EINVAL; + } + + return 0; +} +/* END XID RELATED */ + + + /* Entry function from upper level (LLC), asking us to transmit a BSSGP PDU * to a remote MS (identified by TLLI) at a BTS identified by its BVCI and NSEI */ @@ -52,7 +330,7 @@ memset(&dup, 0, sizeof(dup)); /* before we have received some identity from the MS, we might * not yet have a MMC context (e.g. XID negotiation of primarly - * LLC connection fro GMM sapi). */ + * LLC connection from GMM sapi). */ if (mmctx) { dup.imsi = mmctx->imsi; dup.drx_parms = mmctx->drx_parms; @@ -252,6 +530,7 @@ static void llme_free(struct gprs_llc_llme *llme) { + talloc_free(llme->xid); llist_del(&llme->list); talloc_free(llme); } @@ -468,54 +747,6 @@ /* Send BSSGP-DL-UNITDATA.req */ return _bssgp_tx_dl_ud(msg, mmctx); -} - -/* According to 6.4.1.6 / Figure 11 */ -static int msgb_put_xid_par(struct msgb *msg, uint8_t type, uint8_t length, uint8_t *data) -{ - uint8_t header_len = 1; - uint8_t *cur; - - /* type is a 5-bit field... */ - if (type > 0x1f) - return -EINVAL; - - if (length > 3) - header_len = 2; - - cur = msgb_put(msg, length + header_len); - - /* build the header without or with XL bit */ - if (length <= 3) { - *cur++ = (type << 2) | (length & 3); - } else { - *cur++ = 0x80 | (type << 2) | (length >> 6); - *cur++ = (length << 2); - } - - /* copy over the payload of the parameter*/ - memcpy(cur, data, length); - - return length + header_len; -} - -static void rx_llc_xid(struct gprs_llc_lle *lle, - struct gprs_llc_hdr_parsed *gph) -{ - /* FIXME: 8.5.3.3: check if XID is invalid */ - if (gph->is_cmd) { - /* FIXME: implement XID negotiation using SNDCP */ - struct msgb *resp; - uint8_t *xid; - resp = msgb_alloc_headroom(4096, 1024, "LLC_XID"); - xid = msgb_put(resp, gph->data_len); - memcpy(xid, gph->data, gph->data_len); - gprs_llc_tx_xid(lle, resp, 0); - } else { - /* FIXME: if we had sent a XID reset, send - * LLGMM-RESET.conf to GMM */ - /* FIXME: implement XID negotiation using SNDCP */ - } } static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph, @@ -791,17 +1022,24 @@ { struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); struct gprs_llc_lle *lle = &llme->lle[1]; + uint8_t xid_bytes[1024]; + int xid_bytes_len; + uint8_t *xid; + LOGP(DLLC, LOGL_NOTICE, "LLGM Reset\n"); if (RAND_bytes((uint8_t *) &llme->iov_ui, 4) != 1) { LOGP(DLLC, LOGL_NOTICE, "RAND_bytes failed for LLC XID reset, " "falling back to rand()\n"); llme->iov_ui = rand(); } - /* First XID component must be RESET */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL); - /* randomly select new IOV-UI */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &llme->iov_ui); + /* Generate XID message */ + xid_bytes_len = gprs_llc_generate_xid_for_gmm_reset(xid_bytes, + sizeof(xid_bytes),llme->iov_ui,llme); + if(xid_bytes_len < 0) + return -EINVAL; + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); /* Reset some of the LLC parameters. See GSM 04.64, 8.5.3.1 */ lle->vu_recv = 0; @@ -817,17 +1055,24 @@ struct gprs_llc_llme *llme) { struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + uint8_t xid_bytes[1024]; + int xid_bytes_len; + uint8_t *xid; + LOGP(DLLC, LOGL_NOTICE, "LLGM Reset\n"); if (RAND_bytes((uint8_t *) &llme->iov_ui, 4) != 1) { LOGP(DLLC, LOGL_NOTICE, "RAND_bytes failed for LLC XID reset, " "falling back to rand()\n"); llme->iov_ui = rand(); } - /* First XID component must be RESET */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL); - /* randomly select new IOV-UI */ - msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &llme->iov_ui); + /* Generate XID message */ + xid_bytes_len = gprs_llc_generate_xid_for_gmm_reset(xid_bytes, + sizeof(xid_bytes),llme->iov_ui,llme); + if(xid_bytes_len < 0) + return -EINVAL; + xid = msgb_put(msg, xid_bytes_len); + memcpy(xid, xid_bytes, xid_bytes_len); /* FIXME: Start T200, wait for XID response */ diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index b6036c7..74af159 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -30,6 +30,7 @@ $(top_builddir)/src/gprs/gprs_gb_parse.o \ $(top_builddir)/src/gprs/oap.o \ $(top_builddir)/src/gprs/oap_messages.o \ + $(top_builddir)/src/gprs/gprs_llc_xid.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ -- To view, visit https://gerrit.osmocom.org/652 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I65b9d625e72d3d61c99abdc7041773701d694d52 Gerrit-PatchSet: 15 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Sat Aug 27 04:45:57 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 04:45:57 +0000 Subject: [MERGED] openbsc[master]: Adding LLC-XID encoder / decoder and unit test In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: Adding LLC-XID encoder / decoder and unit test ...................................................................... Adding LLC-XID encoder / decoder and unit test The lle-xid encoder/decoder is needed to encode and decode llc xid parameter messages. We need this to exchange sndcp-parameters (SNDCP-XID) and also simple parameters such as encryption IOVs Change-Id: Ia06e4cb08bf9b48c2a4682606d1b1a91d19a9d37 --- M openbsc/.gitignore M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_llc_xid.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_llc_xid.c M openbsc/tests/Makefile.am M openbsc/tests/testsuite.at A openbsc/tests/xid/Makefile.am A openbsc/tests/xid/xid_test.c A openbsc/tests/xid/xid_test.ok 11 files changed, 526 insertions(+), 3 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/openbsc/.gitignore b/openbsc/.gitignore index 0a2965d..518a960 100644 --- a/openbsc/.gitignore +++ b/openbsc/.gitignore @@ -81,6 +81,7 @@ tests/oap/oap_test tests/gtphub/gtphub_test tests/mm_auth/mm_auth_test +tests/xid/xid_test tests/atconfig tests/atlocal diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 0980413..fbf2930 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -229,6 +229,7 @@ tests/oap/Makefile tests/gtphub/Makefile tests/mm_auth/Makefile + tests/xid/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index c272b14..11f650d 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,7 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h + gtphub.h gprs_llc_xid.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_llc_xid.h b/openbsc/include/openbsc/gprs_llc_xid.h new file mode 100644 index 0000000..d340d40 --- /dev/null +++ b/openbsc/include/openbsc/gprs_llc_xid.h @@ -0,0 +1,57 @@ +/* GPRS LLC XID field encoding/decoding as per 3GPP TS 44.064 */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include + +/* 3GPP TS 44.064 6.4.1.6 Exchange Identification (XID) + command/response parameter field */ +struct gprs_llc_xid_field { + struct llist_head list; + uint8_t type; /* See also Table 6: LLC layer parameter + negotiation */ + uint8_t *data; /* Payload data (memory is owned by the + * creator of the struct) */ + unsigned int data_len; /* Payload length */ +}; + +/* Transform a list with XID fields into a XID message (dst) */ +int gprs_llc_compile_xid(uint8_t *dst, int dst_maxlen, + const struct llist_head *xid_fields); + +/* Transform a XID message (dst) into a list of XID fields */ +struct llist_head *gprs_llc_parse_xid(const void *ctx, const uint8_t *src, + int src_len); + +/* Create a duplicate of an XID-Field */ +struct gprs_llc_xid_field *gprs_llc_dup_xid_field(const void *ctx, + const struct gprs_llc_xid_field *xid_field); + +/* Copy an llist with xid fields */ +struct llist_head *gprs_llc_copy_xid(const void *ctx, + const struct llist_head *xid_fields); + +/* Dump a list with XID fields (Debug) */ +void gprs_llc_dump_xid_fields(const struct llist_head *xid_fields, + unsigned int logl); + diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 6dc7e16..8cbdd91 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -28,7 +28,7 @@ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ - oap.c oap_messages.c + oap.c oap_messages.c gprs_llc_xid.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/gprs_llc_xid.c b/openbsc/src/gprs/gprs_llc_xid.c new file mode 100644 index 0000000..4b1685e --- /dev/null +++ b/openbsc/src/gprs/gprs_llc_xid.c @@ -0,0 +1,262 @@ +/* GPRS LLC XID field encoding/decoding as per 3GPP TS 44.064 */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Parse XID parameter field */ +static int decode_xid_field(struct gprs_llc_xid_field *xid_field, + const uint8_t *src, uint8_t src_len) +{ + uint8_t xl; + uint8_t type; + uint8_t len; + int src_counter = 0; + + /* Exit immediately if it is clear that no + * parseable data is present */ + if (src_len < 1 || !src) + return -EINVAL; + + /* Extract header info */ + xl = (*src >> 7) & 1; + type = (*src >> 2) & 0x1F; + + /* Extract length field */ + len = (*src) & 0x3; + src++; + src_counter++; + if (xl) { + if (src_len < 2) + return -EINVAL; + len = (len << 6) & 0xC0; + len |= ((*src) >> 2) & 0x3F; + src++; + src_counter++; + } + + /* Fill out struct */ + xid_field->type = type; + xid_field->data_len = len; + if (len > 0) { + if (src_len < src_counter + len) + return -EINVAL; + xid_field->data = + talloc_memdup(xid_field,src,xid_field->data_len); + } else + xid_field->data = NULL; + + /* Return consumed length */ + return src_counter + len; +} + +/* Encode XID parameter field */ +static int encode_xid_field(uint8_t *dst, int dst_maxlen, + const struct gprs_llc_xid_field *xid_field) +{ + int xl = 0; + + /* When the length does not fit into 2 bits, + * we need extended length fields */ + if (xid_field->data_len > 3) + xl = 1; + + /* Exit immediately if it is clear that no + * encoding result can be stored */ + if (dst_maxlen < xid_field->data_len + 1 + xl) + return -EINVAL; + + /* There are only 5 bits reserved for the type, exit on exceed */ + if (xid_field->type > 31) + return -EINVAL; + + /* Encode header */ + memset(dst, 0, dst_maxlen); + if (xl) + dst[0] |= 0x80; + dst[0] |= (((xid_field->type) & 0x1F) << 2); + + if (xl) { + dst[0] |= (((xid_field->data_len) >> 6) & 0x03); + dst[1] = ((xid_field->data_len) << 2) & 0xFC; + } else + dst[0] |= ((xid_field->data_len) & 0x03); + + /* Append payload data */ + if (xid_field->data && xid_field->data_len) + memcpy(dst + 1 + xl, xid_field->data, xid_field->data_len); + + /* Return generated length */ + return xid_field->data_len + 1 + xl; +} + +/* Transform a list with XID fields into a XID message (dst) */ +int gprs_llc_compile_xid(uint8_t *dst, int dst_maxlen, + const struct llist_head *xid_fields) +{ + struct gprs_llc_xid_field *xid_field; + int rc; + int byte_counter = 0; + + OSMO_ASSERT(xid_fields); + OSMO_ASSERT(dst); + + llist_for_each_entry_reverse(xid_field, xid_fields, list) { + /* Encode XID-Field */ + rc = encode_xid_field(dst, dst_maxlen, xid_field); + if (rc < 0) + return -EINVAL; + + /* Advance pointer and lower maxlen for the + * next encoding round */ + dst += rc; + byte_counter += rc; + dst_maxlen -= rc; + } + + /* Return generated length */ + return byte_counter; +} + +/* Transform a XID message (dst) into a list of XID fields */ +struct llist_head *gprs_llc_parse_xid(const void *ctx, const uint8_t *src, + int src_len) +{ + struct gprs_llc_xid_field *xid_field; + struct llist_head *xid_fields; + + int rc; + int max_loops = src_len; + + OSMO_ASSERT(src); + + xid_fields = talloc_zero(ctx, struct llist_head); + INIT_LLIST_HEAD(xid_fields); + + while (1) { + /* Bail in case decode_xid_field() constantly returns zero */ + if (max_loops <= 0) { + talloc_free(xid_fields); + return NULL; + } + + /* Decode XID field */ + xid_field = talloc_zero(xid_fields, struct gprs_llc_xid_field); + rc = decode_xid_field(xid_field, src, src_len); + + /* Immediately stop on error */ + if (rc < 0) { + talloc_free(xid_fields); + return NULL; + } + + /* Add parsed XID field to list */ + llist_add(&xid_field->list, xid_fields); + + /* Advance pointer and lower dst_len for the next + * decoding round */ + src += rc; + src_len -= rc; + + /* We are (scuccessfully) done when no further byes are left */ + if (src_len == 0) + return xid_fields; + + max_loops--; + } +} + +/* Create a duplicate of an XID-Field */ +struct gprs_llc_xid_field *gprs_llc_dup_xid_field(const void *ctx, const struct + gprs_llc_xid_field + *xid_field) +{ + struct gprs_llc_xid_field *dup; + + OSMO_ASSERT(xid_field); + + /* Create a copy of the XID field in memory */ + dup = talloc_memdup(ctx, xid_field, sizeof(*xid_field)); + dup->data = talloc_memdup(ctx, xid_field->data, xid_field->data_len); + + /* Unlink duplicate from source list */ + INIT_LLIST_HEAD(&dup->list); + + return dup; +} + +/* Copy an llist with xid fields */ +struct llist_head *gprs_llc_copy_xid(const void *ctx, + const struct llist_head *xid_fields) +{ + struct gprs_llc_xid_field *xid_field; + struct llist_head *xid_fields_copy; + + OSMO_ASSERT(xid_fields); + + xid_fields_copy = talloc_zero(ctx, struct llist_head); + INIT_LLIST_HEAD(xid_fields_copy); + + /* Create duplicates and add them to the target list */ + llist_for_each_entry(xid_field, xid_fields, list) { + llist_add(&gprs_llc_dup_xid_field(ctx, xid_field)->list, + xid_fields_copy); + } + + return xid_fields_copy; +} + +/* Dump a list with XID fields (Debug) */ +void gprs_llc_dump_xid_fields(const struct llist_head *xid_fields, + unsigned int logl) +{ + struct gprs_llc_xid_field *xid_field; + + OSMO_ASSERT(xid_fields); + + llist_for_each_entry(xid_field, xid_fields, list) { + if (xid_field->data_len) { + OSMO_ASSERT(xid_field->data); + LOGP(DLLC, logl, + "XID: type=%d, data_len=%d, data=%s\n", + xid_field->type, xid_field->data_len, + osmo_hexdump_nospc(xid_field->data, + xid_field->data_len)); + } else { + LOGP(DLLC, logl, + "XID: type=%d, data_len=%d, data=NULL\n", + xid_field->type, xid_field->data_len); + } + } +} diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index 09298a3..ba5ca28 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index dab9568..6470ab9 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -124,3 +124,8 @@ AT_CHECK([$abs_top_builddir/tests/mm_auth/mm_auth_test], [], [expout], [ignore]) AT_CLEANUP +AT_SETUP([xid]) +AT_KEYWORDS([xid]) +cat $abs_srcdir/xid/xid_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/xid/xid_test], [], [expout], [ignore]) +AT_CLEANUP diff --git a/openbsc/tests/xid/Makefile.am b/openbsc/tests/xid/Makefile.am new file mode 100644 index 0000000..9b64965 --- /dev/null +++ b/openbsc/tests/xid/Makefile.am @@ -0,0 +1,21 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) + +EXTRA_DIST = xid_test.ok + +noinst_PROGRAMS = xid_test + +xid_test_SOURCES = xid_test.c + +xid_test_LDADD = \ + $(top_builddir)/src/gprs/gprs_llc_xid.o \ + $(top_builddir)/src/libcommon/libcommon.a \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOGB_LIBS) \ + $(LIBCARES_LIBS) \ + $(LIBCRYPTO_LIBS) \ + -lgtp -lrt -lm + + diff --git a/openbsc/tests/xid/xid_test.c b/openbsc/tests/xid/xid_test.c new file mode 100644 index 0000000..b77a4ae --- /dev/null +++ b/openbsc/tests/xid/xid_test.c @@ -0,0 +1,164 @@ +/* Test LLC-XID Encoding/Decoding */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include +#include + +#include + +#include +#include + +/* Test XID encoding */ +static void test_xid_encode(const void *ctx) +{ + struct gprs_llc_xid_field xid_field_1; + struct gprs_llc_xid_field xid_field_2; + struct gprs_llc_xid_field xid_field_3; + struct gprs_llc_xid_field xid_field_4; + LLIST_HEAD(xid_fields); + uint8_t xid[255]; + uint8_t xid_expected[] = + { 0x10, 0x8c, 0x14, 0x43, 0x43, 0x43, 0x43, 0x43, 0x0b, 0x42, 0x42, + 0x42, 0x05, 0x41 }; + int rc; + + printf("Testing LLC XID-Encoder\n"); + + /* Setup some simple XID data */ + xid_field_1.type = 1; + xid_field_2.type = 2; + xid_field_3.type = 3; + xid_field_4.type = 4; + + xid_field_1.data = (uint8_t *) "A"; + xid_field_2.data = (uint8_t *) "BBB"; + xid_field_3.data = (uint8_t *) "CCCCC"; + xid_field_4.data = NULL; + + xid_field_1.data_len = 1; + xid_field_2.data_len = 3; + xid_field_3.data_len = 5; + xid_field_4.data_len = 0; + + llist_add(&xid_field_4.list, &xid_fields); + llist_add(&xid_field_3.list, &xid_fields); + llist_add(&xid_field_2.list, &xid_fields); + llist_add(&xid_field_1.list, &xid_fields); + + printf("Data to encode:\n"); + gprs_llc_dump_xid_fields(&xid_fields, DSNDCP); + + /* Encode data */ + rc = gprs_llc_compile_xid(xid, sizeof(xid), &xid_fields); + OSMO_ASSERT(rc == 14); + printf("Encoded: %s (%i bytes)\n", osmo_hexdump_nospc(xid, rc), rc); + printf("Expected: %s (%i bytes)\n", + osmo_hexdump_nospc(xid_expected, sizeof(xid_expected)), + (int)sizeof(xid_expected)); + + OSMO_ASSERT(memcmp(xid_expected, xid, sizeof(xid_expected)) == 0); + + printf("\n"); +} + +/* Test XID decoding */ +static void test_xid_decode(const void *ctx) +{ + struct llist_head *xid_fields; + int rc; + + printf("Testing LLC XID-Decoder/Encoder\n"); + + /* Example of a real world LLC-XID message */ + uint8_t xid[] = + { 0x01, 0x00, 0x16, 0x05, 0xf0, 0x1a, 0x05, 0xf0, 0xac, 0xd8, 0x00, + 0x01, 0x00, 0x02, 0x31, 0x82, 0x02, 0x27, 0x89, 0xff, 0xe0, 0x00, 0x0f, + 0x00, 0xa8, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x01, 0x02, + 0x00, 0x03, 0x01, 0x03, 0x00, 0x04, 0x01, 0x04, 0x00, 0x05, 0x01, 0x05, + 0x00, 0x06, 0x00, 0x07, 0x01, 0x07, 0x00, 0x08, 0x01, 0x08, 0x80, 0x00, + 0x04, 0x12, 0x00, 0x40, 0x07 }; + + uint8_t xid_r[512]; + + /* Decode and display XID fields */ + xid_fields = gprs_llc_parse_xid(ctx, xid, sizeof(xid)); + OSMO_ASSERT(xid_fields); + + printf("Decoded:\n"); + gprs_llc_dump_xid_fields(xid_fields, DSNDCP); + + + /* Encode xid-fields again */ + rc = gprs_llc_compile_xid(xid_r, sizeof(xid_r), xid_fields); + printf("Result length=%i\n",rc); + printf("Encoded: %s\n", osmo_hexdump_nospc(xid, sizeof(xid))); + printf("Rencoded: %s\n", osmo_hexdump_nospc(xid_r, rc)); + + OSMO_ASSERT(rc == 64); + OSMO_ASSERT(memcmp(xid, xid_r, sizeof(xid)) == 0); + + /* Free xid fields */ + talloc_free(xid_fields); + + printf("\n"); +} + +static struct log_info_cat gprs_categories[] = { + [DSNDCP] = { + .name = "DSNDCP", + .description = + "GPRS Sub-Network Dependent Control Protocol (SNDCP)", + .enabled = 1,.loglevel = LOGL_DEBUG, + } +}; + +static struct log_info info = { + .cat = gprs_categories, + .num_cat = ARRAY_SIZE(gprs_categories), +}; + +int main(int argc, char **argv) +{ + void *xid_ctx; + + osmo_init_logging(&info); + + xid_ctx = talloc_named_const(NULL, 0, "xid_ctx"); + + test_xid_decode(xid_ctx); + test_xid_encode(xid_ctx); + printf("Done\n"); + + talloc_report_full(xid_ctx, stderr); + OSMO_ASSERT(talloc_total_blocks(xid_ctx) == 1); + return 0; +} + +/* stubs */ +struct osmo_prim_hdr; +int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) +{ + abort(); +} diff --git a/openbsc/tests/xid/xid_test.ok b/openbsc/tests/xid/xid_test.ok new file mode 100644 index 0000000..4cf825c --- /dev/null +++ b/openbsc/tests/xid/xid_test.ok @@ -0,0 +1,12 @@ +Testing LLC XID-Decoder/Encoder +Decoded: +Result length=64 +Encoded: 01001605f01a05f0acd8000100023182022789ffe0000f00a8000000010101000201020003010300040104000501050006000701070008010880000412004007 +Rencoded: 01001605f01a05f0acd8000100023182022789ffe0000f00a8000000010101000201020003010300040104000501050006000701070008010880000412004007 + +Testing LLC XID-Encoder +Data to encode: +Encoded: 108c1443434343430b4242420541 (14 bytes) +Expected: 108c1443434343430b4242420541 (14 bytes) + +Done -- To view, visit https://gerrit.osmocom.org/638 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ia06e4cb08bf9b48c2a4682606d1b1a91d19a9d37 Gerrit-PatchSet: 11 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Sat Aug 27 04:45:58 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 04:45:58 +0000 Subject: [MERGED] openbsc[master]: Moving grs_sndcp.h header file to include In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: Moving grs_sndcp.h header file to include ...................................................................... Moving grs_sndcp.h header file to include For some reason gprs_sndcp.h is located in src/gprs. This commit moves gprs_sndcp.h to include/openbsc and fixes the include path in gprs_sndcp.c and gprs_sndcp_vty.c Change-Id: If4e4f1252c81d7907c1b4d738c982bb172b128c9 --- M openbsc/include/openbsc/Makefile.am R openbsc/include/openbsc/gprs_sndcp.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/gprs_sndcp.c M openbsc/src/gprs/gprs_sndcp_vty.c 5 files changed, 3 insertions(+), 7 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 11f650d..ce5f768 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,7 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_llc_xid.h + gtphub.h gprs_llc_xid.h gprs_sndcp.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/src/gprs/gprs_sndcp.h b/openbsc/include/openbsc/gprs_sndcp.h similarity index 100% rename from openbsc/src/gprs/gprs_sndcp.h rename to openbsc/include/openbsc/gprs_sndcp.h diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 8cbdd91..1b6de46 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -6,8 +6,6 @@ OSMO_LIBS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) \ $(LIBOSMOCTRL_LIBS) $(LIBOSMOGB_LIBS) -noinst_HEADERS = gprs_sndcp.h - bin_PROGRAMS = osmo-gbproxy if HAVE_LIBGTP diff --git a/openbsc/src/gprs/gprs_sndcp.c b/openbsc/src/gprs/gprs_sndcp.c index 75f95c9..4f71121 100644 --- a/openbsc/src/gprs/gprs_sndcp.c +++ b/openbsc/src/gprs/gprs_sndcp.c @@ -34,8 +34,7 @@ #include #include #include - -#include "gprs_sndcp.h" +#include /* Chapter 7.2: SN-PDU Formats */ struct sndcp_common_hdr { diff --git a/openbsc/src/gprs/gprs_sndcp_vty.c b/openbsc/src/gprs/gprs_sndcp_vty.c index deeef07..430881f 100644 --- a/openbsc/src/gprs/gprs_sndcp_vty.c +++ b/openbsc/src/gprs/gprs_sndcp_vty.c @@ -35,8 +35,7 @@ #include #include #include - -#include "gprs_sndcp.h" +#include #include #include -- To view, visit https://gerrit.osmocom.org/636 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: If4e4f1252c81d7907c1b4d738c982bb172b128c9 Gerrit-PatchSet: 9 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max From gerrit-no-reply at lists.osmocom.org Sat Aug 27 04:46:43 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 04:46:43 +0000 Subject: openbsc[master]: V.42bis integration and unit test In-Reply-To: References: Message-ID: Patch Set 31: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/644 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d Gerrit-PatchSet: 31 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 04:46:57 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 04:46:57 +0000 Subject: openbsc[master]: Adding V.42bis implementation In-Reply-To: References: Message-ID: Patch Set 26: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/643 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Iabedece9f97ca944a1e3f747bb073e532c4e9dca Gerrit-PatchSet: 26 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 04:47:47 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 04:47:47 +0000 Subject: openbsc[master]: SLHC (RFC1144 header compression) integration and unit-test In-Reply-To: References: Message-ID: Patch Set 15: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/635 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 Gerrit-PatchSet: 15 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 04:52:32 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 04:52:32 +0000 Subject: osmo-pcu[master]: Handle EGPRS 11 bit RACH in osmo-pcu In-Reply-To: References: Message-ID: Patch Set 4: Code-Review-1 (1 comment) https://gerrit.osmocom.org/#/c/430/4/src/bts.h File src/bts.h: Line 290: uint8_t is_11bit, uint16_t*, uint16_t*); why are there un-named / anonymous arguments to this function? Is there a specific reason for this? Have you seen this pattern used in any other part of the code? If so, please point it out so we can fix that. If not, then please always align with the existing coding style, thanks. -- To view, visit https://gerrit.osmocom.org/430 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I61d74a32f7764644ed86f7fdf97fa3c2f61503f7 Gerrit-PatchSet: 4 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: arvind.sirsikar Gerrit-Reviewer: bhargava_abhyankar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Sat Aug 27 04:53:05 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Sat, 27 Aug 2016 04:53:05 +0000 Subject: openbsc[master]: osmo-nitb: generate backtrace on SIGABRT In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+1 -- To view, visit https://gerrit.osmocom.org/767 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia63aa5c39b26e27c3ee220d755c17d2c1ef636c5 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Harald Welte Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 12:02:37 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sat, 27 Aug 2016 12:02:37 +0000 Subject: [PATCH] openbsc[master]: add libiu In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/192 to look at the new patch set (#8). add libiu Co-Authored by dwillmann, laforge, nhofmeyr Change-Id: Iffc26f9c73cb15463948f7435b72ac1747aabdb3 --- M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/iu.h M openbsc/src/Makefile.am A openbsc/src/libiu/Makefile.am A openbsc/src/libiu/iu.c 6 files changed, 844 insertions(+), 3 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/92/192/8 diff --git a/openbsc/configure.ac b/openbsc/configure.ac index fbf2930..f63d61f 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -203,6 +203,7 @@ src/libmgcp/Makefile src/libcommon/Makefile src/libfilter/Makefile + src/libiu/Makefile src/osmo-nitb/Makefile src/osmo-bsc/Makefile src/osmo-bsc_nat/Makefile diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index ce5f768..90aa364 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,8 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_llc_xid.h gprs_sndcp.h + gtphub.h gprs_llc_xid.h gprs_sndcp.h \ + iu.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/iu.h b/openbsc/include/openbsc/iu.h new file mode 100644 index 0000000..d0ab540 --- /dev/null +++ b/openbsc/include/openbsc/iu.h @@ -0,0 +1,60 @@ +#pragma once + +#include + +struct sgsn_pdp_ctx; +struct msgb; +struct gprs_ra_id; + +struct RANAP_RAB_SetupOrModifiedItemIEs_s; +struct RANAP_GlobalRNC_ID; + +struct ue_conn_ctx { + struct llist_head list; + struct osmo_sccp_link *link; + uint32_t conn_id; + int integrity_active; + struct gprs_ra_id ra_id; +}; + +enum iu_event_type { + IU_EVENT_RAB_ASSIGN, + IU_EVENT_SECURITY_MODE_COMPLETE, + IU_EVENT_IU_RELEASE, /* An actual Iu Release message was received */ + IU_EVENT_LINK_INVALIDATED, /* A SUA link was lost or closed down */ + /* FIXME: maybe IU_EVENT_IU_RELEASE and IU_EVENT_LINK_INVALIDATED + * should be combined to one generic event that simply means the + * ue_conn_ctx should no longer be used, for whatever reason. */ +}; + +extern const struct value_string iu_event_type_names[]; +static inline const char *iu_event_type_str(enum iu_event_type e) +{ + return get_value_string(iu_event_type_names, e); +} + +/* Implementations of iu_recv_cb_t shall find the ue_conn_ctx in msg->dst. */ +typedef int (* iu_recv_cb_t )(struct msgb *msg, struct gprs_ra_id *ra_id, + /* TODO "gprs_" in generic CS+PS domain ^ */ + uint16_t *sai); + +typedef int (* iu_event_cb_t )(struct ue_conn_ctx *ue_ctx, + enum iu_event_type type, void *data); + +typedef int (* iu_rab_ass_resp_cb_t )(struct ue_conn_ctx *ue_ctx, uint8_t rab_id, + struct RANAP_RAB_SetupOrModifiedItemIEs_s *setup_ies); + +int iu_init(void *ctx, const char *listen_addr, uint16_t listen_port, + iu_recv_cb_t iu_recv_cb, iu_event_cb_t iu_event_cb); + +void iu_link_del(struct osmo_sccp_link *link); + +int iu_tx(struct msgb *msg, uint8_t sapi); + +int iu_page_cs(const char *imsi, const uint32_t *tmsi, uint16_t lac); +int iu_page_ps(const char *imsi, const uint32_t *ptmsi, uint16_t lac, uint8_t rac); + +int iu_rab_act(struct ue_conn_ctx *ue_ctx, struct msgb *msg); +int iu_rab_deact(struct ue_conn_ctx *ue_ctx, uint8_t rab_id); +int iu_tx_sec_mode_cmd(struct ue_conn_ctx *uectx, struct gsm_auth_tuple *tp, + int send_ck, int new_key); diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 6f6174e..4aa880f 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -2,9 +2,18 @@ AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(COVERAGE_CFLAGS) AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(COVERAGE_LDFLAGS) -SUBDIRS = libcommon libmgcp libbsc libmsc libtrau libfilter osmo-nitb osmo-bsc_mgcp utils ipaccess gprs +# Libraries +SUBDIRS = libcommon libmgcp libbsc libmsc libtrau libfilter -# Conditional modules +# Conditional Libraries +if BUILD_IU +SUBDIRS += libiu +endif + +# Programs +SUBDIRS += osmo-nitb osmo-bsc_mgcp utils ipaccess gprs + +# Conditional Programs if BUILD_NAT SUBDIRS += osmo-bsc_nat endif diff --git a/openbsc/src/libiu/Makefile.am b/openbsc/src/libiu/Makefile.am new file mode 100644 index 0000000..7b1ba4d --- /dev/null +++ b/openbsc/src/libiu/Makefile.am @@ -0,0 +1,10 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) +AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) \ + $(LIBOSMOGSM_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) $(LIBCRYPTO_CFLAGS) \ + $(LIBASN1C_CFLAGS) \ + $(LIBOSMOSIGTRAN_CFLAGS) $(LIBOSMORANAP_CFLAGS) + +noinst_LIBRARIES = libiu.a + +libiu_a_SOURCES = iu.c + diff --git a/openbsc/src/libiu/iu.c b/openbsc/src/libiu/iu.c new file mode 100644 index 0000000..837385e --- /dev/null +++ b/openbsc/src/libiu/iu.c @@ -0,0 +1,760 @@ +/* Common parts of IuCS and IuPS interfaces implementation */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +/* Parsed global RNC id. See also struct RANAP_GlobalRNC_ID, and note that the + * PLMN identity is a BCD representation of the MCC and MNC. + * See iu_grnc_id_parse(). */ +struct iu_grnc_id { + uint16_t mcc; + uint16_t mnc; + uint16_t rnc_id; +}; + +/* A remote RNC (Radio Network Controller, like BSC but for UMTS) that has + * called us and is currently reachable at the given osmo_sccp_link. So, when we + * know a LAC for a subscriber, we can page it at the RNC matching that LAC or + * RAC. An HNB-GW typically presents itself as if it were a single RNC, even + * though it may have several RNCs in hNodeBs connected to it. Those will then + * share the same RNC id, which they actually receive and adopt from the HNB-GW + * in the HNBAP HNB REGISTER ACCEPT message. */ +struct iu_rnc { + struct llist_head entry; + + uint16_t rnc_id; + uint16_t lac; /* Location Area Code (used for CS and PS) */ + uint8_t rac; /* Routing Area Code (used for PS only) */ + struct osmo_sccp_link *link; +}; + +void *talloc_iu_ctx; + +int asn1_xer_print = 1; +void *talloc_asn1_ctx; + +iu_recv_cb_t global_iu_recv_cb = NULL; +iu_event_cb_t global_iu_event_cb = NULL; + +static LLIST_HEAD(ue_conn_ctx_list); +static LLIST_HEAD(rnc_list); + +const struct value_string iu_event_type_names[] = { +#define IU_EVT_STR(X) { X, #X } + IU_EVT_STR(IU_EVENT_RAB_ASSIGN), + IU_EVT_STR(IU_EVENT_SECURITY_MODE_COMPLETE), + IU_EVT_STR(IU_EVENT_IU_RELEASE), + IU_EVT_STR(IU_EVENT_LINK_INVALIDATED), +#undef IU_EVT_STR +}; + +struct ue_conn_ctx *ue_conn_ctx_alloc(struct osmo_sccp_link *link, uint32_t conn_id) +{ + struct ue_conn_ctx *ctx = talloc_zero(talloc_iu_ctx, struct ue_conn_ctx); + + ctx->link = link; + ctx->conn_id = conn_id; + llist_add(&ctx->list, &ue_conn_ctx_list); + + return ctx; +} + +struct ue_conn_ctx *ue_conn_ctx_find(struct osmo_sccp_link *link, + uint32_t conn_id) +{ + struct ue_conn_ctx *ctx; + + llist_for_each_entry(ctx, &ue_conn_ctx_list, list) { + if (ctx->link == link && ctx->conn_id == conn_id) + return ctx; + } + return NULL; +} + +static struct iu_rnc *iu_rnc_alloc(uint16_t rnc_id, uint16_t lac, uint8_t rac, + struct osmo_sccp_link *link) +{ + struct iu_rnc *rnc = talloc_zero(talloc_iu_ctx, struct iu_rnc); + + rnc->rnc_id = rnc_id; + rnc->lac = lac; + rnc->rac = rac; + rnc->link = link; + llist_add(&rnc->entry, &rnc_list); + + LOGP(DRANAP, LOGL_NOTICE, "New RNC %d (LAC=%d RAC=%d)\n", + rnc->rnc_id, rnc->lac, rnc->rac); + + return rnc; +} + +static struct iu_rnc *iu_rnc_register(uint16_t rnc_id, uint16_t lac, + uint8_t rac, struct osmo_sccp_link *link) +{ + struct iu_rnc *rnc; + llist_for_each_entry(rnc, &rnc_list, entry) { + if (rnc->rnc_id != rnc_id) + continue; + + /* We have this RNC Id registered already. Make sure that the + * details match. */ + + /* TODO should a mismatch be an error? */ + if (rnc->lac != lac || rnc->rac != rac) + LOGP(DRANAP, LOGL_NOTICE, "RNC %d changes its details:" + " LAC=%d RAC=%d --> LAC=%d RAC=%d\n", + rnc->rnc_id, rnc->lac, rnc->rac, + lac, rac); + rnc->lac = lac; + rnc->rac = rac; + + if (link && rnc->link != link) + LOGP(DRANAP, LOGL_NOTICE, "RNC %d on new link" + " (LAC=%d RAC=%d)\n", + rnc->rnc_id, rnc->lac, rnc->rac); + rnc->link = link; + return rnc; + } + + /* Not found, make a new one. */ + return iu_rnc_alloc(rnc_id, lac, rac, link); +} + +/* Discard/invalidate all ue_conn_ctx and iu_rnc entries that reference the + * given link, since this link is invalid and about to be deallocated. For + * each ue_conn_ctx, invoke the iu_event_cb_t with IU_EVENT_LINK_INVALIDATED. + */ +void iu_link_del(struct osmo_sccp_link *link) +{ + struct iu_rnc *rnc, *rnc_next; + llist_for_each_entry_safe(rnc, rnc_next, &rnc_list, entry) { + if (!rnc->link) + continue; + if (rnc->link != link) + continue; + rnc->link = NULL; + llist_del(&rnc->entry); + talloc_free(rnc); + } + + struct ue_conn_ctx *uec, *uec_next; + llist_for_each_entry_safe(uec, uec_next, &ue_conn_ctx_list, list) { + if (uec->link != link) + continue; + uec->link = NULL; + global_iu_event_cb(uec, IU_EVENT_LINK_INVALIDATED, NULL); + } +} + +/*********************************************************************** + * RANAP handling + ***********************************************************************/ + +int iu_rab_act(struct ue_conn_ctx *ue_ctx, struct msgb *msg) +{ + struct osmo_scu_prim *prim; + + /* wrap RANAP message in SCCP N-DATA.req */ + prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim)); + prim->u.data.conn_id = ue_ctx->conn_id; + osmo_prim_init(&prim->oph, + SCCP_SAP_USER, + OSMO_SCU_PRIM_N_DATA, + PRIM_OP_REQUEST, + msg); + return osmo_sua_user_link_down(ue_ctx->link, &prim->oph); +} + +int iu_rab_deact(struct ue_conn_ctx *ue_ctx, uint8_t rab_id) +{ + /* FIXME */ + return -1; +} + +int iu_tx_sec_mode_cmd(struct ue_conn_ctx *uectx, struct gsm_auth_tuple *tp, + int send_ck, int new_key) +{ + struct osmo_scu_prim *prim; + struct msgb *msg; + uint8_t ik[16]; + uint8_t ck[16]; + unsigned int i; + + /* C5 function to derive IK from Kc */ + for (i = 0; i < 4; i++) + ik[i] = tp->vec.kc[i] ^ tp->vec.kc[i+4]; + memcpy(ik+4, tp->vec.kc, 8); + for (i = 12; i < 16; i++) + ik[i] = ik[i-12]; + + if (send_ck) { + /* C4 function to derive CK from Kc */ + memcpy(ck, tp->vec.kc, 8); + memcpy(ck+8, tp->vec.kc, 8); + } + + /* create RANAP message */ + msg = ranap_new_msg_sec_mod_cmd(ik, send_ck? ck : NULL, new_key ? RANAP_KeyStatus_new : RANAP_KeyStatus_old); + msg->l2h = msg->data; + /* wrap RANAP message in SCCP N-DATA.req */ + prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim)); + prim->u.data.conn_id = uectx->conn_id; + osmo_prim_init(&prim->oph, SCCP_SAP_USER, + OSMO_SCU_PRIM_N_DATA, + PRIM_OP_REQUEST, msg); + osmo_sua_user_link_down(uectx->link, &prim->oph); + + return 0; +} + +static int iu_grnc_id_parse(struct iu_grnc_id *dst, + struct RANAP_GlobalRNC_ID *src) +{ + /* The size is coming from arbitrary sender, check it gracefully */ + if (src->pLMNidentity.size != 3) { + LOGP(DRANAP, LOGL_ERROR, "Invalid PLMN Identity size:" + " should be 3, is %d\n", src->pLMNidentity.size); + return -1; + } + gsm48_mcc_mnc_from_bcd(&src->pLMNidentity.buf[0], + &dst->mcc, &dst->mnc); + dst->rnc_id = (uint16_t)src->rNC_ID; + return 0; +} + +#if 0 + -- not used at present -- +static int iu_grnc_id_compose(struct iu_grnc_id *src, + struct RANAP_GlobalRNC_ID *dst) +{ + /* The caller must ensure proper size */ + OSMO_ASSERT(dst->pLMNidentity.size == 3); + gsm48_mcc_mnc_to_bcd(&dst->pLMNidentity.buf[0], + src->mcc, src->mnc); + dst->rNC_ID = src->rnc_id; + return 0; +} +#endif + +static int ranap_handle_co_initial_ue(void *ctx, RANAP_InitialUE_MessageIEs_t *ies) +{ + struct ue_conn_ctx *ue_conn = ctx; + struct gprs_ra_id ra_id; + struct iu_grnc_id grnc_id; + uint16_t sai; + struct msgb *msg = msgb_alloc(256, "RANAP->NAS"); + + if (ranap_parse_lai(&ra_id, &ies->lai) != 0) { + LOGP(DRANAP, LOGL_ERROR, "Failed to parse RANAP LAI IE\n"); + return -1; + } + + if (ies->presenceMask & INITIALUE_MESSAGEIES_RANAP_RAC_PRESENT) { + ra_id.rac = asn1str_to_u8(&ies->rac); + } + + if (iu_grnc_id_parse(&grnc_id, &ies->globalRNC_ID) != 0) { + LOGP(DRANAP, LOGL_ERROR, + "Failed to parse RANAP Global-RNC-ID IE\n"); + return -1; + } + + sai = asn1str_to_u16(&ies->sai.sAC); + msgb_gmmh(msg) = msgb_put(msg, ies->nas_pdu.size); + memcpy(msgb_gmmh(msg), ies->nas_pdu.buf, ies->nas_pdu.size); + + /* Make sure we know the RNC Id and LAC+RAC coming in on this connection. */ + iu_rnc_register(grnc_id.rnc_id, ra_id.lac, ra_id.rac, ue_conn->link); + ue_conn->ra_id = ra_id; + + /* Feed into the MM layer */ + msg->dst = ctx; + global_iu_recv_cb(msg, &ra_id, &sai); + + msgb_free(msg); + + return 0; +} + +static int ranap_handle_co_dt(void *ctx, RANAP_DirectTransferIEs_t *ies) +{ + struct gprs_ra_id _ra_id, *ra_id = NULL; + uint16_t _sai, *sai = NULL; + struct msgb *msg = msgb_alloc(256, "RANAP->NAS"); + + if (ies->presenceMask & DIRECTTRANSFERIES_RANAP_LAI_PRESENT) { + if (ranap_parse_lai(&_ra_id, &ies->lai) != 0) { + LOGP(DRANAP, LOGL_ERROR, "Failed to parse RANAP LAI IE\n"); + return -1; + } + ra_id = &_ra_id; + if (ies->presenceMask & DIRECTTRANSFERIES_RANAP_RAC_PRESENT) { + _ra_id.rac = asn1str_to_u8(&ies->rac); + } + if (ies->presenceMask & DIRECTTRANSFERIES_RANAP_SAI_PRESENT) { + _sai = asn1str_to_u16(&ies->sai.sAC); + sai = &_sai; + } + } + + msgb_gmmh(msg) = msgb_put(msg, ies->nas_pdu.size); + memcpy(msgb_gmmh(msg), ies->nas_pdu.buf, ies->nas_pdu.size); + + /* Feed into the MM/CC/SMS-CP layer */ + msg->dst = ctx; + global_iu_recv_cb(msg, ra_id, sai); + + msgb_free(msg); + + return 0; +} + +static int ranap_handle_co_err_ind(void *ctx, RANAP_ErrorIndicationIEs_t *ies) +{ + if (ies->presenceMask & ERRORINDICATIONIES_RANAP_CAUSE_PRESENT) + LOGP(DRANAP, LOGL_ERROR, "Rx Error Indication (%s)\n", + ranap_cause_str(&ies->cause)); + else + LOGP(DRANAP, LOGL_ERROR, "Rx Error Indication\n"); + + return 0; +} + +int iu_tx(struct msgb *msg_nas, uint8_t sapi) +{ + struct ue_conn_ctx *uectx = msg_nas->dst; + struct msgb *msg; + struct osmo_scu_prim *prim; + + LOGP(DRANAP, LOGL_INFO, "Transmitting L3 Message as RANAP DT (SUA link %p conn_id %u)\n", + uectx->link, uectx->conn_id); + + msg = ranap_new_msg_dt(sapi, msg_nas->data, msgb_length(msg_nas)); + msgb_free(msg_nas); + msg->l2h = msg->data; + prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim)); + prim->u.data.conn_id = uectx->conn_id; + osmo_prim_init(&prim->oph, SCCP_SAP_USER, + OSMO_SCU_PRIM_N_DATA, + PRIM_OP_REQUEST, msg); + osmo_sua_user_link_down(uectx->link, &prim->oph); + return 0; +} + +static int ranap_handle_co_iu_rel_req(struct ue_conn_ctx *ctx, RANAP_Iu_ReleaseRequestIEs_t *ies) +{ + struct msgb *msg; + struct osmo_scu_prim *prim; + + LOGP(DRANAP, LOGL_INFO, "Received Iu Release Request, Sending Release Command\n"); + msg = ranap_new_msg_iu_rel_cmd(&ies->cause); + msg->l2h = msg->data; + prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim)); + prim->u.data.conn_id = ctx->conn_id; + osmo_prim_init(&prim->oph, SCCP_SAP_USER, + OSMO_SCU_PRIM_N_DATA, + PRIM_OP_REQUEST, msg); + osmo_sua_user_link_down(ctx->link, &prim->oph); + return 0; +} + +static int ranap_handle_co_rab_ass_resp(struct ue_conn_ctx *ctx, RANAP_RAB_AssignmentResponseIEs_t *ies) +{ + int rc = -1; + + LOGP(DRANAP, LOGL_INFO, "RAB Asignment Response:"); + if (ies->presenceMask & RAB_ASSIGNMENTRESPONSEIES_RANAP_RAB_SETUPORMODIFIEDLIST_PRESENT) { + /* TODO: Iterate over list of SetupOrModifiedList IEs and handle each one */ + RANAP_IE_t *ranap_ie = ies->raB_SetupOrModifiedList.raB_SetupOrModifiedList_ies.list.array[0]; + RANAP_RAB_SetupOrModifiedItemIEs_t setup_ies; + + rc = ranap_decode_rab_setupormodifieditemies_fromlist(&setup_ies, &ranap_ie->value); + if (rc) { + LOGP(DRANAP, LOGL_ERROR, "Error in ranap_decode_rab_setupormodifieditemies()\n"); + return rc; + } + + rc = global_iu_event_cb(ctx, IU_EVENT_RAB_ASSIGN, &setup_ies); + + ranap_free_rab_setupormodifieditemies(&setup_ies); + } + + LOGPC(DRANAP, LOGL_INFO, "\n"); + + return rc; +} + +/* Entry point for connection-oriented RANAP message */ +static void cn_ranap_handle_co(void *ctx, ranap_message *message) +{ + int rc; + + LOGP(DRANAP, LOGL_NOTICE, "handle_co(dir=%u, proc=%u)\n", message->direction, message->procedureCode); + + switch (message->direction) { + case RANAP_RANAP_PDU_PR_initiatingMessage: + switch (message->procedureCode) { + case RANAP_ProcedureCode_id_InitialUE_Message: + rc = ranap_handle_co_initial_ue(ctx, &message->msg.initialUE_MessageIEs); + break; + case RANAP_ProcedureCode_id_DirectTransfer: + rc = ranap_handle_co_dt(ctx, &message->msg.directTransferIEs); + break; + case RANAP_ProcedureCode_id_ErrorIndication: + rc = ranap_handle_co_err_ind(ctx, &message->msg.errorIndicationIEs); + break; + case RANAP_ProcedureCode_id_Iu_ReleaseRequest: + /* Iu Release Request */ + rc = ranap_handle_co_iu_rel_req(ctx, &message->msg.iu_ReleaseRequestIEs); + break; + default: + LOGP(DRANAP, LOGL_ERROR, "Received Initiating Message: unknown Procedure Code %d\n", + message->procedureCode); + rc = -1; + break; + } + break; + case RANAP_RANAP_PDU_PR_successfulOutcome: + switch (message->procedureCode) { + case RANAP_ProcedureCode_id_SecurityModeControl: + /* Security Mode Complete */ + rc = global_iu_event_cb(ctx, IU_EVENT_SECURITY_MODE_COMPLETE, NULL); + break; + case RANAP_ProcedureCode_id_Iu_Release: + /* Iu Release Complete */ + rc = global_iu_event_cb(ctx, IU_EVENT_IU_RELEASE, NULL); + if (rc) { + LOGP(DRANAP, LOGL_ERROR, "Iu Release event: Iu Event callback returned %d\n", + rc); + } + break; + default: + LOGP(DRANAP, LOGL_ERROR, "Received Successful Outcome: unknown Procedure Code %d\n", + message->procedureCode); + rc = -1; + break; + } + break; + case RANAP_RANAP_PDU_PR_outcome: + switch (message->procedureCode) { + case RANAP_ProcedureCode_id_RAB_Assignment: + /* RAB Assignment Response */ + rc = ranap_handle_co_rab_ass_resp(ctx, &message->msg.raB_AssignmentResponseIEs); + break; + default: + LOGP(DRANAP, LOGL_ERROR, "Received Outcome: unknown Procedure Code %d\n", + message->procedureCode); + rc = -1; + break; + } + break; + case RANAP_RANAP_PDU_PR_unsuccessfulOutcome: + default: + LOGP(DRANAP, LOGL_ERROR, "Received Unsuccessful Outcome: Procedure Code %d\n", + message->procedureCode); + rc = -1; + break; + } + + if (rc) { + LOGP(DRANAP, LOGL_ERROR, "Error in cn_ranap_handle_co (%d)\n", + rc); + /* TODO handling of the error? */ + } +} + +static int ranap_handle_cl_reset_req(void *ctx, RANAP_ResetIEs_t *ies) +{ + /* FIXME: send reset response */ + return -1; +} + +static int ranap_handle_cl_err_ind(void *ctx, RANAP_ErrorIndicationIEs_t *ies) +{ + if (ies->presenceMask & ERRORINDICATIONIES_RANAP_CAUSE_PRESENT) + LOGP(DRANAP, LOGL_ERROR, "Rx Error Indication (%s)\n", + ranap_cause_str(&ies->cause)); + else + LOGP(DRANAP, LOGL_ERROR, "Rx Error Indication\n"); + + return 0; +} + +/* Entry point for connection-less RANAP message */ +static void cn_ranap_handle_cl(void *ctx, ranap_message *message) +{ + int rc; + + switch (message->direction) { + case RANAP_RANAP_PDU_PR_initiatingMessage: + switch (message->procedureCode) { + case RANAP_ProcedureCode_id_Reset: + /* received reset.req, send reset.resp */ + rc = ranap_handle_cl_reset_req(ctx, &message->msg.resetIEs); + break; + case RANAP_ProcedureCode_id_ErrorIndication: + rc = ranap_handle_cl_err_ind(ctx, &message->msg.errorIndicationIEs); + break; + default: + rc = -1; + break; + } + break; + case RANAP_RANAP_PDU_PR_successfulOutcome: + case RANAP_RANAP_PDU_PR_unsuccessfulOutcome: + case RANAP_RANAP_PDU_PR_outcome: + default: + rc = -1; + break; + } + + if (rc) { + LOGP(DRANAP, LOGL_ERROR, "Error in cn_ranap_handle_cl (%d)\n", + rc); + /* TODO handling of the error? */ + } +} + +/*********************************************************************** + * Paging + ***********************************************************************/ + +/* Send a paging command down a given SUA link. tmsi and paging_cause are + * optional and may be passed NULL and 0, respectively, to disable their use. + * See enum RANAP_PagingCause. + * + * If TMSI is given, the IMSI is not sent over the air interface. Nevertheless, + * the IMSI is still required for resolution in the HNB-GW and/or(?) RNC. */ +static int iu_tx_paging_cmd(struct osmo_sccp_link *link, + const char *imsi, const uint32_t *tmsi, + bool is_ps, uint32_t paging_cause) +{ + struct msgb *msg; + msg = ranap_new_msg_paging_cmd(imsi, tmsi, is_ps? 1 : 0, paging_cause); + msg->l2h = msg->data; + return osmo_sccp_tx_unitdata_ranap(link, 1, 2, msg->data, + msgb_length(msg)); +} + +static int iu_page(const char *imsi, const uint32_t *tmsi_or_ptimsi, + uint16_t lac, uint8_t rac, bool is_ps) +{ + struct iu_rnc *rnc; + int pagings_sent = 0; + + if (tmsi_or_ptimsi) { + LOGP(DRANAP, LOGL_DEBUG, "%s: Looking for RNCs to page for IMSI %s" + " (paging will use %s %x)\n", + is_ps? "IuPS" : "IuCS", + imsi, + is_ps? "PTMSI" : "TMSI", + *tmsi_or_ptimsi); + } else { + LOGP(DRANAP, LOGL_DEBUG, "%s: Looking for RNCs to page for IMSI %s" + " (paging will use IMSI)\n", + is_ps? "IuPS" : "IuCS", + imsi + ); + } + + llist_for_each_entry(rnc, &rnc_list, entry) { + if (!rnc->link) { + /* Not actually connected, don't count it. */ + continue; + } + if (rnc->lac != lac) + continue; + if (is_ps && rnc->rac != rac) + continue; + + /* Found a match! */ + if (iu_tx_paging_cmd(rnc->link, imsi, tmsi_or_ptimsi, is_ps, 0) + == 0) { + LOGP(DRANAP, LOGL_DEBUG, + "%s: Paged for IMSI %s on RNC %d, on SUA link %p\n", + is_ps? "IuPS" : "IuCS", + imsi, rnc->rnc_id, rnc->link); + pagings_sent ++; + } + } + + /* Some logging... */ + if (pagings_sent > 0) { + LOGP(DRANAP, LOGL_DEBUG, + "%s: %d RNCs were paged for IMSI %s.\n", + is_ps? "IuPS" : "IuCS", + pagings_sent, imsi); + } + else { + if (is_ps) { + LOGP(DRANAP, LOGL_ERROR, "IuPS: Found no RNC to page for" + " LAC %d RAC %d (would have paged IMSI %s)\n", + lac, rac, imsi); + } + else { + LOGP(DRANAP, LOGL_ERROR, "IuCS: Found no RNC to page for" + " LAC %d (would have paged IMSI %s)\n", + lac, imsi); + } + } + + return pagings_sent; +} + +int iu_page_cs(const char *imsi, const uint32_t *tmsi, uint16_t lac) +{ + return iu_page(imsi, tmsi, lac, 0, false); +} + +int iu_page_ps(const char *imsi, const uint32_t *ptmsi, uint16_t lac, uint8_t rac) +{ + return iu_page(imsi, ptmsi, lac, rac, true); +} + + +/*********************************************************************** + * + ***********************************************************************/ + +int tx_unitdata(struct osmo_sccp_link *link); +int tx_conn_req(struct osmo_sccp_link *link, uint32_t conn_id); + +struct osmo_prim_hdr *make_conn_req(uint32_t conn_id); +struct osmo_prim_hdr *make_dt1_req(uint32_t conn_id, const uint8_t *data, unsigned int len); + +struct osmo_prim_hdr *make_conn_resp(struct osmo_scu_connect_param *param) +{ + struct msgb *msg = msgb_alloc(1024, "conn_resp"); + struct osmo_scu_prim *prim; + + prim = (struct osmo_scu_prim *) msgb_put(msg, sizeof(*prim)); + osmo_prim_init(&prim->oph, SCCP_SAP_USER, + OSMO_SCU_PRIM_N_CONNECT, + PRIM_OP_RESPONSE, msg); + memcpy(&prim->u.connect, param, sizeof(prim->u.connect)); + return &prim->oph; +} + +static int sccp_sap_up(struct osmo_prim_hdr *oph, void *link) +{ + struct osmo_scu_prim *prim = (struct osmo_scu_prim *) oph; + struct osmo_prim_hdr *resp = NULL; + int rc; + struct ue_conn_ctx *ue; + + DEBUGP(DRANAP, "sccp_sap_up(%s)\n", osmo_scu_prim_name(oph)); + + switch (OSMO_PRIM_HDR(oph)) { + case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_CONFIRM): + /* confirmation of outbound connection */ + rc = -1; + break; + case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_INDICATION): + /* indication of new inbound connection request*/ + DEBUGP(DRANAP, "N-CONNECT.ind(X->%u)\n", prim->u.connect.conn_id); + if (/* prim->u.connect.called_addr.ssn != OSMO_SCCP_SSN_RANAP || */ + !msgb_l2(oph->msg) || msgb_l2len(oph->msg) == 0) { + LOGP(DRANAP, LOGL_NOTICE, + "Received invalid N-CONNECT.ind\n"); + return 0; + } + ue = ue_conn_ctx_alloc(link, prim->u.connect.conn_id); + /* first ensure the local SUA/SCCP socket is ACTIVE */ + resp = make_conn_resp(&prim->u.connect); + osmo_sua_user_link_down(link, resp); + /* then handle the RANAP payload */ + rc = ranap_cn_rx_co(cn_ranap_handle_co, ue, msgb_l2(oph->msg), msgb_l2len(oph->msg)); + break; + case OSMO_PRIM(OSMO_SCU_PRIM_N_DISCONNECT, PRIM_OP_INDICATION): + /* indication of disconnect */ + DEBUGP(DRANAP, "N-DISCONNECT.ind(%u)\n", + prim->u.disconnect.conn_id); + ue = ue_conn_ctx_find(link, prim->u.disconnect.conn_id); + rc = ranap_cn_rx_co(cn_ranap_handle_co, ue, msgb_l2(oph->msg), msgb_l2len(oph->msg)); + break; + case OSMO_PRIM(OSMO_SCU_PRIM_N_DATA, PRIM_OP_INDICATION): + /* connection-oriented data received */ + DEBUGP(DRANAP, "N-DATA.ind(%u, %s)\n", prim->u.data.conn_id, + osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg))); + /* resolve UE context */ + ue = ue_conn_ctx_find(link, prim->u.data.conn_id); + rc = ranap_cn_rx_co(cn_ranap_handle_co, ue, msgb_l2(oph->msg), msgb_l2len(oph->msg)); + break; + case OSMO_PRIM(OSMO_SCU_PRIM_N_UNITDATA, PRIM_OP_INDICATION): + /* connection-less data received */ + DEBUGP(DRANAP, "N-UNITDATA.ind(%s)\n", + osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg))); + rc = ranap_cn_rx_cl(cn_ranap_handle_cl, link, msgb_l2(oph->msg), msgb_l2len(oph->msg)); + break; + default: + rc = -1; + break; + } + + msgb_free(oph->msg); + return rc; +} + +int iu_init(void *ctx, const char *listen_addr, uint16_t listen_port, + iu_recv_cb_t iu_recv_cb, iu_event_cb_t iu_event_cb) +{ + struct osmo_sccp_user *user; + talloc_iu_ctx = talloc_named_const(ctx, 1, "iu"); + talloc_asn1_ctx = talloc_named_const(talloc_iu_ctx, 1, "asn1"); + + global_iu_recv_cb = iu_recv_cb; + global_iu_event_cb = iu_event_cb; + osmo_sua_set_log_area(DSUA); + user = osmo_sua_user_create(talloc_iu_ctx, sccp_sap_up, talloc_iu_ctx); + return osmo_sua_server_listen(user, listen_addr, listen_port); +} + -- To view, visit https://gerrit.osmocom.org/192 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Iffc26f9c73cb15463948f7435b72ac1747aabdb3 Gerrit-PatchSet: 8 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Sat Aug 27 12:02:37 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sat, 27 Aug 2016 12:02:37 +0000 Subject: [PATCH] openbsc[master]: IuPS: GMM Service Request: add local gsm_04_08_gprs.h and .c In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/736 to look at the new patch set (#2). IuPS: GMM Service Request: add local gsm_04_08_gprs.h and .c These items will probably move to libosmocore's gsm_04_08_gprs.h and .c, add them here in openbsc until things have settled. Change-Id: Iaf9316f07d21280b6e090d65892c338f9555313a --- M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gsm_04_08_gprs.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/gprs_gmm.c A openbsc/src/gprs/gsm_04_08_gprs.c M openbsc/tests/sgsn/Makefile.am 6 files changed, 63 insertions(+), 3 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/36/736/2 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 90aa364..e9fbebb 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -8,7 +8,7 @@ vty.h socket.h e1_config.h trau_upqueue.h token_auth.h \ handover_decision.h rrlp.h \ crc24.h gprs_llc.h gprs_gmm.h \ - gb_proxy.h gprs_sgsn.h sgsn.h \ + gb_proxy.h gprs_sgsn.h gsm_04_08_gprs.h sgsn.h \ auth.h osmo_msc.h bsc_msc.h bsc_nat.h \ osmo_bsc_rf.h osmo_bsc.h network_listen.h bsc_nat_sccp.h \ osmo_msc_data.h osmo_bsc_grace.h sms_queue.h abis_om2000.h \ diff --git a/openbsc/include/openbsc/gsm_04_08_gprs.h b/openbsc/include/openbsc/gsm_04_08_gprs.h new file mode 100644 index 0000000..42b9a79 --- /dev/null +++ b/openbsc/include/openbsc/gsm_04_08_gprs.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +/* TODO: Move this to osmocom/gsm/protocol/gsm_04_08_gprs.h ? */ + +/* Table 10.4 in 3GPP TS 24.008 (successor to 04.08) */ +#define GSM48_MT_GMM_SERVICE_REQ 0x0c +#define GSM48_MT_GMM_SERVICE_ACK 0x0d +#define GSM48_MT_GMM_SERVICE_REJ 0x0e + +/* 3GPP 24.008 / Chapter 10.5.5.20 / Table 10.5.153a */ +enum gsm48_gmm_service_type { + GPRS_SERVICE_T_SIGNALLING = 0x00, + GPRS_SERVICE_T_DATA = 0x01, + GPRS_SERVICE_T_PAGING_RESP = 0x02, + GPRS_SERVICE_T_MBMS_MC_SERV = 0x03, + GPRS_SERVICE_T_MBMS_BC_SERV = 0x04, +}; + +extern const struct value_string *gprs_service_t_strs; diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 6a95315..28b42e1 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -30,7 +30,8 @@ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ - oap.c oap_messages.c gprs_llc_xid.c + oap.c oap_messages.c gprs_llc_xid.c \ + gsm_04_08_gprs.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a if BUILD_IU diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index 4f228ea..e34f823 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -44,7 +44,6 @@ #include #include #include -#include #include @@ -56,6 +55,7 @@ #include #include #include +#include #include #include #include diff --git a/openbsc/src/gprs/gsm_04_08_gprs.c b/openbsc/src/gprs/gsm_04_08_gprs.c new file mode 100644 index 0000000..90657eb --- /dev/null +++ b/openbsc/src/gprs/gsm_04_08_gprs.c @@ -0,0 +1,37 @@ +/* (C) 2009-2010 by Harald Welte + * (C) 2010 by On-Waves + * (C) 2014-2015 by Sysmocom s.f.m.c. GmbH + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +/* TODO: Move this to osmocom/gsm/protocol/gsm_04_08_gprs.h ? */ + +#include + +#include + +const struct value_string gprs_service_t_strs_[] = { + { GPRS_SERVICE_T_SIGNALLING, "signalling" }, + { GPRS_SERVICE_T_DATA, "data" }, + { GPRS_SERVICE_T_PAGING_RESP, "paging response" }, + { GPRS_SERVICE_T_MBMS_MC_SERV, "MBMS multicast service" }, + { GPRS_SERVICE_T_MBMS_BC_SERV, "MBMS broadcast service" }, + { 0, NULL } +}; + +const struct value_string *gprs_service_t_strs = gprs_service_t_strs_; diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index ce64429..4d27bc7 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -30,6 +30,7 @@ $(top_builddir)/src/gprs/gprs_gsup_client.o \ $(top_builddir)/src/gprs/gprs_utils.o \ $(top_builddir)/src/gprs/gprs_subscriber.o \ + $(top_builddir)/src/gprs/gsm_04_08_gprs.o \ $(top_builddir)/src/gprs/gprs_gb_parse.o \ $(top_builddir)/src/gprs/oap.o \ $(top_builddir)/src/gprs/oap_messages.o \ -- To view, visit https://gerrit.osmocom.org/736 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Iaf9316f07d21280b6e090d65892c338f9555313a Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Sat Aug 27 12:28:45 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sat, 27 Aug 2016 12:28:45 +0000 Subject: openbsc[master]: add libiu In-Reply-To: References: Message-ID: Patch Set 8: Code-Review+2 re-adding +2 from before the rebase -- To view, visit https://gerrit.osmocom.org/192 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Iffc26f9c73cb15463948f7435b72ac1747aabdb3 Gerrit-PatchSet: 8 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sat Aug 27 12:31:33 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Sat, 27 Aug 2016 12:31:33 +0000 Subject: [MERGED] osmo-bts[master]: log: l1sap: add 0x to hex output of chan_nr, 5 times In-Reply-To: References: Message-ID: Neels Hofmeyr has submitted this change and it was merged. Change subject: log: l1sap: add 0x to hex output of chan_nr, 5 times ...................................................................... log: l1sap: add 0x to hex output of chan_nr, 5 times Change-Id: I187a74fd255dbdfb9bfb1e32786031a66f013efb --- M src/common/l1sap.c 1 file changed, 5 insertions(+), 5 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 2ab4055..f7df218 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -403,7 +403,7 @@ struct bts_ul_meas ulm; struct gsm_lchan *lchan; - DEBUGP(DL1P, "MPH_INFO meas ind chan_nr=%02x\n", + DEBUGP(DL1P, "MPH_INFO meas ind chan_nr=0x%02x\n", info_meas_ind->chan_nr); lchan = get_active_lchan_by_chan_nr(trx, info_meas_ind->chan_nr); @@ -489,7 +489,7 @@ { struct gsm_lchan *lchan; - LOGP(DL1P, LOGL_INFO, "deactivate confirm chan_nr=%02x trx=%d\n", + LOGP(DL1P, LOGL_INFO, "deactivate confirm chan_nr=0x%02x trx=%d\n", info_act_cnf->chan_nr, trx->nr); lchan = get_lchan_by_chan_nr(trx, info_act_cnf->chan_nr); @@ -1148,7 +1148,7 @@ int l1sap_chan_rel(struct gsm_bts_trx *trx, uint8_t chan_nr) { - LOGP(DL1P, LOGL_INFO, "deactivating channel chan_nr=%02x trx=%d\n", + LOGP(DL1P, LOGL_INFO, "deactivating channel chan_nr=0x%02x trx=%d\n", chan_nr, trx->nr); return l1sap_chan_act_dact_modify(trx, chan_nr, PRIM_INFO_DEACTIVATE, @@ -1159,7 +1159,7 @@ { struct gsm_lchan *lchan = get_lchan_by_chan_nr(trx, chan_nr); - LOGP(DL1P, LOGL_INFO, "deactivating sacch chan_nr=%02x trx=%d\n", + LOGP(DL1P, LOGL_INFO, "deactivating sacch chan_nr=0x%02x trx=%d\n", chan_nr, trx->nr); lchan->sacch_deact = 1; @@ -1170,7 +1170,7 @@ int l1sap_chan_modify(struct gsm_bts_trx *trx, uint8_t chan_nr) { - LOGP(DL1P, LOGL_INFO, "modifying channel chan_nr=%02x trx=%d\n", + LOGP(DL1P, LOGL_INFO, "modifying channel chan_nr=0x%02x trx=%d\n", chan_nr, trx->nr); return l1sap_chan_act_dact_modify(trx, chan_nr, PRIM_INFO_MODIFY, 0); -- To view, visit https://gerrit.osmocom.org/745 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I187a74fd255dbdfb9bfb1e32786031a66f013efb Gerrit-PatchSet: 2 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Sun Aug 28 10:39:57 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Sun, 28 Aug 2016 10:39:57 +0000 Subject: [PATCH] osmo-pcu[master]: GPRS: PUAN encoding: add test case to show wrong BSNs status Message-ID: Review at https://gerrit.osmocom.org/770 GPRS: PUAN encoding: add test case to show wrong BSNs status This patch adds a test case test_gprs_puan which expects a current bug with GPRS PUAN encoding. The test's expectation is corrected along with the bug fix in a subsequent commit Related: OS#1806 Change-Id: Ied0f1dd3037d8fac6a772f4e097defb72634f955 --- M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 3 files changed, 1,858 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/70/770/1 diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 2feb9c3..8cdac9a 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -646,7 +646,7 @@ * simulate RACH, this sends an Immediate * Assignment Uplink on the AGCH */ - the_bts->rcv_rach(0x73, rach_fn, qta); + the_bts->rcv_rach(0x73, rach_fn, qta, 0, GSM_L1_BURST_TYPE_ACCESS_0); /* get next free TFI */ tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1); @@ -1298,6 +1298,100 @@ return ul_tbf; } +static gprs_rlcmac_ul_tbf *gprs_ul_tbf_validation(BTS *the_bts, + uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta, + uint8_t ms_class) +{ + GprsMs *ms; + uint32_t rach_fn = *fn - 51; + uint32_t sba_fn = *fn + 52; + uint8_t trx_no = 0; + int tfi = 0; + int i = 0; + gprs_rlcmac_ul_tbf *ul_tbf; + struct gprs_rlcmac_pdch *pdch; + gprs_rlcmac_bts *bts; + RlcMacUplink_t ulreq = {0}; + struct pcu_l1_meas meas; + + meas.set_rssi(31); + + bts = the_bts->bts_data(); + + /* needed to set last_rts_fn in the PDCH object */ + request_dl_rlc_block(bts, trx_no, ts_no, fn); + + /* simulate RACH, sends an Immediate Assignment Uplink on the AGCH */ + the_bts->rcv_rach(0x73, rach_fn, qta, 0, GSM_L1_BURST_TYPE_ACCESS_0); + + /* get next free TFI */ + tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1); + + /* fake a resource request */ + ulreq.u.MESSAGE_TYPE = MT_PACKET_RESOURCE_REQUEST; + ulreq.u.Packet_Resource_Request.PayloadType = GPRS_RLCMAC_CONTROL_BLOCK; + ulreq.u.Packet_Resource_Request.ID.UnionType = 1; /* != 0 */ + ulreq.u.Packet_Resource_Request.ID.u.TLLI = tlli; + ulreq.u.Packet_Resource_Request.Exist_MS_Radio_Access_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + Count_MS_RA_capability_value = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content. + Exist_Multislot_capability = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + Exist_GPRS_multislot_class = 1; + ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability. + MS_RA_capability_value[0].u.Content.Multislot_capability. + GPRS_multislot_class = ms_class; + + send_ul_mac_block(the_bts, trx_no, ts_no, &ulreq, sba_fn); + + /* check the TBF */ + ul_tbf = the_bts->ul_tbf_by_tfi(tfi, trx_no, ts_no); + OSMO_ASSERT(ul_tbf != NULL); + OSMO_ASSERT(ul_tbf->ta() == qta / 4); + + /* send packet uplink assignment */ + *fn = sba_fn; + request_dl_rlc_block(ul_tbf, fn); + + /* send real acknowledgement */ + send_control_ack(ul_tbf); + + check_tbf(ul_tbf); + + pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no]; + + /* send fake data */ + uint8_t data_msg[23] = { + 0x00 | 0xf << 2, /* GPRS_RLCMAC_DATA_BLOCK << 6, CV = 15 */ + uint8_t(0 | (tfi << 1)), + }; + + /* send the data starting from BSN 0 to 127 */ + for (i = 0; i < 128; i++) { + data_msg[2] = (i << 1) | 1; + pdch->rcv_block(&data_msg[0], sizeof(data_msg), *fn, &meas); + } + + /* send BSN 0 again */ + data_msg[2] = 1; + pdch->rcv_block(&data_msg[0], sizeof(data_msg), *fn, &meas); + + /* trigger GPRS ack/nack */ + struct msgb *msg1 = ul_tbf->create_ul_ack(*fn, ts_no); + + /* TODO: Should not expect any BSN as nacked. + * should be fixed in subsequent patch + */ + OSMO_ASSERT(!strcmp(osmo_hexdump(msg1->data, msg1->data_len), + "40 24 00 00 40 00 00 00 00 00 00 00 7e 24 46 68 81 4b 2b 2b 2b 2b 2b " + )); + + return ul_tbf; +} + static void send_dl_data(BTS *the_bts, uint32_t tlli, const char *imsi, const uint8_t *data, unsigned data_size) { @@ -1461,6 +1555,27 @@ OSMO_ASSERT(ms == NULL); ms = the_bts.ms_by_tlli(tlli2); OSMO_ASSERT(ms == ms2); + + printf("=== end %s ===\n", __func__); +} + +static void test_gprs_puan(void) +{ + BTS the_bts; + int ts_no = 7; + uint32_t fn = 2654218; + uint16_t qta = 31; + uint32_t tlli1 = 0xf1223344; + const char *imsi = "0011223344"; + uint8_t ms_class = 1; + gprs_rlcmac_ul_tbf *ul_tbf; + + printf("=== start %s ===\n", __func__); + + setup_bts(&the_bts, ts_no, 1); + + ul_tbf = gprs_ul_tbf_validation(&the_bts, ts_no, tlli1, &fn, qta, + ms_class); printf("=== end %s ===\n", __func__); } @@ -2485,7 +2600,7 @@ test_tbf_egprs_retx_dl(); test_tbf_egprs_spb_dl(); test_tbf_puan_urbb_len(); - + test_gprs_puan(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); return EXIT_SUCCESS; diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 452f1c1..6979652 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -6335,3 +6335,1742 @@ TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) changes state from NULL to ASSIGN TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) starting timer 0. TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) append +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654218 block=8 data=47 94 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +MS requests UL TBF on RACH, so we provide one: +MS requests single block allocation +RX: [PCU <- BTS] RACH qbit-ta=31 ra=0x73, Fn=2654167 (17,25,9), SBFn=2654270 +TX: Immediate Assignment Uplink (AGCH) + - TRX=0 (0) TS=7 TA=7 TSC=0 TFI=-1 USF=7 +Sending data request: trx=0 ts=0 sapi=2 arfcn=0 fn=0 block=0 data=2d 06 3f 10 0f 00 00 73 8b 29 07 00 c0 0c 5a 43 2b 2b 2b 2b 2b 2b 2b +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +MS requests UL TBF in packet resource request of single block, so we provide one: +********** TBF starts here ********** +Allocating UL TBF: MS_CLASS=1/0 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 1 +Slot Allocation (Algorithm A) for class 1 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 2, because not enabled +- Skipping TS 3, because not enabled +- Skipping TS 4, because not enabled +- Skipping TS 5, because not enabled +- Skipping TS 6, because not enabled +- Assign uplink TS=7 TFI=0 USF=0 +PDCH(TS 7, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL), 1 TBFs, USFs = 01, TFIs = 00000001. +- Setting Control TS 7 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL): trx = 0, ul_slots = 80, dl_slots = 00 +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL) changes state from NULL to ASSIGN +TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=ASSIGN) starting timer 3169. +Modifying MS object, UL TLLI: 0x00000000 -> 0xf1223344, not yet confirmed +Modifying MS object, TLLI = 0xf1223344, TA 0 -> 7 +Change control TS to 7 until assinment is complete. +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN)s start Packet Uplink Assignment (PACCH) ++++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++ +------------------------- TX : Packet Uplink Assignment ------------------------- +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN): Scheduling polling at FN 2654283 TS 7 +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=ASSIGN) changes state from ASSIGN to WAIT ASSIGN +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) Scheduled UL Assignment polling on FN=2654283, TS=7 +Scheduling control message at RTS for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) (TRX=0, TS=7) +Sending data request: trx=0 ts=7 sapi=5 arfcn=0 fn=2654270 block=8 data=4f 28 5e 24 46 68 83 1d 00 00 88 00 08 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +Got RLC block, coding scheme: CS-1, length: 23 (23)) ++++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++ +------------------------- RX : Uplink Control Block ------------------------- +RX: [PCU <- BTS] TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) Packet Control Ack +TBF: [DOWNLINK] UPLINK ASSIGNED TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=WAIT ASSIGN) changes state from WAIT ASSIGN to FLOW +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=0 .. V(R)=0) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=0, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 0 storing in window (0..63) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 1 +- Taking block 0 out, raising V(Q) to 1 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=0 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=1 .. V(R)=1) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=1, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 1 storing in window (1..64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 2 +- Taking block 1 out, raising V(Q) to 2 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=1 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=2 .. V(R)=2) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=2, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 2 storing in window (2..65) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 3 +- Taking block 2 out, raising V(Q) to 3 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=2 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=3 .. V(R)=3) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=3, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 3 storing in window (3..66) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 4 +- Taking block 3 out, raising V(Q) to 4 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=3 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 09 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=4 .. V(R)=4) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=4, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 4 storing in window (4..67) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 5 +- Taking block 4 out, raising V(Q) to 5 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=4 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 0b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=5 .. V(R)=5) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=5, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 5 storing in window (5..68) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 6 +- Taking block 5 out, raising V(Q) to 6 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=5 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=6 .. V(R)=6) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=6, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 6 storing in window (6..69) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 7 +- Taking block 6 out, raising V(Q) to 7 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=6 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=7 .. V(R)=7) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=7, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 7 storing in window (7..70) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 8 +- Taking block 7 out, raising V(Q) to 8 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=7 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 11 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=8 .. V(R)=8) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=8, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 8 storing in window (8..71) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 9 +- Taking block 8 out, raising V(Q) to 9 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=8 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 13 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=9 .. V(R)=9) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=9, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 9 storing in window (9..72) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 10 +- Taking block 9 out, raising V(Q) to 10 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=9 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 15 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=10 .. V(R)=10) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=10, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 10 storing in window (10..73) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 11 +- Taking block 10 out, raising V(Q) to 11 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=10 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 17 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=11 .. V(R)=11) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=11, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 11 storing in window (11..74) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 12 +- Taking block 11 out, raising V(Q) to 12 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=11 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 19 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=12 .. V(R)=12) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=12, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 12 storing in window (12..75) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 13 +- Taking block 12 out, raising V(Q) to 13 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=12 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 1b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=13 .. V(R)=13) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=13, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 13 storing in window (13..76) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 14 +- Taking block 13 out, raising V(Q) to 14 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=13 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 1d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=14 .. V(R)=14) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=14, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 14 storing in window (14..77) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 15 +- Taking block 14 out, raising V(Q) to 15 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=14 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 1f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=15 .. V(R)=15) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=15, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 15 storing in window (15..78) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 16 +- Taking block 15 out, raising V(Q) to 16 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=15 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 21 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=16 .. V(R)=16) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=16, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 16 storing in window (16..79) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 17 +- Taking block 16 out, raising V(Q) to 17 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=16 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 23 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=17 .. V(R)=17) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=17, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 17 storing in window (17..80) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 18 +- Taking block 17 out, raising V(Q) to 18 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=17 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 25 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=18 .. V(R)=18) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=18, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 18 storing in window (18..81) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 19 +- Taking block 18 out, raising V(Q) to 19 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=18 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 27 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=19 .. V(R)=19) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=19, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 19 storing in window (19..82) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 20 +- Taking block 19 out, raising V(Q) to 20 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=19 CV=15 +- Scheduling Ack/Nack, because 20 frames received. +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 29 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=20 .. V(R)=20) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=20, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 20 storing in window (20..83) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 21 +- Taking block 20 out, raising V(Q) to 21 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=20 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 2b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=21 .. V(R)=21) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=21, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 21 storing in window (21..84) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 22 +- Taking block 21 out, raising V(Q) to 22 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=21 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 2d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=22 .. V(R)=22) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=22, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 22 storing in window (22..85) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 23 +- Taking block 22 out, raising V(Q) to 23 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=22 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 2f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=23 .. V(R)=23) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=23, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 23 storing in window (23..86) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 24 +- Taking block 23 out, raising V(Q) to 24 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=23 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=24 .. V(R)=24) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=24, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 24 storing in window (24..87) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 25 +- Taking block 24 out, raising V(Q) to 25 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=24 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 33 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=25 .. V(R)=25) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=25, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 25 storing in window (25..88) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 26 +- Taking block 25 out, raising V(Q) to 26 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=25 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=26 .. V(R)=26) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=26, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 26 storing in window (26..89) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 27 +- Taking block 26 out, raising V(Q) to 27 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=26 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 37 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=27 .. V(R)=27) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=27, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 27 storing in window (27..90) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 28 +- Taking block 27 out, raising V(Q) to 28 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=27 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 39 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=28 .. V(R)=28) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=28, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 28 storing in window (28..91) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 29 +- Taking block 28 out, raising V(Q) to 29 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=28 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 3b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=29 .. V(R)=29) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=29, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 29 storing in window (29..92) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 30 +- Taking block 29 out, raising V(Q) to 30 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=29 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 3d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=30 .. V(R)=30) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=30, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 30 storing in window (30..93) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 31 +- Taking block 30 out, raising V(Q) to 31 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=30 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 3f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=31 .. V(R)=31) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=31, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 31 storing in window (31..94) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 32 +- Taking block 31 out, raising V(Q) to 32 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=31 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 41 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=32 .. V(R)=32) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=32, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 32 storing in window (32..95) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 33 +- Taking block 32 out, raising V(Q) to 33 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=32 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 43 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=33 .. V(R)=33) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=33, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 33 storing in window (33..96) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 34 +- Taking block 33 out, raising V(Q) to 34 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=33 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 45 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=34 .. V(R)=34) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=34, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 34 storing in window (34..97) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 35 +- Taking block 34 out, raising V(Q) to 35 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=34 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 47 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=35 .. V(R)=35) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=35, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 35 storing in window (35..98) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 36 +- Taking block 35 out, raising V(Q) to 36 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=35 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 49 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=36 .. V(R)=36) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=36, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 36 storing in window (36..99) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 37 +- Taking block 36 out, raising V(Q) to 37 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=36 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 4b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=37 .. V(R)=37) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=37, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 37 storing in window (37..100) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 38 +- Taking block 37 out, raising V(Q) to 38 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=37 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 4d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=38 .. V(R)=38) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=38, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 38 storing in window (38..101) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 39 +- Taking block 38 out, raising V(Q) to 39 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=38 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 4f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=39 .. V(R)=39) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=39, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 39 storing in window (39..102) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 40 +- Taking block 39 out, raising V(Q) to 40 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=39 CV=15 +- Scheduling Ack/Nack, because 20 frames received. +- Sending Ack/Nack is already triggered, don't schedule! +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 51 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=40 .. V(R)=40) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=40, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 40 storing in window (40..103) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 41 +- Taking block 40 out, raising V(Q) to 41 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=40 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 53 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=41 .. V(R)=41) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=41, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 41 storing in window (41..104) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 42 +- Taking block 41 out, raising V(Q) to 42 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=41 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 55 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=42 .. V(R)=42) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=42, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 42 storing in window (42..105) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 43 +- Taking block 42 out, raising V(Q) to 43 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=42 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 57 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=43 .. V(R)=43) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=43, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 43 storing in window (43..106) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 44 +- Taking block 43 out, raising V(Q) to 44 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=43 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 59 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=44 .. V(R)=44) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=44, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 44 storing in window (44..107) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 45 +- Taking block 44 out, raising V(Q) to 45 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=44 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 5b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=45 .. V(R)=45) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=45, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 45 storing in window (45..108) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 46 +- Taking block 45 out, raising V(Q) to 46 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=45 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 5d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=46 .. V(R)=46) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=46, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 46 storing in window (46..109) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 47 +- Taking block 46 out, raising V(Q) to 47 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=46 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 5f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=47 .. V(R)=47) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=47, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 47 storing in window (47..110) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 48 +- Taking block 47 out, raising V(Q) to 48 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=47 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 61 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=48 .. V(R)=48) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=48, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 48 storing in window (48..111) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 49 +- Taking block 48 out, raising V(Q) to 49 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=48 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 63 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=49 .. V(R)=49) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=49, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 49 storing in window (49..112) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 50 +- Taking block 49 out, raising V(Q) to 50 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=49 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 65 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=50 .. V(R)=50) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=50, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 50 storing in window (50..113) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 51 +- Taking block 50 out, raising V(Q) to 51 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=50 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 67 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=51 .. V(R)=51) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=51, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 51 storing in window (51..114) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 52 +- Taking block 51 out, raising V(Q) to 52 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=51 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 69 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=52 .. V(R)=52) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=52, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 52 storing in window (52..115) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 53 +- Taking block 52 out, raising V(Q) to 53 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=52 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 6b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=53 .. V(R)=53) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=53, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 53 storing in window (53..116) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 54 +- Taking block 53 out, raising V(Q) to 54 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=53 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 6d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=54 .. V(R)=54) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=54, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 54 storing in window (54..117) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 55 +- Taking block 54 out, raising V(Q) to 55 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=54 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 6f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=55 .. V(R)=55) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=55, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 55 storing in window (55..118) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 56 +- Taking block 55 out, raising V(Q) to 56 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=55 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 71 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=56 .. V(R)=56) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=56, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 56 storing in window (56..119) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 57 +- Taking block 56 out, raising V(Q) to 57 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=56 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 73 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=57 .. V(R)=57) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=57, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 57 storing in window (57..120) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 58 +- Taking block 57 out, raising V(Q) to 58 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=57 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 75 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=58 .. V(R)=58) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=58, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 58 storing in window (58..121) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 59 +- Taking block 58 out, raising V(Q) to 59 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=58 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 77 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=59 .. V(R)=59) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=59, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 59 storing in window (59..122) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 60 +- Taking block 59 out, raising V(Q) to 60 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=59 CV=15 +- Scheduling Ack/Nack, because 20 frames received. +- Sending Ack/Nack is already triggered, don't schedule! +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 79 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=60 .. V(R)=60) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=60, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 60 storing in window (60..123) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 61 +- Taking block 60 out, raising V(Q) to 61 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=60 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 7b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=61 .. V(R)=61) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=61, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 61 storing in window (61..124) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 62 +- Taking block 61 out, raising V(Q) to 62 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=61 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 7d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=62 .. V(R)=62) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=62, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 62 storing in window (62..125) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 63 +- Taking block 62 out, raising V(Q) to 63 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=62 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 7f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=63 .. V(R)=63) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=63, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 63 storing in window (63..126) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 64 +- Taking block 63 out, raising V(Q) to 64 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=63 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 81 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=64 .. V(R)=64) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=64, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 64 storing in window (64..127) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 65 +- Taking block 64 out, raising V(Q) to 65 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=64 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 83 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=65 .. V(R)=65) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=65, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 65 storing in window (65..0) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 66 +- Taking block 65 out, raising V(Q) to 66 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=65 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 85 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=66 .. V(R)=66) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=66, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 66 storing in window (66..1) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 67 +- Taking block 66 out, raising V(Q) to 67 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=66 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 87 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=67 .. V(R)=67) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=67, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 67 storing in window (67..2) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 68 +- Taking block 67 out, raising V(Q) to 68 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=67 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 89 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=68 .. V(R)=68) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=68, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 68 storing in window (68..3) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 69 +- Taking block 68 out, raising V(Q) to 69 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=68 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 8b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=69 .. V(R)=69) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=69, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 69 storing in window (69..4) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 70 +- Taking block 69 out, raising V(Q) to 70 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=69 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 8d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=70 .. V(R)=70) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=70, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 70 storing in window (70..5) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 71 +- Taking block 70 out, raising V(Q) to 71 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=70 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=71 .. V(R)=71) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=71, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 71 storing in window (71..6) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 72 +- Taking block 71 out, raising V(Q) to 72 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=71 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 91 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=72 .. V(R)=72) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=72, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 72 storing in window (72..7) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 73 +- Taking block 72 out, raising V(Q) to 73 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=72 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 93 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=73 .. V(R)=73) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=73, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 73 storing in window (73..8) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 74 +- Taking block 73 out, raising V(Q) to 74 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=73 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 95 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=74 .. V(R)=74) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=74, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 74 storing in window (74..9) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 75 +- Taking block 74 out, raising V(Q) to 75 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=74 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 97 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=75 .. V(R)=75) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=75, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 75 storing in window (75..10) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 76 +- Taking block 75 out, raising V(Q) to 76 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=75 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 99 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=76 .. V(R)=76) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=76, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 76 storing in window (76..11) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 77 +- Taking block 76 out, raising V(Q) to 77 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=76 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 9b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=77 .. V(R)=77) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=77, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 77 storing in window (77..12) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 78 +- Taking block 77 out, raising V(Q) to 78 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=77 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 9d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=78 .. V(R)=78) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=78, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 78 storing in window (78..13) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 79 +- Taking block 78 out, raising V(Q) to 79 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=78 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 9f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=79 .. V(R)=79) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=79, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 79 storing in window (79..14) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 80 +- Taking block 79 out, raising V(Q) to 80 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=79 CV=15 +- Scheduling Ack/Nack, because 20 frames received. +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 a1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=80 .. V(R)=80) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=80, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 80 storing in window (80..15) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 81 +- Taking block 80 out, raising V(Q) to 81 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=80 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 a3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=81 .. V(R)=81) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=81, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 81 storing in window (81..16) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 82 +- Taking block 81 out, raising V(Q) to 82 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=81 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 a5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=82 .. V(R)=82) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=82, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 82 storing in window (82..17) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 83 +- Taking block 82 out, raising V(Q) to 83 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=82 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 a7 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=83 .. V(R)=83) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=83, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 83 storing in window (83..18) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 84 +- Taking block 83 out, raising V(Q) to 84 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=83 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 a9 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=84 .. V(R)=84) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=84, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 84 storing in window (84..19) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 85 +- Taking block 84 out, raising V(Q) to 85 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=84 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 ab 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=85 .. V(R)=85) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=85, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 85 storing in window (85..20) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 86 +- Taking block 85 out, raising V(Q) to 86 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=85 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 ad 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=86 .. V(R)=86) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=86, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 86 storing in window (86..21) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 87 +- Taking block 86 out, raising V(Q) to 87 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=86 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 af 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=87 .. V(R)=87) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=87, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 87 storing in window (87..22) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 88 +- Taking block 87 out, raising V(Q) to 88 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=87 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 b1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=88 .. V(R)=88) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=88, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 88 storing in window (88..23) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 89 +- Taking block 88 out, raising V(Q) to 89 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=88 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 b3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=89 .. V(R)=89) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=89, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 89 storing in window (89..24) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 90 +- Taking block 89 out, raising V(Q) to 90 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=89 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 b5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=90 .. V(R)=90) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=90, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 90 storing in window (90..25) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 91 +- Taking block 90 out, raising V(Q) to 91 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=90 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 b7 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=91 .. V(R)=91) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=91, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 91 storing in window (91..26) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 92 +- Taking block 91 out, raising V(Q) to 92 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=91 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 b9 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=92 .. V(R)=92) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=92, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 92 storing in window (92..27) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 93 +- Taking block 92 out, raising V(Q) to 93 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=92 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 bb 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=93 .. V(R)=93) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=93, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 93 storing in window (93..28) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 94 +- Taking block 93 out, raising V(Q) to 94 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=93 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 bd 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=94 .. V(R)=94) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=94, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 94 storing in window (94..29) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 95 +- Taking block 94 out, raising V(Q) to 95 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=94 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 bf 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=95 .. V(R)=95) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=95, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 95 storing in window (95..30) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 96 +- Taking block 95 out, raising V(Q) to 96 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=95 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 c1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=96 .. V(R)=96) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=96, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 96 storing in window (96..31) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 97 +- Taking block 96 out, raising V(Q) to 97 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=96 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 c3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=97 .. V(R)=97) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=97, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 97 storing in window (97..32) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 98 +- Taking block 97 out, raising V(Q) to 98 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=97 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 c5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=98 .. V(R)=98) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=98, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 98 storing in window (98..33) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 99 +- Taking block 98 out, raising V(Q) to 99 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=98 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 c7 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=99 .. V(R)=99) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=99, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 99 storing in window (99..34) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 100 +- Taking block 99 out, raising V(Q) to 100 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=99 CV=15 +- Scheduling Ack/Nack, because 20 frames received. +- Sending Ack/Nack is already triggered, don't schedule! +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 c9 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=100 .. V(R)=100) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=100, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 100 storing in window (100..35) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 101 +- Taking block 100 out, raising V(Q) to 101 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=100 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 cb 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=101 .. V(R)=101) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=101, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 101 storing in window (101..36) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 102 +- Taking block 101 out, raising V(Q) to 102 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=101 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 cd 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=102 .. V(R)=102) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=102, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 102 storing in window (102..37) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 103 +- Taking block 102 out, raising V(Q) to 103 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=102 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 cf 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=103 .. V(R)=103) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=103, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 103 storing in window (103..38) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 104 +- Taking block 103 out, raising V(Q) to 104 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=103 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 d1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=104 .. V(R)=104) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=104, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 104 storing in window (104..39) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 105 +- Taking block 104 out, raising V(Q) to 105 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=104 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 d3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=105 .. V(R)=105) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=105, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 105 storing in window (105..40) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 106 +- Taking block 105 out, raising V(Q) to 106 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=105 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 d5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=106 .. V(R)=106) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=106, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 106 storing in window (106..41) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 107 +- Taking block 106 out, raising V(Q) to 107 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=106 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 d7 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=107 .. V(R)=107) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=107, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 107 storing in window (107..42) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 108 +- Taking block 107 out, raising V(Q) to 108 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=107 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 d9 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=108 .. V(R)=108) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=108, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 108 storing in window (108..43) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 109 +- Taking block 108 out, raising V(Q) to 109 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=108 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 db 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=109 .. V(R)=109) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=109, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 109 storing in window (109..44) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 110 +- Taking block 109 out, raising V(Q) to 110 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=109 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 dd 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=110 .. V(R)=110) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=110, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 110 storing in window (110..45) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 111 +- Taking block 110 out, raising V(Q) to 111 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=110 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=111 .. V(R)=111) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=111, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 111 storing in window (111..46) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 112 +- Taking block 111 out, raising V(Q) to 112 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=111 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 e1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=112 .. V(R)=112) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=112, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 112 storing in window (112..47) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 113 +- Taking block 112 out, raising V(Q) to 113 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=112 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 e3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=113 .. V(R)=113) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=113, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 113 storing in window (113..48) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 114 +- Taking block 113 out, raising V(Q) to 114 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=113 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 e5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=114 .. V(R)=114) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=114, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 114 storing in window (114..49) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 115 +- Taking block 114 out, raising V(Q) to 115 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=114 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 e7 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=115 .. V(R)=115) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=115, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 115 storing in window (115..50) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 116 +- Taking block 115 out, raising V(Q) to 116 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=115 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 e9 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=116 .. V(R)=116) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=116, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 116 storing in window (116..51) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 117 +- Taking block 116 out, raising V(Q) to 117 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=116 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 eb 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=117 .. V(R)=117) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=117, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 117 storing in window (117..52) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 118 +- Taking block 117 out, raising V(Q) to 118 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=117 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 ed 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=118 .. V(R)=118) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=118, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 118 storing in window (118..53) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 119 +- Taking block 118 out, raising V(Q) to 119 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=118 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 ef 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=119 .. V(R)=119) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=119, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 119 storing in window (119..54) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 120 +- Taking block 119 out, raising V(Q) to 120 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=119 CV=15 +- Scheduling Ack/Nack, because 20 frames received. +- Sending Ack/Nack is already triggered, don't schedule! +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 f1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=120 .. V(R)=120) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=120, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 120 storing in window (120..55) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 121 +- Taking block 120 out, raising V(Q) to 121 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=120 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 f3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=121 .. V(R)=121) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=121, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 121 storing in window (121..56) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 122 +- Taking block 121 out, raising V(Q) to 122 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=121 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 f5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=122 .. V(R)=122) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=122, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 122 storing in window (122..57) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 123 +- Taking block 122 out, raising V(Q) to 123 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=122 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 f7 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=123 .. V(R)=123) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=123, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 123 storing in window (123..58) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 124 +- Taking block 123 out, raising V(Q) to 124 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=123 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 f9 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=124 .. V(R)=124) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=124, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 124 storing in window (124..59) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 125 +- Taking block 124 out, raising V(Q) to 125 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=124 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 fb 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=125 .. V(R)=125) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=125, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 125 storing in window (125..60) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 126 +- Taking block 125 out, raising V(Q) to 126 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=125 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 fd 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=126 .. V(R)=126) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=126, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 126 storing in window (126..61) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 127 +- Taking block 126 out, raising V(Q) to 127 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=126 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=127 .. V(R)=127) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=127, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 127 storing in window (127..62) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 0 +- Taking block 127 out, raising V(Q) to 0 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=127 CV=15 +Got RLC block, coding scheme: CS-1, length: 23 (23)) + UL data: 3c 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Got CS-1 RLC block: R=0, SI=0, TFI=0, CPS=0, RSB=0, rc=184 +UL DATA TFI=0 received (V(Q)=0 .. V(R)=0) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) restarting timer 3169 while old timer 3169 pending +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): Got CS-1 RLC data block: CV=15, BSN=0, SPB=0, PI=0, E=1, TI=0, bitoffs=24 +- BSN 0 storing in window (0..63) +TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW): data_length=20, data=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +- Raising V(R) to 1 +- Taking block 0 out, raising V(Q) to 1 +- Assembling frames: (len=20) +-- Frame 1 starts at offset 0, length=20, is_complete=0 +- No gaps in received block, last block: BSN=0 CV=15 +Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) (final=0) +- V(N): "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIR" R=Received I=Invalid +Uplink Ack/Nack bit count 139, max 184, message = 40 24 00 00 40 00 00 00 00 00 00 00 7e 24 46 68 81 4b 2b 2b 2b 2b 2b diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index dda72ef..d2639f9 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -62,3 +62,5 @@ === end test_tbf_egprs_spb_dl === === start test_tbf_puan_urbb_len === === end test_tbf_puan_urbb_len === +=== start test_gprs_puan === +=== end test_gprs_puan === -- To view, visit https://gerrit.osmocom.org/770 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ied0f1dd3037d8fac6a772f4e097defb72634f955 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Sun Aug 28 10:39:57 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Sun, 28 Aug 2016 10:39:57 +0000 Subject: [PATCH] osmo-pcu[master]: Fix GPRS PUAN encoding: wrong BSN status Message-ID: Review at https://gerrit.osmocom.org/771 Fix GPRS PUAN encoding: wrong BSN status Earlier there was an incorrect encoding of BSN status in GPRS PUAN message. This was a bottle neck for GPRS performance testing for UL. Which has been fixed in this patch. Related: OS#1806 Change-Id: I98e586aa5cb9200cf03e092556304211d4d459aa --- M src/rlc.cpp M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err 3 files changed, 4 insertions(+), 7 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/71/771/1 diff --git a/src/rlc.cpp b/src/rlc.cpp index e69d1fc..ee2635a 100644 --- a/src/rlc.cpp +++ b/src/rlc.cpp @@ -227,7 +227,7 @@ { int i; for (i=0; i < ws(); i++) { - if (m_v_n.is_received(ssn()-1-i)) + if (m_v_n.is_received((ssn()-1-i) & mod_sns())) rbb[ws()-1-i] = 'R'; else rbb[ws()-1-i] = 'I'; diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 8cdac9a..c9a2233 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -1382,11 +1382,8 @@ /* trigger GPRS ack/nack */ struct msgb *msg1 = ul_tbf->create_ul_ack(*fn, ts_no); - /* TODO: Should not expect any BSN as nacked. - * should be fixed in subsequent patch - */ OSMO_ASSERT(!strcmp(osmo_hexdump(msg1->data, msg1->data_len), - "40 24 00 00 40 00 00 00 00 00 00 00 7e 24 46 68 81 4b 2b 2b 2b 2b 2b " + "40 24 00 00 7f ff ff ff ff ff ff ff fe 24 46 68 81 4b 2b 2b 2b 2b 2b " )); return ul_tbf; diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 6979652..9136d47 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -8072,5 +8072,5 @@ -- Frame 1 starts at offset 0, length=20, is_complete=0 - No gaps in received block, last block: BSN=0 CV=15 Encoding Ack/Nack for TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FLOW) (final=0) -- V(N): "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIR" R=Received I=Invalid -Uplink Ack/Nack bit count 139, max 184, message = 40 24 00 00 40 00 00 00 00 00 00 00 7e 24 46 68 81 4b 2b 2b 2b 2b 2b +- V(N): "RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR" R=Received I=Invalid +Uplink Ack/Nack bit count 139, max 184, message = 40 24 00 00 7f ff ff ff ff ff ff ff fe 24 46 68 81 4b 2b 2b 2b 2b 2b -- To view, visit https://gerrit.osmocom.org/771 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I98e586aa5cb9200cf03e092556304211d4d459aa Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Sun Aug 28 11:19:38 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Sun, 28 Aug 2016 11:19:38 +0000 Subject: osmo-pcu[master]: EGPRS: EPDAN decoding: add test case to show no ack_nack len... In-Reply-To: References: Message-ID: Patch Set 3: (1 comment) https://gerrit.osmocom.org/#/c/765/3/tests/rlcmac/RLCMACTest.cpp File tests/rlcmac/RLCMACTest.cpp: Line 231: OSMO_ASSERT(!strcmp(osmo_hexdump(urbb->URBB, (urbb->URBB_LENGTH + 7)/8), fix here. -- To view, visit https://gerrit.osmocom.org/765 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I8da84794748f2e81722c3eca69b46ccc3a21552e Gerrit-PatchSet: 3 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Sun Aug 28 11:21:52 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Sun, 28 Aug 2016 11:21:52 +0000 Subject: [PATCH] osmo-pcu[master]: EGPRS: EPDAN decoding: add test case to show no ack_nack len... In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/765 to look at the new patch set (#4). EGPRS: EPDAN decoding: add test case to show no ack_nack len issue This patch adds a test case itest_epdan_noack_nack_len_issue which expects a current bug with EGPRS EPDAN decoding Ack/Nack dissector length is not received. The test's expectation is corrected along with the bug fix in a subsequent commit Related: OS#1805 Change-Id: I8da84794748f2e81722c3eca69b46ccc3a21552e --- M tests/rlcmac/RLCMACTest.cpp 1 file changed, 23 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/65/765/4 diff --git a/tests/rlcmac/RLCMACTest.cpp b/tests/rlcmac/RLCMACTest.cpp index 466b89e..4f74ea4 100644 --- a/tests/rlcmac/RLCMACTest.cpp +++ b/tests/rlcmac/RLCMACTest.cpp @@ -30,6 +30,7 @@ #include "pcu_vty.h" #include #include +#include #include } using namespace std; @@ -211,6 +212,27 @@ bitvec_free(resultVector); } +void test_epdan_no_ack_nack_len() +{ + bitvec *vector = bitvec_alloc(23); + + bitvec_unhex(vector, "40200bffd161003e0e519ffffffb800000000000000000"); + RlcMacUplink_t data; + + decode_gsm_rlcmac_uplink(vector, &data); + + EGPRS_AckNack_Desc_t *urbb = + &data.u.Egprs_Packet_Downlink_Ack_Nack.EGPRS_AckNack.Desc; + /* + * TODO: URBB len is decoded as 102. so there is total 12 bytes and + * 6 bits in the 13th byte. in 13th byte we expect value + * as 0x00. But we see some incorrect value + */ + OSMO_ASSERT(strcmp(osmo_hexdump(urbb->URBB, 13), + "7f ff ff ee 00 00 00 00 00 00 00 00 00 " + )); +} + int main(int argc, char *argv[]) { osmo_init_logging(&gprs_log_info); @@ -218,5 +240,5 @@ //printSizeofRLCMAC(); testRlcMacDownlink(); testRlcMacUplink(); - + test_epdan_no_ack_nack_len(); } -- To view, visit https://gerrit.osmocom.org/765 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I8da84794748f2e81722c3eca69b46ccc3a21552e Gerrit-PatchSet: 4 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Sun Aug 28 11:24:54 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Sun, 28 Aug 2016 11:24:54 +0000 Subject: osmo-pcu[master]: Fix EGPRS EPDAN decoding: no ack nack dissector length In-Reply-To: References: Message-ID: Patch Set 3: (1 comment) https://gerrit.osmocom.org/#/c/766/3/tests/rlcmac/RLCMACTest.cpp File tests/rlcmac/RLCMACTest.cpp: Line 227: OSMO_ASSERT(!strcmp(osmo_hexdump(urbb->URBB, (urbb->URBB_LENGTH + 7)/8), fix it here -- To view, visit https://gerrit.osmocom.org/766 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieddf96aca82b0b0e917cfcc70aeb978799fb4e95 Gerrit-PatchSet: 3 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Sun Aug 28 11:25:51 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Sun, 28 Aug 2016 11:25:51 +0000 Subject: [PATCH] osmo-pcu[master]: Fix EGPRS EPDAN decoding: no ack nack dissector length In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/766 to look at the new patch set (#4). Fix EGPRS EPDAN decoding: no ack nack dissector length Earlier there was an incorrect decoding of URBB fields when EPDAN is received withot ack/Nack dissector length.This was a bottle neck for performance testing. Which has been fixed in this patch. Related: OS#1805 unit test assertion in the previous commit is fixed in this patch. Change-Id: Ieddf96aca82b0b0e917cfcc70aeb978799fb4e95 --- M src/csn1.cpp M tests/rlcmac/RLCMACTest.cpp 2 files changed, 4 insertions(+), 7 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/66/766/4 diff --git a/src/csn1.cpp b/src/csn1.cpp index d51fe83..da5fe3b 100644 --- a/src/csn1.cpp +++ b/src/csn1.cpp @@ -1111,6 +1111,7 @@ { /* extract bits */ guint8* pui8 = pui8DATA(data, pDescr->offset); gint16 nB1 = no_of_bits & 0x07;/* no_of_bits Mod 8 */ + no_of_bits -= nB1; while (no_of_bits > 0) { diff --git a/tests/rlcmac/RLCMACTest.cpp b/tests/rlcmac/RLCMACTest.cpp index 0dbfe3f..091fc5a 100644 --- a/tests/rlcmac/RLCMACTest.cpp +++ b/tests/rlcmac/RLCMACTest.cpp @@ -223,13 +223,9 @@ EGPRS_AckNack_Desc_t *urbb = &data.u.Egprs_Packet_Downlink_Ack_Nack.EGPRS_AckNack.Desc; - /* - * TODO: URBB len is decoded as 102. so there is total 12 bytes and - * 6 bits in the 13th byte. in 13th byte we expect value - * as 0x00. But we see 0xea. Which is incorrect - */ - OSMO_ASSERT(!strcmp(osmo_hexdump(urbb->URBB, (urbb->URBB_LENGTH + 7)/8), - "7f ff ff ee 00 00 00 00 00 00 00 00 ea " + + OSMO_ASSERT(!strcmp(osmo_hexdump(urbb->URBB, 13), + "7f ff ff ee 00 00 00 00 00 00 00 00 00 " )); } -- To view, visit https://gerrit.osmocom.org/766 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ieddf96aca82b0b0e917cfcc70aeb978799fb4e95 Gerrit-PatchSet: 4 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Sun Aug 28 11:39:12 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Sun, 28 Aug 2016 11:39:12 +0000 Subject: [PATCH] osmo-pcu[master]: EGPRS: EPDAN decoding: add test case to show no ack_nack len... In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/765 to look at the new patch set (#5). EGPRS: EPDAN decoding: add test case to show no ack_nack len issue This patch adds a test case itest_epdan_noack_nack_len_issue which expects a current bug with EGPRS EPDAN decoding Ack/Nack dissector length is not received. The test's expectation is corrected along with the bug fix in a subsequent commit Related: OS#1805 Change-Id: I8da84794748f2e81722c3eca69b46ccc3a21552e --- M tests/rlcmac/RLCMACTest.cpp M tests/tbf/TbfTest.cpp 2 files changed, 24 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/65/765/5 diff --git a/tests/rlcmac/RLCMACTest.cpp b/tests/rlcmac/RLCMACTest.cpp index 466b89e..4f74ea4 100644 --- a/tests/rlcmac/RLCMACTest.cpp +++ b/tests/rlcmac/RLCMACTest.cpp @@ -30,6 +30,7 @@ #include "pcu_vty.h" #include #include +#include #include } using namespace std; @@ -211,6 +212,27 @@ bitvec_free(resultVector); } +void test_epdan_no_ack_nack_len() +{ + bitvec *vector = bitvec_alloc(23); + + bitvec_unhex(vector, "40200bffd161003e0e519ffffffb800000000000000000"); + RlcMacUplink_t data; + + decode_gsm_rlcmac_uplink(vector, &data); + + EGPRS_AckNack_Desc_t *urbb = + &data.u.Egprs_Packet_Downlink_Ack_Nack.EGPRS_AckNack.Desc; + /* + * TODO: URBB len is decoded as 102. so there is total 12 bytes and + * 6 bits in the 13th byte. in 13th byte we expect value + * as 0x00. But we see some incorrect value + */ + OSMO_ASSERT(strcmp(osmo_hexdump(urbb->URBB, 13), + "7f ff ff ee 00 00 00 00 00 00 00 00 00 " + )); +} + int main(int argc, char *argv[]) { osmo_init_logging(&gprs_log_info); @@ -218,5 +240,5 @@ //printSizeofRLCMAC(); testRlcMacDownlink(); testRlcMacUplink(); - + test_epdan_no_ack_nack_len(); } diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 2feb9c3..a4de6c9 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -646,7 +646,7 @@ * simulate RACH, this sends an Immediate * Assignment Uplink on the AGCH */ - the_bts->rcv_rach(0x73, rach_fn, qta); + the_bts->rcv_rach(0x73, rach_fn, qta, 0, GSM_L1_BURST_TYPE_ACCESS_0); /* get next free TFI */ tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1); -- To view, visit https://gerrit.osmocom.org/765 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I8da84794748f2e81722c3eca69b46ccc3a21552e Gerrit-PatchSet: 5 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Sun Aug 28 11:39:12 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Sun, 28 Aug 2016 11:39:12 +0000 Subject: [PATCH] osmo-pcu[master]: Fix EGPRS EPDAN decoding: no ack nack dissector length In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/766 to look at the new patch set (#5). Fix EGPRS EPDAN decoding: no ack nack dissector length Earlier there was an incorrect decoding of URBB fields when EPDAN is received withot ack/Nack dissector length.This was a bottle neck for performance testing. Which has been fixed in this patch. Related: OS#1805 unit test assertion in the previous commit is fixed in this patch. Change-Id: Ieddf96aca82b0b0e917cfcc70aeb978799fb4e95 --- M src/csn1.cpp M tests/rlcmac/RLCMACTest.cpp 2 files changed, 2 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/66/766/5 diff --git a/src/csn1.cpp b/src/csn1.cpp index d51fe83..da5fe3b 100644 --- a/src/csn1.cpp +++ b/src/csn1.cpp @@ -1111,6 +1111,7 @@ { /* extract bits */ guint8* pui8 = pui8DATA(data, pDescr->offset); gint16 nB1 = no_of_bits & 0x07;/* no_of_bits Mod 8 */ + no_of_bits -= nB1; while (no_of_bits > 0) { diff --git a/tests/rlcmac/RLCMACTest.cpp b/tests/rlcmac/RLCMACTest.cpp index 4f74ea4..68a4005 100644 --- a/tests/rlcmac/RLCMACTest.cpp +++ b/tests/rlcmac/RLCMACTest.cpp @@ -228,7 +228,7 @@ * 6 bits in the 13th byte. in 13th byte we expect value * as 0x00. But we see some incorrect value */ - OSMO_ASSERT(strcmp(osmo_hexdump(urbb->URBB, 13), + OSMO_ASSERT(!strcmp(osmo_hexdump(urbb->URBB, 13), "7f ff ff ee 00 00 00 00 00 00 00 00 00 " )); } -- To view, visit https://gerrit.osmocom.org/766 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ieddf96aca82b0b0e917cfcc70aeb978799fb4e95 Gerrit-PatchSet: 5 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Sun Aug 28 11:42:09 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Sun, 28 Aug 2016 11:42:09 +0000 Subject: osmo-pcu[master]: EGPRS: EPDAN decoding: add test case to show no ack_nack len... In-Reply-To: References: Message-ID: Patch Set 5: (1 comment) https://gerrit.osmocom.org/#/c/765/5/tests/tbf/TbfTest.cpp File tests/tbf/TbfTest.cpp: Line 649: the_bts->rcv_rach(0x73, rach_fn, qta, 0, GSM_L1_BURST_TYPE_ACCESS_0); ignore this. This change is here only to align with current host compilation error -- To view, visit https://gerrit.osmocom.org/765 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I8da84794748f2e81722c3eca69b46ccc3a21552e Gerrit-PatchSet: 5 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Sun Aug 28 11:43:00 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Sun, 28 Aug 2016 11:43:00 +0000 Subject: osmo-pcu[master]: GPRS: PUAN encoding: add test case to show wrong BSNs status In-Reply-To: References: Message-ID: Patch Set 1: (1 comment) https://gerrit.osmocom.org/#/c/770/1/tests/tbf/TbfTest.cpp File tests/tbf/TbfTest.cpp: Line 649: the_bts->rcv_rach(0x73, rach_fn, qta, 0, GSM_L1_BURST_TYPE_ACCESS_0); Ignore this. This is only to align with current host compilation error. -- To view, visit https://gerrit.osmocom.org/770 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ied0f1dd3037d8fac6a772f4e097defb72634f955 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Sun Aug 28 11:52:42 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Sun, 28 Aug 2016 11:52:42 +0000 Subject: openbsc[master]: osmo-nitb: generate backtrace on SIGABRT In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/767 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia63aa5c39b26e27c3ee220d755c17d2c1ef636c5 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Harald Welte Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sun Aug 28 11:54:31 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Sun, 28 Aug 2016 11:54:31 +0000 Subject: osmo-pcu[master]: TBF flow: Coverity fix In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/769 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ib1f71a8940eed7ad74211092275dfa29aa353fc7 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sun Aug 28 11:55:02 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Sun, 28 Aug 2016 11:55:02 +0000 Subject: [MERGED] osmo-pcu[master]: TBF flow: Coverity fix In-Reply-To: References: Message-ID: arvind.sirsikar has submitted this change and it was merged. Change subject: TBF flow: Coverity fix ...................................................................... TBF flow: Coverity fix Related: CID#1361925, CID:#1361924 Change-Id: Ib1f71a8940eed7ad74211092275dfa29aa353fc7 --- M src/tbf_dl.cpp 1 file changed, 3 insertions(+), 0 deletions(-) Approvals: Jenkins Builder: Verified Holger Freyther: Looks good to me, approved diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp index a24cc21..4c67a12 100644 --- a/src/tbf_dl.cpp +++ b/src/tbf_dl.cpp @@ -691,6 +691,9 @@ msg_data = msgb_put(dl_msg, msg_len); + OSMO_ASSERT(rlc.num_data_blocks <= ARRAY_SIZE(rlc.block_info)); + OSMO_ASSERT(rlc.num_data_blocks > 0); + /* Copy block(s) to RLC message */ for (data_block_idx = 0; data_block_idx < rlc.num_data_blocks; data_block_idx++) -- To view, visit https://gerrit.osmocom.org/769 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ib1f71a8940eed7ad74211092275dfa29aa353fc7 Gerrit-PatchSet: 2 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Sun Aug 28 12:20:05 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Sun, 28 Aug 2016 12:20:05 +0000 Subject: osmo-pcu[master]: GPRS: PUAN encoding: add test case to show wrong BSNs status In-Reply-To: References: Message-ID: Patch Set 1: (2 comments) https://gerrit.osmocom.org/#/c/770/1/tests/tbf/TbfTest.cpp File tests/tbf/TbfTest.cpp: Line 649: the_bts->rcv_rach(0x73, rach_fn, qta, 0, GSM_L1_BURST_TYPE_ACCESS_0); > Ignore this. This is only to align with current host compilation error. yes, I sent an email to the list asking it to be fixed, otherwise please feel free to submit this as a separate patch and I merge it. Line 1388: OSMO_ASSERT(!strcmp(osmo_hexdump(msg1->data, msg1->data_len), That is good and I wouldn't want to go without it. But the idea was that with gprs_rlc_ul_window we could write unit tests that just utilize the window. E.g. see test_rlc_dl_ul_basic in tests/types/TypesTest.cpp. Could you create another test where wrapping is needed? -- To view, visit https://gerrit.osmocom.org/770 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ied0f1dd3037d8fac6a772f4e097defb72634f955 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Sun Aug 28 12:26:49 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Sun, 28 Aug 2016 12:26:49 +0000 Subject: [PATCH] osmo-pcu[master]: TBF flow: unit test compilation error fix Message-ID: Review at https://gerrit.osmocom.org/772 TBF flow: unit test compilation error fix Change-Id: I89638ba908e7d9964a5525061ce0cf26049be438 --- M tests/tbf/TbfTest.cpp 1 file changed, 1 insertion(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/72/772/1 diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 2feb9c3..a4de6c9 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -646,7 +646,7 @@ * simulate RACH, this sends an Immediate * Assignment Uplink on the AGCH */ - the_bts->rcv_rach(0x73, rach_fn, qta); + the_bts->rcv_rach(0x73, rach_fn, qta, 0, GSM_L1_BURST_TYPE_ACCESS_0); /* get next free TFI */ tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1); -- To view, visit https://gerrit.osmocom.org/772 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I89638ba908e7d9964a5525061ce0cf26049be438 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Sun Aug 28 12:49:07 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Sun, 28 Aug 2016 12:49:07 +0000 Subject: osmo-pcu[master]: TBF flow: unit test compilation error fix In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/772 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I89638ba908e7d9964a5525061ce0cf26049be438 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Sun Aug 28 12:49:10 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Sun, 28 Aug 2016 12:49:10 +0000 Subject: [MERGED] osmo-pcu[master]: TBF flow: unit test compilation error fix In-Reply-To: References: Message-ID: Holger Freyther has submitted this change and it was merged. Change subject: TBF flow: unit test compilation error fix ...................................................................... TBF flow: unit test compilation error fix Change-Id: I89638ba908e7d9964a5525061ce0cf26049be438 --- M tests/tbf/TbfTest.cpp 1 file changed, 1 insertion(+), 1 deletion(-) Approvals: Jenkins Builder: Verified Holger Freyther: Looks good to me, approved diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index 2feb9c3..a4de6c9 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -646,7 +646,7 @@ * simulate RACH, this sends an Immediate * Assignment Uplink on the AGCH */ - the_bts->rcv_rach(0x73, rach_fn, qta); + the_bts->rcv_rach(0x73, rach_fn, qta, 0, GSM_L1_BURST_TYPE_ACCESS_0); /* get next free TFI */ tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1); -- To view, visit https://gerrit.osmocom.org/772 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I89638ba908e7d9964a5525061ce0cf26049be438 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 29 07:03:55 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Mon, 29 Aug 2016 07:03:55 +0000 Subject: osmo-pcu[master]: EGPRS: EPDAN decoding: add test case to show no ack_nack len... In-Reply-To: References: Message-ID: Patch Set 5: Hi Neeels, I have incorporated the comments you have raised. Please have a look. Thanks, Aravind Sirsikar -- To view, visit https://gerrit.osmocom.org/765 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I8da84794748f2e81722c3eca69b46ccc3a21552e Gerrit-PatchSet: 5 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 29 09:17:34 2016 From: gerrit-no-reply at lists.osmocom.org (pravin) Date: Mon, 29 Aug 2016 09:17:34 +0000 Subject: [ABANDON] osmo-pcu[master]: Add test case for decompression of compressed bitmap In-Reply-To: References: Message-ID: pravin has abandoned this change. Change subject: Add test case for decompression of compressed bitmap ...................................................................... Abandoned Merged to gerrit_id:416 -- To view, visit https://gerrit.osmocom.org/417 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: abandon Gerrit-Change-Id: I0f26ec3d9eeace4ea8396ad5786a988fb58cf445 Gerrit-PatchSet: 3 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: pravin From gerrit-no-reply at lists.osmocom.org Mon Aug 29 09:23:00 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 09:23:00 +0000 Subject: [PATCH] libosmocore[master]: fix printf format for commit 'osmo_sock_init(): include host... Message-ID: Review at https://gerrit.osmocom.org/773 fix printf format for commit 'osmo_sock_init(): include host and port in error messages' Related: CID#143566 Change-Id: I75c542089749a0875d3d1913151fe838d7722ff2 --- M src/socket.c 1 file changed, 1 insertion(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/73/773/1 diff --git a/src/socket.c b/src/socket.c index a36aee7..19c513a 100644 --- a/src/socket.c +++ b/src/socket.c @@ -73,7 +73,7 @@ if ((flags & (OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT)) == (OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT)) { fprintf(stderr, "invalid: both bind and connect flags set:" - " %s:%u: %s\n", host, port); + " %s:%u\n", host, port); return -EINVAL; } -- To view, visit https://gerrit.osmocom.org/773 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I75c542089749a0875d3d1913151fe838d7722ff2 Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 29 09:25:39 2016 From: gerrit-no-reply at lists.osmocom.org (bhargava_abhyankar) Date: Mon, 29 Aug 2016 09:25:39 +0000 Subject: [PATCH] osmo-pcu[master]: Handle EGPRS 11 bit RACH in osmo-pcu In-Reply-To: References: Message-ID: Hello Harald Welte, arvind.sirsikar, Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/430 to look at the new patch set (#5). Handle EGPRS 11 bit RACH in osmo-pcu A function is_single_block is added to get request type of RACH. EGPRS 11 bit RACH is handled. Change-Id: I61d74a32f7764644ed86f7fdf97fa3c2f61503f7 --- M src/bts.cpp M src/bts.h 2 files changed, 81 insertions(+), 11 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/30/430/5 diff --git a/src/bts.cpp b/src/bts.cpp index e65d608..63ef1f6 100644 --- a/src/bts.cpp +++ b/src/bts.cpp @@ -479,20 +479,16 @@ uint8_t usf = 7; uint8_t tsc; uint16_t ta; + uint16_t ms_class = 0; + uint16_t priority = 0; rach_frame(); LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF on RACH, so we provide " "one:\n"); - if ((ra & 0xf8) == 0x70) { - LOGP(DRLCMAC, LOGL_DEBUG, "MS requests single block " - "allocation\n"); - sb = 1; - } else if (m_bts.force_two_phase) { - LOGP(DRLCMAC, LOGL_DEBUG, "MS requests single phase access, " - "but we force two phase access\n"); - sb = 1; - } + + sb = is_single_block(ra, burst_type, is_11bit, &ms_class, &priority); + if (qta < 0) qta = 0; if (qta > 252) @@ -515,8 +511,16 @@ } else { // Create new TBF #warning "Copy and paste with other routines.." - /* set class to 0, since we don't know the multislot class yet */ - tbf = tbf_alloc_ul_tbf(&m_bts, NULL, -1, 0, 0, 1); + + if (is_11bit == 1) { + tbf = tbf_alloc_ul_tbf(&m_bts, NULL, -1, 0, + ms_class, 1); + } else { + /* set class to 0,as we don't know the multislot */ + /* class yet */ + tbf = tbf_alloc_ul_tbf(&m_bts, NULL, -1, 0, 0, 1); + } + if (!tbf) { LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH resource\n"); /* FIXME: send reject */ @@ -564,6 +568,70 @@ return 0; } +uint8_t BTS::is_single_block(uint16_t ra, enum ph_burst_type burst_type, + uint8_t is_11bit, uint16_t *ms_class, uint16_t *priority) +{ + uint8_t sb = 0, val = 0; + + if ((is_11bit == 0) && (burst_type == GSM_L1_BURST_TYPE_ACCESS_0)) { + + if ((ra & 0xf8) == 0x70) { + LOGP(DRLCMAC, LOGL_DEBUG, "MS requests single block " + "allocation\n"); + sb = 1; + } else if (m_bts.force_two_phase) { + LOGP(DRLCMAC, LOGL_DEBUG, "MS requests single " + "phase access,but we force two phase access\n"); + sb = 1; + } + + } else if ((is_11bit == 1) && + ((burst_type == GSM_L1_BURST_TYPE_ACCESS_1) || + (burst_type == GSM_L1_BURST_TYPE_ACCESS_2))) { + + val = !!(ra & (1 << 10)); + + if (val == 0) { + if (m_bts.force_two_phase) { + LOGP(DRLCMAC, LOGL_DEBUG, "EGPRS 11 bit RACH " + "received. MS requests single phase access " + "but we force two phase access\n"); + sb = 1; + } else { + sb = 0; + *ms_class = (ra & 0x3e0) >> 5; + *priority = ((ra & 0x18) >> 3); + } + + } else { + LOGP(DRLCMAC, LOGL_DEBUG, "EGPRS 11 bit RACH received." + "MS requests single block allocation\n"); + sb = 1; + } + + } else if ((is_11bit == 1) && + (burst_type == GSM_L1_BURST_TYPE_ACCESS_0)) { + LOGP(DRLCMAC, LOGL_ERROR, + "Error: GPRS 11 bit RACH not supported\n"); + + } else if (burst_type == GSM_L1_BURST_TYPE_NONE) { + LOGP(DRLCMAC, LOGL_DEBUG, "pcu has not received burst type " + "from bts \n"); + + if ((ra & 0xf8) == 0x70) { + LOGP(DRLCMAC, LOGL_DEBUG, "MS requests single block " + "allocation\n"); + sb = 1; + } else if (m_bts.force_two_phase) { + LOGP(DRLCMAC, LOGL_DEBUG, "MS requests single " + "phase access,but we force two phase access\n"); + sb = 1; + } + } + + return sb; +} + /* depending on the current TBF, we assign on PACCH or AGCH */ void BTS::trigger_dl_ass( struct gprs_rlcmac_dl_tbf *dl_tbf, diff --git a/src/bts.h b/src/bts.h index 801342d..ba6fc4d 100644 --- a/src/bts.h +++ b/src/bts.h @@ -290,6 +290,8 @@ int tfi_find_free(enum gprs_rlcmac_tbf_direction dir, uint8_t *_trx, int8_t use_trx); int rcv_imm_ass_cnf(const uint8_t *data, uint32_t fn); + uint8_t is_single_block(uint16_t ra, enum ph_burst_type burst_type, + uint8_t is_11bit, uint16_t *ms_class, uint16_t *priority); int rcv_rach(uint16_t ra, uint32_t Fn, int16_t qta, uint8_t is_11bit, enum ph_burst_type burst_type); -- To view, visit https://gerrit.osmocom.org/430 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I61d74a32f7764644ed86f7fdf97fa3c2f61503f7 Gerrit-PatchSet: 5 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: arvind.sirsikar Gerrit-Reviewer: bhargava_abhyankar From gerrit-no-reply at lists.osmocom.org Mon Aug 29 09:25:39 2016 From: gerrit-no-reply at lists.osmocom.org (bhargava_abhyankar) Date: Mon, 29 Aug 2016 09:25:39 +0000 Subject: [PATCH] osmo-pcu[master]: Update the function immediate assignment for EGPRS In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Harald Welte, arvind.sirsikar, Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/431 to look at the new patch set (#6). Update the function immediate assignment for EGPRS Encode the EGPRS fields of immediate assignment message in uplink when EGPRS PACKET CHANNEL REQUEST (11 bit RACH) is received. The series of patches for 11 bit RACH are dependent on libosmocore and osmo-bts patches for 11 bit RACH. Change-Id: Ie5e309156e5dbbb6add74a1b4d257c4ee2332e52 --- M src/bts.cpp M src/encoding.cpp M src/encoding.h M tests/edge/EdgeTest.cpp 4 files changed, 86 insertions(+), 12 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/31/431/6 diff --git a/src/bts.cpp b/src/bts.cpp index 63ef1f6..e90f97d 100644 --- a/src/bts.cpp +++ b/src/bts.cpp @@ -555,7 +555,7 @@ plen = Encoding::write_immediate_assignment( tbf, immediate_assignment, 0, ra, Fn, ta, m_bts.trx[trx_no].arfcn, ts_no, tsc, usf, 0, sb_fn, - m_bts.alpha, m_bts.gamma, -1); + m_bts.alpha, m_bts.gamma, -1, burst_type, sb); if (plen >= 0) { pcu_l1if_tx_agch(immediate_assignment, plen); diff --git a/src/encoding.cpp b/src/encoding.cpp index 41e0d10..7d3fa14 100644 --- a/src/encoding.cpp +++ b/src/encoding.cpp @@ -147,11 +147,71 @@ gprs_rlcmac_ul_tbf *tbf, bitvec * dest, unsigned& wp, uint8_t usf, uint32_t fn, - uint8_t alpha, uint8_t gamma, int8_t ta_idx) + uint8_t alpha, uint8_t gamma, int8_t ta_idx, + enum ph_burst_type burst_type, uint16_t ra) { - LOGP(DRLCMACUL, LOGL_ERROR, - "EGPRS Packet Uplink Assignment is not yet implemented\n"); - return -EINVAL; + unsigned int ws_enc = 0; + uint8_t extended_ra = 0; + + extended_ra = (ra & 0x1F); + + bitvec_write_field(dest, wp, 1, 2); /* LH */ + bitvec_write_field(dest, wp, 0, 2); /* 0 EGPRS Uplink Assignment */ + bitvec_write_field(dest, wp, extended_ra, 5); /* Extended RA */ + bitvec_write_field(dest, wp, 0, 1); /* Access technology Request */ + + if (tbf == NULL) { + + bitvec_write_field(dest, wp, 0, 1); /* multiblock allocation */ + + if (alpha) { + bitvec_write_field(dest, wp, 0x1, 1); /* ALPHA =yes */ + bitvec_write_field(dest, wp, alpha, 4); /* ALPHA */ + } else { + bitvec_write_field(dest, wp, 0x0, 1); /* ALPHA = no */ + } + + bitvec_write_field(dest, wp, gamma, 5); /* GAMMA power contrl */ + bitvec_write_field(dest, wp, (fn / (26 * 51)) % 32, 5);/* T1' */ + bitvec_write_field(dest, wp, fn % 51, 6); /* T3 */ + bitvec_write_field(dest, wp, fn % 26, 5); /* T2 */ + bitvec_write_field(dest, wp, 0, 2); /* Radio block allocation */ + + bitvec_write_field(dest, wp, 0, 1); + + } else { + + ws_enc = (tbf->m_window.ws() - 64) / 32; + + bitvec_write_field(dest, wp, 1, 1); /* single block alloc */ + bitvec_write_field(dest, wp, tbf->tfi(), 5);/* TFI assignment */ + bitvec_write_field(dest, wp, 0, 1); /* polling bit */ + bitvec_write_field(dest, wp, 0, 1); /* constant */ + bitvec_write_field(dest, wp, usf, 3); /* USF bit */ + bitvec_write_field(dest, wp, 0, 1); /* USF granularity */ + bitvec_write_field(dest, wp, 0, 1); /* P0 */ + /* MCS */ + bitvec_write_field(dest, wp, tbf->current_cs().to_num()-1, 4); + /* tlli channel block */ + bitvec_write_field(dest, wp, tbf->tlli(), 1); + bitvec_write_field(dest, wp, 0, 1); /* BEP period present */ + bitvec_write_field(dest, wp, 0, 1); /* resegmentation */ + bitvec_write_field(dest, wp, ws_enc, 5);/* egprs window_size */ + + if (alpha) { + bitvec_write_field(dest, wp, 0x1, 1); /* ALPHA =yes */ + bitvec_write_field(dest, wp, alpha, 4); /* ALPHA */ + } else { + bitvec_write_field(dest, wp, 0x0, 1); /* ALPHA = no */ + } + + bitvec_write_field(dest, wp, gamma, 5); /* GAMMA power contrl */ + bitvec_write_field(dest, wp, 0, 1); /* TIMING_ADVANCE_INDEX */ + bitvec_write_field(dest, wp, 0, 1); /* TBF_STARTING_TIME_FLAG */ + bitvec_write_field(dest, wp, 0, 1); /* NULL */ + } + + return 0; } /* @@ -160,10 +220,10 @@ */ int Encoding::write_immediate_assignment( struct gprs_rlcmac_tbf *tbf, - bitvec * dest, uint8_t downlink, uint8_t ra, + bitvec * dest, uint8_t downlink, uint16_t ra, uint32_t ref_fn, uint8_t ta, uint16_t arfcn, uint8_t ts, uint8_t tsc, uint8_t usf, uint8_t polling, uint32_t fn, uint8_t alpha, - uint8_t gamma, int8_t ta_idx) + uint8_t gamma, int8_t ta_idx, enum ph_burst_type burst_type, uint8_t sb) { unsigned wp = 0; int plen; @@ -189,7 +249,13 @@ bitvec_write_field(dest, wp,arfcn,10); // ARFCN //10.5.2.30 Request Reference - bitvec_write_field(dest, wp,ra,8); // RA + if (((burst_type == GSM_L1_BURST_TYPE_ACCESS_1) || + (burst_type == GSM_L1_BURST_TYPE_ACCESS_2))) { + bitvec_write_field(dest, wp, 0x7f, 8); /* RACH value */ + } else { + bitvec_write_field(dest, wp, ra, 8); /* RACH value */ + } + bitvec_write_field(dest, wp,(ref_fn / (26 * 51)) % 32,5); // T1' bitvec_write_field(dest, wp,ref_fn % 51,6); // T3 bitvec_write_field(dest, wp,ref_fn % 26,5); // T2 @@ -213,10 +279,11 @@ rc = write_ia_rest_downlink(as_dl_tbf(tbf), dest, wp, polling, gsm48_ta_is_valid(ta), fn, alpha, gamma, ta_idx); - else if (as_ul_tbf(tbf) && as_ul_tbf(tbf)->is_egprs_enabled()) + else if (((burst_type == GSM_L1_BURST_TYPE_ACCESS_1) || + (burst_type == GSM_L1_BURST_TYPE_ACCESS_2))) rc = write_ia_rest_egprs_uplink(as_ul_tbf(tbf), dest, wp, usf, fn, - alpha, gamma, ta_idx); + alpha, gamma, ta_idx, burst_type, ra); else rc = write_ia_rest_uplink(as_ul_tbf(tbf), dest, wp, usf, fn, diff --git a/src/encoding.h b/src/encoding.h index 710de78..69f8cdc 100644 --- a/src/encoding.h +++ b/src/encoding.h @@ -23,6 +23,9 @@ #include #include #include +extern "C" { +#include +} struct gprs_rlcmac_bts; struct gprs_rlcmac_tbf; @@ -40,11 +43,14 @@ public: static int write_immediate_assignment( struct gprs_rlcmac_tbf *tbf, - bitvec * dest, uint8_t downlink, uint8_t ra, + bitvec * dest, uint8_t downlink, uint16_t ra, uint32_t ref_fn, uint8_t ta, uint16_t arfcn, uint8_t ts, uint8_t tsc, uint8_t usf, uint8_t polling, uint32_t fn, uint8_t alpha, uint8_t gamma, - int8_t ta_idx); + int8_t ta_idx, + enum ph_burst_type burst_type = + GSM_L1_BURST_TYPE_ACCESS_0, + uint8_t sb = 1); static void write_packet_uplink_assignment( struct gprs_rlcmac_bts *bts, diff --git a/tests/edge/EdgeTest.cpp b/tests/edge/EdgeTest.cpp index 9081d4d..0e7378e 100644 --- a/tests/edge/EdgeTest.cpp +++ b/tests/edge/EdgeTest.cpp @@ -36,6 +36,7 @@ #include #include #include +#include } #include -- To view, visit https://gerrit.osmocom.org/431 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ie5e309156e5dbbb6add74a1b4d257c4ee2332e52 Gerrit-PatchSet: 6 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-Reviewer: bhargava_abhyankar From gerrit-no-reply at lists.osmocom.org Mon Aug 29 09:27:34 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Mon, 29 Aug 2016 09:27:34 +0000 Subject: osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Patch Set 5: (4 comments) https://gerrit.osmocom.org/#/c/416/21/src/egprs_rlc_compression.h File src/egprs_rlc_compression.h: Line 17: #define MOD8(X) (((X)+8) & (0x07)) can we move it to .cpp/.c file? Line 18: can we move it to .cpp/.c file? Line 26: extern const char *zero_run_len_code_list[MAX_CDWDTBL_LEN]; Can you use scope as private here? Line 38: } Keep Public first and then private. I have noticed in many .h file . -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 5 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-Reviewer: pravin Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Mon Aug 29 09:42:59 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 09:42:59 +0000 Subject: libosmocore[master]: fix printf format for commit 'osmo_sock_init(): include host... In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/773 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I75c542089749a0875d3d1913151fe838d7722ff2 Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 29 09:43:02 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 09:43:02 +0000 Subject: [MERGED] libosmocore[master]: fix printf format for commit 'osmo_sock_init(): include host... In-Reply-To: References: Message-ID: Neels Hofmeyr has submitted this change and it was merged. Change subject: fix printf format for commit 'osmo_sock_init(): include host and port in error messages' ...................................................................... fix printf format for commit 'osmo_sock_init(): include host and port in error messages' Related: CID#143566 Change-Id: I75c542089749a0875d3d1913151fe838d7722ff2 --- M src/socket.c 1 file changed, 1 insertion(+), 1 deletion(-) Approvals: Neels Hofmeyr: Looks good to me, approved Jenkins Builder: Verified diff --git a/src/socket.c b/src/socket.c index a36aee7..19c513a 100644 --- a/src/socket.c +++ b/src/socket.c @@ -73,7 +73,7 @@ if ((flags & (OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT)) == (OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT)) { fprintf(stderr, "invalid: both bind and connect flags set:" - " %s:%u: %s\n", host, port); + " %s:%u\n", host, port); return -EINVAL; } -- To view, visit https://gerrit.osmocom.org/773 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I75c542089749a0875d3d1913151fe838d7722ff2 Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 29 09:54:23 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Mon, 29 Aug 2016 09:54:23 +0000 Subject: osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Patch Set 21: (4 comments) https://gerrit.osmocom.org/#/c/416/21/tests/bitcomp/BitcompTest.cpp File tests/bitcomp/BitcompTest.cpp: Line 26: uint8_t crbb_data[MAX_CRBB_LEN]; /* compressed data */ check for extra space Line 216: tall_pcu_ctx = talloc_named_const(NULL, 1, "moiji-mobile TbfTest context"); change TbfTest context Line 220: test_EPDAN_decode_tree(); can you write a test cases(1 or 2) to validate the csn1 part?. capture a OTA hex stream and validate. refer RLCMACTest.cpp Line 226: } can you leave a empty line here? -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 21 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-Reviewer: pravin Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Mon Aug 29 09:58:29 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Mon, 29 Aug 2016 09:58:29 +0000 Subject: osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Patch Set 21: (1 comment) https://gerrit.osmocom.org/#/c/416/21//COMMIT_MSG Commit Message: Line 7: Add decoding of compressed bitmap in EPDAN EGPRS: Add EPDAN CRBB support -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 21 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-Reviewer: pravin Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Mon Aug 29 10:02:48 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Mon, 29 Aug 2016 10:02:48 +0000 Subject: osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Patch Set 21: (2 comments) https://gerrit.osmocom.org/#/c/416/21/src/egprs_rlc_compression.cpp File src/egprs_rlc_compression.cpp: Line 1: /* egprs_rlc_compression.h Logs are missing from whole file. Can we have a debug logs at least at debug level? Line 49: if (cdwd[idx][i] == '0') { good to keep the debug level log here? -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 21 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-Reviewer: pravin Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Mon Aug 29 10:03:23 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Mon, 29 Aug 2016 10:03:23 +0000 Subject: osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Patch Set 21: Code-Review-1 -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 21 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-Reviewer: pravin Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 29 11:12:26 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 11:12:26 +0000 Subject: [ABANDON] openbsc[master]: IuPS: sgsn-test: link Iu related libs In-Reply-To: References: Message-ID: Neels Hofmeyr has abandoned this change. Change subject: IuPS: sgsn-test: link Iu related libs ...................................................................... Abandoned will be merged into 731 -- To view, visit https://gerrit.osmocom.org/730 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: abandon Gerrit-Change-Id: I4c05f15c29797456ddcd7c95bfb7dfd480101577 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: daniel Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Mon Aug 29 11:19:53 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 11:19:53 +0000 Subject: [PATCH] libosmocore[master]: IuPS: add GMM Service Request related constants and value_str Message-ID: Review at https://gerrit.osmocom.org/774 IuPS: add GMM Service Request related constants and value_str Change-Id: Ie023fc78099932f95cc8f1b3a04fe25dfd14bc35 --- M include/osmocom/gsm/protocol/gsm_04_08_gprs.h 1 file changed, 16 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/74/774/1 diff --git a/include/osmocom/gsm/protocol/gsm_04_08_gprs.h b/include/osmocom/gsm/protocol/gsm_04_08_gprs.h index af828fb..cda1e48 100644 --- a/include/osmocom/gsm/protocol/gsm_04_08_gprs.h +++ b/include/osmocom/gsm/protocol/gsm_04_08_gprs.h @@ -73,6 +73,11 @@ extern const struct value_string *gprs_upd_t_strs; +/* Table 10.4 in 3GPP TS 24.008 (successor to 04.08) */ +#define GSM48_MT_GMM_SERVICE_REQ 0x0c +#define GSM48_MT_GMM_SERVICE_ACK 0x0d +#define GSM48_MT_GMM_SERVICE_REJ 0x0e + enum gsm48_gprs_ie_mm { GSM48_IE_GMM_CIPH_CKSN = 0x08, /* 10.5.1.2 */ GSM48_IE_GMM_TIMER_READY = 0x17, /* 10.5.7.3 */ @@ -365,6 +370,17 @@ GSM48_QOS_SERR_1e_1 = 0x07, }; +/* 3GPP 24.008 / Chapter 10.5.5.20 / Table 10.5.153a */ +enum gsm48_gmm_service_type { + GPRS_SERVICE_T_SIGNALLING = 0x00, + GPRS_SERVICE_T_DATA = 0x01, + GPRS_SERVICE_T_PAGING_RESP = 0x02, + GPRS_SERVICE_T_MBMS_MC_SERV = 0x03, + GPRS_SERVICE_T_MBMS_BC_SERV = 0x04, +}; + +extern const struct value_string *gprs_service_t_strs; + bool gprs_ms_net_cap_gea_supported(const uint8_t *ms_net_cap, uint8_t cap_len, enum gprs_ciph_algo gea); -- To view, visit https://gerrit.osmocom.org/774 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ie023fc78099932f95cc8f1b3a04fe25dfd14bc35 Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 29 11:21:59 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 11:21:59 +0000 Subject: [PATCH] libosmocore[master]: IuPS: add GMM Service Request related constants and value_str In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/774 to look at the new patch set (#2). IuPS: add GMM Service Request related constants and value_str Change-Id: Ie023fc78099932f95cc8f1b3a04fe25dfd14bc35 --- M include/osmocom/gsm/protocol/gsm_04_08_gprs.h M src/gsm/gsm_04_08_gprs.c 2 files changed, 27 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/74/774/2 diff --git a/include/osmocom/gsm/protocol/gsm_04_08_gprs.h b/include/osmocom/gsm/protocol/gsm_04_08_gprs.h index af828fb..cda1e48 100644 --- a/include/osmocom/gsm/protocol/gsm_04_08_gprs.h +++ b/include/osmocom/gsm/protocol/gsm_04_08_gprs.h @@ -73,6 +73,11 @@ extern const struct value_string *gprs_upd_t_strs; +/* Table 10.4 in 3GPP TS 24.008 (successor to 04.08) */ +#define GSM48_MT_GMM_SERVICE_REQ 0x0c +#define GSM48_MT_GMM_SERVICE_ACK 0x0d +#define GSM48_MT_GMM_SERVICE_REJ 0x0e + enum gsm48_gprs_ie_mm { GSM48_IE_GMM_CIPH_CKSN = 0x08, /* 10.5.1.2 */ GSM48_IE_GMM_TIMER_READY = 0x17, /* 10.5.7.3 */ @@ -365,6 +370,17 @@ GSM48_QOS_SERR_1e_1 = 0x07, }; +/* 3GPP 24.008 / Chapter 10.5.5.20 / Table 10.5.153a */ +enum gsm48_gmm_service_type { + GPRS_SERVICE_T_SIGNALLING = 0x00, + GPRS_SERVICE_T_DATA = 0x01, + GPRS_SERVICE_T_PAGING_RESP = 0x02, + GPRS_SERVICE_T_MBMS_MC_SERV = 0x03, + GPRS_SERVICE_T_MBMS_BC_SERV = 0x04, +}; + +extern const struct value_string *gprs_service_t_strs; + bool gprs_ms_net_cap_gea_supported(const uint8_t *ms_net_cap, uint8_t cap_len, enum gprs_ciph_algo gea); diff --git a/src/gsm/gsm_04_08_gprs.c b/src/gsm/gsm_04_08_gprs.c index 7cfcc80..14207f8 100644 --- a/src/gsm/gsm_04_08_gprs.c +++ b/src/gsm/gsm_04_08_gprs.c @@ -199,3 +199,14 @@ }; const struct value_string *gprs_det_t_mt_strs = gprs_det_t_mt_strs_; + +const struct value_string gprs_service_t_strs_[] = { + { GPRS_SERVICE_T_SIGNALLING, "signalling" }, + { GPRS_SERVICE_T_DATA, "data" }, + { GPRS_SERVICE_T_PAGING_RESP, "paging response" }, + { GPRS_SERVICE_T_MBMS_MC_SERV, "MBMS multicast service" }, + { GPRS_SERVICE_T_MBMS_BC_SERV, "MBMS broadcast service" }, + { 0, NULL } +}; + +const struct value_string *gprs_service_t_strs = gprs_service_t_strs_; -- To view, visit https://gerrit.osmocom.org/774 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ie023fc78099932f95cc8f1b3a04fe25dfd14bc35 Gerrit-PatchSet: 2 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 29 11:33:35 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 11:33:35 +0000 Subject: [ABANDON] openbsc[master]: IuPS: GMM Service Request: add local gsm_04_08_gprs.h and .c In-Reply-To: References: Message-ID: Neels Hofmeyr has abandoned this change. Change subject: IuPS: GMM Service Request: add local gsm_04_08_gprs.h and .c ...................................................................... Abandoned moved to libosmogsm, https://gerrit.osmocom.org/774 -- To view, visit https://gerrit.osmocom.org/736 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: abandon Gerrit-Change-Id: Iaf9316f07d21280b6e090d65892c338f9555313a Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 29 11:47:29 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 11:47:29 +0000 Subject: libosmocore[master]: IuPS: add GMM Service Request related constants and value_str In-Reply-To: References: Message-ID: Patch Set 2: > http://jenkins.osmocom.org/jenkins/job/libosmocore-gerrit/153/ : > FAILURE timer test failed, retriggered -- To view, visit https://gerrit.osmocom.org/774 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ie023fc78099932f95cc8f1b3a04fe25dfd14bc35 Gerrit-PatchSet: 2 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 29 11:56:27 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 11:56:27 +0000 Subject: [PATCH] libosmocore[master]: IuPS: add GMM Service Request related constants and value_str In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/774 to look at the new patch set (#3). IuPS: add GMM Service Request related constants and value_str Change-Id: Ie023fc78099932f95cc8f1b3a04fe25dfd14bc35 --- M include/osmocom/gsm/protocol/gsm_04_08_gprs.h M src/gsm/gsm_04_08_gprs.c M src/gsm/libosmogsm.map 3 files changed, 28 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/74/774/3 diff --git a/include/osmocom/gsm/protocol/gsm_04_08_gprs.h b/include/osmocom/gsm/protocol/gsm_04_08_gprs.h index af828fb..cda1e48 100644 --- a/include/osmocom/gsm/protocol/gsm_04_08_gprs.h +++ b/include/osmocom/gsm/protocol/gsm_04_08_gprs.h @@ -73,6 +73,11 @@ extern const struct value_string *gprs_upd_t_strs; +/* Table 10.4 in 3GPP TS 24.008 (successor to 04.08) */ +#define GSM48_MT_GMM_SERVICE_REQ 0x0c +#define GSM48_MT_GMM_SERVICE_ACK 0x0d +#define GSM48_MT_GMM_SERVICE_REJ 0x0e + enum gsm48_gprs_ie_mm { GSM48_IE_GMM_CIPH_CKSN = 0x08, /* 10.5.1.2 */ GSM48_IE_GMM_TIMER_READY = 0x17, /* 10.5.7.3 */ @@ -365,6 +370,17 @@ GSM48_QOS_SERR_1e_1 = 0x07, }; +/* 3GPP 24.008 / Chapter 10.5.5.20 / Table 10.5.153a */ +enum gsm48_gmm_service_type { + GPRS_SERVICE_T_SIGNALLING = 0x00, + GPRS_SERVICE_T_DATA = 0x01, + GPRS_SERVICE_T_PAGING_RESP = 0x02, + GPRS_SERVICE_T_MBMS_MC_SERV = 0x03, + GPRS_SERVICE_T_MBMS_BC_SERV = 0x04, +}; + +extern const struct value_string *gprs_service_t_strs; + bool gprs_ms_net_cap_gea_supported(const uint8_t *ms_net_cap, uint8_t cap_len, enum gprs_ciph_algo gea); diff --git a/src/gsm/gsm_04_08_gprs.c b/src/gsm/gsm_04_08_gprs.c index 7cfcc80..14207f8 100644 --- a/src/gsm/gsm_04_08_gprs.c +++ b/src/gsm/gsm_04_08_gprs.c @@ -199,3 +199,14 @@ }; const struct value_string *gprs_det_t_mt_strs = gprs_det_t_mt_strs_; + +const struct value_string gprs_service_t_strs_[] = { + { GPRS_SERVICE_T_SIGNALLING, "signalling" }, + { GPRS_SERVICE_T_DATA, "data" }, + { GPRS_SERVICE_T_PAGING_RESP, "paging response" }, + { GPRS_SERVICE_T_MBMS_MC_SERV, "MBMS multicast service" }, + { GPRS_SERVICE_T_MBMS_BC_SERV, "MBMS broadcast service" }, + { 0, NULL } +}; + +const struct value_string *gprs_service_t_strs = gprs_service_t_strs_; diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map index f530b6f..dc8559f 100644 --- a/src/gsm/libosmogsm.map +++ b/src/gsm/libosmogsm.map @@ -56,6 +56,7 @@ gprs_upd_t_strs; gprs_det_t_mo_strs; gprs_det_t_mt_strs; +gprs_service_t_strs; gsm0341_build_msg; -- To view, visit https://gerrit.osmocom.org/774 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ie023fc78099932f95cc8f1b3a04fe25dfd14bc35 Gerrit-PatchSet: 3 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 29 12:31:37 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Mon, 29 Aug 2016 12:31:37 +0000 Subject: osmo-pcu[master]: Add decoding of compressed bitmap in EPDAN In-Reply-To: References: Message-ID: Patch Set 21: (2 comments) https://gerrit.osmocom.org/#/c/416/21//COMMIT_MSG Commit Message: Line 7: Add decoding of compressed bitmap in EPDAN > EGPRS: Add EPDAN CRBB support "EGPRS: Add EPDAN CRBB Tree based decoding" would be more better. https://gerrit.osmocom.org/#/c/416/21/tests/bitcomp/BitcompTest.cpp File tests/bitcomp/BitcompTest.cpp: Line 220: test_EPDAN_decode_tree(); > can you write a test cases(1 or 2) to validate the csn1 part?. capture a OT As csn1 validation is already handled with existing algorithm we can drop this comment. -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 21 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-Reviewer: pravin Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Mon Aug 29 13:29:14 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 13:29:14 +0000 Subject: libosmocore[master]: IuPS: add GMM Service Request related constants and value_str In-Reply-To: References: Message-ID: Patch Set 3: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/774 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ie023fc78099932f95cc8f1b3a04fe25dfd14bc35 Gerrit-PatchSet: 3 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 29 13:29:16 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 13:29:16 +0000 Subject: [MERGED] libosmocore[master]: IuPS: add GMM Service Request related constants and value_str In-Reply-To: References: Message-ID: Neels Hofmeyr has submitted this change and it was merged. Change subject: IuPS: add GMM Service Request related constants and value_str ...................................................................... IuPS: add GMM Service Request related constants and value_str Change-Id: Ie023fc78099932f95cc8f1b3a04fe25dfd14bc35 --- M include/osmocom/gsm/protocol/gsm_04_08_gprs.h M src/gsm/gsm_04_08_gprs.c M src/gsm/libosmogsm.map 3 files changed, 28 insertions(+), 0 deletions(-) Approvals: Neels Hofmeyr: Looks good to me, approved Jenkins Builder: Verified diff --git a/include/osmocom/gsm/protocol/gsm_04_08_gprs.h b/include/osmocom/gsm/protocol/gsm_04_08_gprs.h index af828fb..cda1e48 100644 --- a/include/osmocom/gsm/protocol/gsm_04_08_gprs.h +++ b/include/osmocom/gsm/protocol/gsm_04_08_gprs.h @@ -73,6 +73,11 @@ extern const struct value_string *gprs_upd_t_strs; +/* Table 10.4 in 3GPP TS 24.008 (successor to 04.08) */ +#define GSM48_MT_GMM_SERVICE_REQ 0x0c +#define GSM48_MT_GMM_SERVICE_ACK 0x0d +#define GSM48_MT_GMM_SERVICE_REJ 0x0e + enum gsm48_gprs_ie_mm { GSM48_IE_GMM_CIPH_CKSN = 0x08, /* 10.5.1.2 */ GSM48_IE_GMM_TIMER_READY = 0x17, /* 10.5.7.3 */ @@ -365,6 +370,17 @@ GSM48_QOS_SERR_1e_1 = 0x07, }; +/* 3GPP 24.008 / Chapter 10.5.5.20 / Table 10.5.153a */ +enum gsm48_gmm_service_type { + GPRS_SERVICE_T_SIGNALLING = 0x00, + GPRS_SERVICE_T_DATA = 0x01, + GPRS_SERVICE_T_PAGING_RESP = 0x02, + GPRS_SERVICE_T_MBMS_MC_SERV = 0x03, + GPRS_SERVICE_T_MBMS_BC_SERV = 0x04, +}; + +extern const struct value_string *gprs_service_t_strs; + bool gprs_ms_net_cap_gea_supported(const uint8_t *ms_net_cap, uint8_t cap_len, enum gprs_ciph_algo gea); diff --git a/src/gsm/gsm_04_08_gprs.c b/src/gsm/gsm_04_08_gprs.c index 7cfcc80..14207f8 100644 --- a/src/gsm/gsm_04_08_gprs.c +++ b/src/gsm/gsm_04_08_gprs.c @@ -199,3 +199,14 @@ }; const struct value_string *gprs_det_t_mt_strs = gprs_det_t_mt_strs_; + +const struct value_string gprs_service_t_strs_[] = { + { GPRS_SERVICE_T_SIGNALLING, "signalling" }, + { GPRS_SERVICE_T_DATA, "data" }, + { GPRS_SERVICE_T_PAGING_RESP, "paging response" }, + { GPRS_SERVICE_T_MBMS_MC_SERV, "MBMS multicast service" }, + { GPRS_SERVICE_T_MBMS_BC_SERV, "MBMS broadcast service" }, + { 0, NULL } +}; + +const struct value_string *gprs_service_t_strs = gprs_service_t_strs_; diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map index f530b6f..dc8559f 100644 --- a/src/gsm/libosmogsm.map +++ b/src/gsm/libosmogsm.map @@ -56,6 +56,7 @@ gprs_upd_t_strs; gprs_det_t_mo_strs; gprs_det_t_mt_strs; +gprs_service_t_strs; gsm0341_build_msg; -- To view, visit https://gerrit.osmocom.org/774 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ie023fc78099932f95cc8f1b3a04fe25dfd14bc35 Gerrit-PatchSet: 3 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 29 13:37:39 2016 From: gerrit-no-reply at lists.osmocom.org (lynxis lazus) Date: Mon, 29 Aug 2016 13:37:39 +0000 Subject: [PATCH] osmo-pcu[master]: llc: remove NULL-pointer check of gprs_llc_queue::size()/oct... In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/213 to look at the new patch set (#4). llc: remove NULL-pointer check of gprs_llc_queue::size()/octets() All callers now check the pointer before calling it. gcc6 is optimizing `if (!this) {CODE}` as this is assumed to never be a std::nullptr here. Change-Id: I918a094e0dc59098a9eb00d152c9ae42d36b3a99 --- M src/llc.h 1 file changed, 2 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/13/213/4 diff --git a/src/llc.h b/src/llc.h index 94de16e..4883624 100644 --- a/src/llc.h +++ b/src/llc.h @@ -127,10 +127,10 @@ inline size_t gprs_llc_queue::size() const { - return this ? m_queue_size : 0; + return m_queue_size; } inline size_t gprs_llc_queue::octets() const { - return this ? m_queue_octets : 0; + return m_queue_octets; } -- To view, visit https://gerrit.osmocom.org/213 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I918a094e0dc59098a9eb00d152c9ae42d36b3a99 Gerrit-PatchSet: 4 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: lynxis lazus From gerrit-no-reply at lists.osmocom.org Mon Aug 29 13:51:54 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 13:51:54 +0000 Subject: [PATCH] osmo-iuh[master]: jenkins.sh: cosmetic: mark start of main build Message-ID: Review at https://gerrit.osmocom.org/775 jenkins.sh: cosmetic: mark start of main build Change-Id: I58ab958414eb9e9b0fd7e214103578e5b4aa6ff2 --- M contrib/jenkins.sh 1 file changed, 5 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/75/775/1 diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index 4b92861..3d45fe2 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -49,6 +49,11 @@ # the asn1c binary is used by the 'regen' target below build_dep asn1c aper-prefix +echo +echo +echo +echo " =============================== osmo-iuh ===============================" +echo cd "$base" # Build using the checked-in asn1 code autoreconf --install --force -- To view, visit https://gerrit.osmocom.org/775 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I58ab958414eb9e9b0fd7e214103578e5b4aa6ff2 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 29 13:56:23 2016 From: gerrit-no-reply at lists.osmocom.org (pravin) Date: Mon, 29 Aug 2016 13:56:23 +0000 Subject: [PATCH] osmo-pcu[master]: EGPRS: Add EPDAN CRBB Tree based decoding In-Reply-To: References: Message-ID: Hello Max, Neels Hofmeyr, arvind.sirsikar, Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/416 to look at the new patch set (#22). EGPRS: Add EPDAN CRBB Tree based decoding Implemented tree based algorithm to decode compressed bitmap in EPDAN as described in section 9.1.10 of 3GPP 44.060. This algorithm intends to improve the performance over existing method. New Regression test is added under bitcomp directory. Test case is added to validate decompressed result of the bitmap Present in EPDAN. Test is done for multiple bitmaps of varying length. Invalid inputs are also part of the test vector. Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce --- M src/Makefile.am M src/decoding.cpp A src/egprs_rlc_compression.cpp A src/egprs_rlc_compression.h M tests/Makefile.am A tests/bitcomp/BitcompTest.cpp A tests/bitcomp/BitcompTest.err A tests/bitcomp/BitcompTest.ok M tests/testsuite.at 9 files changed, 785 insertions(+), 15 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/16/416/22 diff --git a/src/Makefile.am b/src/Makefile.am index 9bdec2f..9b047e7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -62,7 +62,8 @@ rlc.cpp \ osmobts_sock.cpp \ gprs_codel.c \ - gprs_coding_scheme.cpp + gprs_coding_scheme.cpp \ + egprs_rlc_compression.cpp bin_PROGRAMS = \ osmo-pcu @@ -94,7 +95,8 @@ pcu_utils.h \ cxx_linuxlist.h \ gprs_codel.h \ - gprs_coding_scheme.h + gprs_coding_scheme.h \ + egprs_rlc_compression.h osmo_pcu_SOURCES = pcu_main.cpp diff --git a/src/decoding.cpp b/src/decoding.cpp index 7c00ff7..60ebc0d 100644 --- a/src/decoding.cpp +++ b/src/decoding.cpp @@ -20,6 +20,7 @@ #include #include #include +#include extern "C" { #include @@ -695,21 +696,17 @@ if (crbb_len > 0) { int old_len = bits->cur_bit; - struct bitvec crbb; - crbb.data = (uint8_t *)desc->CRBB; - crbb.data_len = sizeof(desc->CRBB); - crbb.cur_bit = desc->CRBB_LENGTH; - - rc = osmo_t4_decode(&crbb, desc->CRBB_STARTING_COLOR_CODE, - bits); - + LOGP(DRLCMACDL, LOGL_DEBUG, "Compress bitmap exist, " + "CRBB LEN =%d and Starting color code =%d", + desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE); + rc = decompress_crbb(desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE, + desc->CRBB, bits); if (rc < 0) { LOGP(DRLCMACUL, LOGL_NOTICE, - "Failed to decode CRBB: " - "length %d, data '%s'\n", - desc->CRBB_LENGTH, - osmo_hexdump(crbb.data, crbb.data_len)); + "Failed to decode CRBB: length %d, data '%s'\n", + desc->CRBB_LENGTH, osmo_hexdump( + desc->CRBB, (desc->CRBB_LENGTH + 7)/8)); /* We don't know the SSN offset for the URBB, * return what we have so far and assume the * bitmap has stopped here */ diff --git a/src/egprs_rlc_compression.cpp b/src/egprs_rlc_compression.cpp new file mode 100644 index 0000000..4a1f598 --- /dev/null +++ b/src/egprs_rlc_compression.cpp @@ -0,0 +1,337 @@ +/* egprs_rlc_compression.h +* Routines for EGPRS RLC bitmap compression handling +*/ +#include +#include +#include +#include +#include +#include +#include + +extern "C" { +#include +#include +#include +} + +extern void *tall_pcu_ctx; +extern const char *one_run_len_code_list[MAX_CDWDTBL_LEN]; +extern const char *zero_run_len_code_list[MAX_CDWDTBL_LEN]; + +egprs_compress *egprs_compress::s_instance = 0; + +/* Function to create tree node */ +Node *egprs_compress::create_tree_node(void *parent) +{ + Node *new_node; + + new_node = talloc_zero(parent, Node); + new_node->left = NULL; + new_node->right = NULL; + new_node->run_length = -1; + return new_node; +} + +/* Function to build the codeword tree + * \param root[in] Root of Ones or Zeros tree + * \param cdwd[in] Code word + */ +void egprs_compress::build_codeword(Node *root, const char *cdwd[]) +{ + Node *iter; + int len; + int i; + int idx; + + for (idx = 0; idx < MAX_CDWDTBL_LEN; idx++) { + len = strlen((const char *)cdwd[idx]); + iter = root; + for (i = 0; i < len; i++) { + if (cdwd[idx][i] == '0') { + if (!iter->left) + iter->left = create_tree_node(root); + iter = iter->left; + } else if (cdwd[idx][i] == '1') { + if (!iter->right) + iter->right = create_tree_node(root); + iter = iter->right; + } + } + if (iter) { + if (idx < 64) + (iter->run_length) = idx; + else + (iter->run_length) = (idx - 63) * 64; + } + } +} + +const char *one_run_len_code_list[MAX_CDWDTBL_LEN] = { + "00110101", + "000111", + "0111", + "1000", + "1011", + "1100", + "1110", + "1111", + "10011", + "10100", + "00111", + "01000", + "001000", + "000011", + "110100", + "110101", + "101010", + "101011", + "0100111", + "0001100", + "0001000", + "0010111", + "0000011", + "0000100", + "0101000", + "0101011", + "0010011", + "0100100", + "0011000", + "00000010", + "00000011", + "00011010", + "00011011", + "00010010", + "00010011", + "00010100", + "00010101", + "00010110", + "00010111", + "00101000", + "00101001", + "00101010", + "00101011", + "00101100", + "00101101", + "00000100", + "00000101", + "00001010", + "00001011", + "01010010", + "01010011", + "01010100", + "01010101", + "00100100", + "00100101", + "01011000", + "01011001", + "01011010", + "01011011", + "01001010", + "01001011", + "00110010", + "00110011", + "00110100", + "11011", + "10010", + "010111", + "0110111", + "00110110", + "00110111", + "01100100", + "01100101", + "01101000", + "01100111", + "011001100", + "011001101", + "011010010", + "011010011", + "011010100" +}; + +const char *zero_run_len_code_list[MAX_CDWDTBL_LEN] = { + "0000110111", + "10", + "11", + "010", + "011", + "0011", + "0010", + "00011", + "000101", + "000100", + "0000100", + "0000101", + "0000111", + "00000100", + "00000111", + "000011000", + "0000010111", + "0000011000", + "0000001000", + "00001100111", + "00001101000", + "00001101100", + "00000110111", + "00000101000", + "00000010111", + "00000011000", + "000011001010", + "000011001011", + "000011001100", + "000011001101", + "000001101000", + "000001101001", + "000001101010", + "000001101011", + "000011010010", + "000011010011", + "000011010100", + "000011010101", + "000011010110", + "000011010111", + "000001101100", + "000001101101", + "000011011010", + "000011011011", + "000001010100", + "000001010101", + "000001010110", + "000001010111", + "000001100100", + "000001100101", + "000001010010", + "000001010011", + "000000100100", + "000000110111", + "000000111000", + "000000100111", + "000000101000", + "000001011000", + "000001011001", + "000000101011", + "000000101100", + "000001011010", + "000001100110", + "000001100111", + "0000001111", + "000011001000", + "000011001001", + "000001011011", + "000000110011", + "000000110100", + "000000110101", + "0000001101100", + "0000001101101", + "0000001001010", + "0000001001011", + "0000001001100", + "0000001001101", + "0000001110010", + "0000001110011" +}; + +/* search_runlen function will return the runlength for the codeword + * \param root[in] Root of Ones or Zeros tree + * \param bmbuf[in] Recevied compressed bitmap buf + * \param bit_pos[in] The start bit pos to read codeword + * \param len_codewd[in] Length of code word + * \param rlen[out] Run length value + */ +static int search_runlen( + Node *root, + const uint8_t *bmbuf, + uint8_t bit_pos, + uint8_t *len_codewd, + uint16_t *rlen) +{ + Node *iter; + uint8_t dir; + + iter = root; + *len_codewd = 0; + + while (iter->run_length == -1) { + if ((!iter->left) && (!iter->right)) + return -1; + /* get the bit value at the bitpos and put it in right most of dir */ + dir = ((bmbuf[BITS_TO_BYTES(bit_pos)-1] + >>(7-(MOD8(bit_pos)))) & 0x01); + (bit_pos)++; + (*len_codewd)++; + if (((dir&0x01) == 0) && (iter->left != NULL)) + iter = iter->left; + else if (((dir&0x01) == 1) && (iter->right != NULL)) + iter = iter->right; + else + return -1; + } + LOGP(DRLCMACUL, LOGL_DEBUG, "Run_length = %d\n", iter->run_length); + (*rlen) = (iter->run_length); + return 1; +} + +/* Function to decompress crbb + * \param compress_bmap_len[in] Compressed bitmap length + * \param clr_code_bit[in] Color code 1 for Ones runlength 0 for Zero runlength + * \param orig_crbb_buf[in] Received block crbb bitmap + * \param dest[out] Uncompressed bitvector + */ +int decompress_crbb( + int8_t compress_bmap_len, + uint8_t clr_code_bit, + const uint8_t *orig_crbb_buf, + bitvec *dest) +{ + + uint8_t bit_pos = 0; + uint8_t data = 0x0; + node *list = NULL; + uint8_t nbits = 0; /* number of bits of codeword */ + uint16_t run_length = 0; + uint16_t cbmaplen = 0; /* compressed bitmap part after decompression */ + unsigned wp = dest->cur_bit; + int rc = 0; + egprs_compress *compress = egprs_compress::instance(); + + while (compress_bmap_len > 0) { + if (clr_code_bit == 1) { + data = 0xff; + list = compress->ones_list; + } else { + data = 0x00; + list = compress->zeros_list; + } + rc = search_runlen(list, orig_crbb_buf, + bit_pos, &nbits, &run_length); + if (rc == -1) + return -1; + /* If run length > 64, need makeup and terminating code */ + if (run_length < 64) + clr_code_bit ? clr_code_bit = 0 : clr_code_bit = 1; + cbmaplen = cbmaplen + run_length; + /* put run length of Ones in uncompressed bitmap */ + while (run_length != 0) { + if (run_length > 8) { + bitvec_write_field(dest, wp, data, 8); + run_length = run_length - 8; + } else { + bitvec_write_field(dest, wp, data, run_length); + run_length = 0; + } + } + bit_pos = bit_pos + nbits; + compress_bmap_len = compress_bmap_len - nbits; + } + return 0; +} + +/* init function to build codeword */ +int egprs_compress::decode_tree_init() +{ + ones_list = create_tree_node(tall_pcu_ctx); + zeros_list = create_tree_node(tall_pcu_ctx); + build_codeword(ones_list, one_run_len_code_list); + build_codeword(zeros_list, zero_run_len_code_list); + return 0; +} diff --git a/src/egprs_rlc_compression.h b/src/egprs_rlc_compression.h new file mode 100644 index 0000000..2ec00da --- /dev/null +++ b/src/egprs_rlc_compression.h @@ -0,0 +1,49 @@ +/* egprs_rlc_compression.h + * Routines for EGPRS RLC bitmap compression handling + */ + +#pragma once + +#define MAX_CDWDTBL_LEN 79 /* total number of codewords */ +#define BITS_TO_BYTES(X) ((X ? (X/8):0)+1) +#define MOD8(X) (((X)+8) & (0x07)) + +typedef struct node { + struct node *left; + struct node *right; + int run_length; +} Node; + +int decompress_crbb(int8_t compress_bmap_len, uint8_t clr_code_bit, + const uint8_t *orig_buf, bitvec *dest); + +/* Creating singleton class*/ +class egprs_compress +{ +public: + Node *ones_list; + Node *zeros_list; + + int decode_tree_init(void); + + static egprs_compress *instance() + { + if (!s_instance) + s_instance = new egprs_compress; + + return s_instance; + } +private: + static egprs_compress *s_instance; + + egprs_compress() + { + if (decode_tree_init() < 0) { + fprintf(stderr, "Error initializing tree\n"); + exit(1); + } + } + Node *create_tree_node(void *); + void build_codeword(Node *root, const char *cdwd[]); + ~egprs_compress(); +}; diff --git a/tests/Makefile.am b/tests/Makefile.am index 2a3415e..a24f4ea 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,7 +1,7 @@ AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGB_CFLAGS) $(LIBOSMOGSM_CFLAGS) -I$(top_srcdir)/src/ AM_LDFLAGS = -lrt -check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest llc/LlcTest codel/codel_test edge/EdgeTest +check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest llc/LlcTest codel/codel_test edge/EdgeTest bitcomp/BitcompTest noinst_PROGRAMS = emu/pcu_emu rlcmac_RLCMACTest_SOURCES = rlcmac/RLCMACTest.cpp @@ -23,6 +23,11 @@ $(top_builddir)/src/libgprs.la \ $(LIBOSMOGB_LIBS) \ $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(COMMON_LA) + +bitcomp_BitcompTest_SOURCES = bitcomp/BitcompTest.cpp ../src/egprs_rlc_compression.cpp +bitcomp_BitcompTest_LDADD = \ $(LIBOSMOCORE_LIBS) \ $(COMMON_LA) @@ -108,6 +113,7 @@ rlcmac/RLCMACTest.ok rlcmac/RLCMACTest.err \ alloc/AllocTest.ok alloc/AllocTest.err \ tbf/TbfTest.ok tbf/TbfTest.err \ + bitcomp/BitcompTest.ok bitcomp/BitcompTest.err \ types/TypesTest.ok types/TypesTest.err \ ms/MsTest.ok ms/MsTest.err \ llc/LlcTest.ok llc/LlcTest.err \ diff --git a/tests/bitcomp/BitcompTest.cpp b/tests/bitcomp/BitcompTest.cpp new file mode 100644 index 0000000..3092872 --- /dev/null +++ b/tests/bitcomp/BitcompTest.cpp @@ -0,0 +1,237 @@ +#include +#include + +#include "rlc.h" +#include "gprs_debug.h" +#include +#include "egprs_rlc_compression.h" + +extern "C" { +#include +#include +#include +#include +} + +#define NEW 1 +#define MASK(n) (0xFF << (8-n)) +#define MAX_CRBB_LEN 23 +#define MAX_URBB_LEN 40 + +void *tall_pcu_ctx; + +struct test_data { + int8_t crbb_len; + uint8_t cc; + uint8_t crbb_data[MAX_CRBB_LEN]; /* compressed data */ + uint8_t ucmp_data[MAX_URBB_LEN]; /* uncompressed data */ + int ucmp_len; + int verify; +} test[] = { + { .crbb_len = 67, .cc = 1, + .crbb_data = { + 0x02, 0x0c, 0xa0, 0x30, 0xcb, 0x1a, 0x0c, 0xe3, 0x6c + }, + .ucmp_data = { + 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x01, 0xff, 0xff, + 0xff, 0xf8, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, + 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xdb + }, + .ucmp_len = 194, .verify = 1 + }, + { .crbb_len = 40, .cc = 1, + .crbb_data = { + 0x53, 0x06, 0xc5, 0x40, 0x6d + }, + .ucmp_data = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x03 + }, + .ucmp_len = 182, .verify = 1 + }, + { .crbb_len = 8, .cc = 1, + .crbb_data = {0x02}, + .ucmp_data = {0xff, 0xff, 0xff, 0xf8}, + .ucmp_len = 29, .verify = 1 + }, + { .crbb_len = 103, .cc = 1, + .crbb_data = { + 0x02, 0x0c, 0xe0, 0x41, 0xa0, 0x0c, 0x36, 0x0d, 0x03, + 0x71, 0xb0, 0x6e, 0x24 + }, + .ucmp_data = { + 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xf8, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, + 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff + }, + .ucmp_len = 288, .verify = 1 + }, + /* Test vector from libosmocore test */ + { .crbb_len = 35, .cc = 0, + .crbb_data = {0xde, 0x88, 0x75, 0x65, 0x80}, + .ucmp_data = {0x37, 0x47, 0x81, 0xf0}, + .ucmp_len = 28, .verify = 1 + }, + { .crbb_len = 18, .cc = 1, + .crbb_data = {0xdd, 0x41, 0x00}, + .ucmp_data = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00 + }, + .ucmp_len = 90, .verify = 1 + }, + /*Invalid inputs*/ + { .crbb_len = 18, .cc = 1, + .crbb_data = {0x1E, 0x70, 0xc0}, + .ucmp_data = {0x0}, + .ucmp_len = 0, .verify = 0 + }, + { .crbb_len = 14, .cc = 1, + .crbb_data = {0x00, 0x1E, 0x7c}, + .ucmp_data = {0x0}, + .ucmp_len = 0, .verify = 0 + }, + { .crbb_len = 24, .cc = 0, + .crbb_data = {0x00, 0x00, 0x00}, + .ucmp_data = {0x0}, + .ucmp_len = 0, .verify = 0 + } + }; + +static const struct log_info_cat default_categories[] = { + {"DCSN1", "\033[1;31m", "Concrete Syntax Notation One (CSN1)", LOGL_INFO, 0}, + {"DL1IF", "\033[1;32m", "GPRS PCU L1 interface (L1IF)", LOGL_DEBUG, 1}, + {"DRLCMAC", "\033[0;33m", "GPRS RLC/MAC layer (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACDATA", "\033[0;33m", "GPRS RLC/MAC layer Data (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACDL", "\033[1;33m", "GPRS RLC/MAC layer Downlink (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACUL", "\033[1;36m", "GPRS RLC/MAC layer Uplink (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACSCHED", "\033[0;36m", "GPRS RLC/MAC layer Scheduling (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACMEAS", "\033[1;31m", "GPRS RLC/MAC layer Measurements (RLCMAC)", LOGL_INFO, 1}, + {"DNS", "\033[1;34m", "GPRS Network Service Protocol (NS)", LOGL_INFO, 1}, + {"DBSSGP", "\033[1;34m", "GPRS BSS Gateway Protocol (BSSGP)", LOGL_INFO, 1}, + {"DPCU", "\033[1;35m", "GPRS Packet Control Unit (PCU)", LOGL_NOTICE, 1}, +}; + +static int filter_fn(const struct log_context *ctx, + struct log_target *tar) +{ + return 1; +} + +/* To verify the result with expected result */ +int check_result(bitvec bits, uint8_t *exp_data, int exp_len) +{ + if (bits.cur_bit != exp_len) + return 0; + size_t n = (exp_len / 8); + int rem = (exp_len % 8); + + if (memcmp(exp_data, bits.data, n) == 0) { + if (rem == 0) + return 1; + if ((bits.data[n] & MASK(rem)) == ((*(exp_data + n)) & MASK(rem))) + return 1; + else + return 0; + } else + return 0; +} + +/* To test decoding of compressed bitmap by Tree based method + * and to verify the result with expected result + * for invalid input verfication is suppressed + */ +static void test_EPDAN_decode_tree(void) +{ + bitvec dest; + int init_flag = 1; + int itr; + int rc; + uint8_t bits_data[RLC_EGPRS_MAX_WS/8]; + + printf("=== start %s ===\n", __func__); + + for (itr = 0 ; itr < (sizeof(test) / sizeof(test_data)) ; itr++) { + dest.data = bits_data; + dest.data_len = sizeof(bits_data); + dest.cur_bit = 0; + memset(dest.data, 0, sizeof(bits_data)); + LOGP(DRLCMACDL, LOGL_DEBUG, "\nTest:%d\nTree based decoding:" + "\nuncompressed data = %s\nlen = %d\n", itr + 1, + osmo_hexdump(test[itr].crbb_data, + (test[itr].crbb_len + 7)/8), test[itr].crbb_len + ); + rc = decompress_crbb(test[itr].crbb_len, test[itr].cc, + test[itr].crbb_data, &dest + ); + if (rc < 0) { + LOGP(DRLCMACUL, LOGL_NOTICE, + "\nFailed to decode CRBB: length %d, data %s", + test[itr].crbb_len, osmo_hexdump( + test[itr].crbb_data, (test[itr].crbb_len + 7)/8)); + } + if (init_flag) + init_flag = 0; + if (test[itr].verify) { + if (check_result(dest, test[itr].ucmp_data, + test[itr].ucmp_len) == 0) { + LOGP(DRLCMACDL, LOGL_DEBUG, "\nTree based decoding" + ":Error\nexpected data = %s\nexpected" + " len = %d\ndecoded data = %s\n" + "decoded len = %d\n", + osmo_hexdump(test[itr].ucmp_data, + (test[itr].ucmp_len + 7)/8), + test[itr].ucmp_len, osmo_hexdump(dest.data, + (dest.cur_bit + 7)/8), dest.cur_bit + ); + OSMO_ASSERT(0); + } + } + LOGP(DRLCMACDL, LOGL_DEBUG, "\nexpected data = %s\nexpected len = %d" + "\ndecoded data = %s\ndecoded len = %d\n", + osmo_hexdump(test[itr].ucmp_data, + (test[itr].ucmp_len + 7)/8), + test[itr].ucmp_len, osmo_hexdump(dest.data, + (dest.cur_bit + 7)/8), dest.cur_bit + ); + } + + printf("=== end %s ===\n", __func__); +} + +const struct log_info debug_log_info = { + filter_fn, + (struct log_info_cat *)default_categories, + ARRAY_SIZE(default_categories), +}; + +int main(int argc, char **argv) +{ + osmo_init_logging(&debug_log_info); + log_set_use_color(osmo_stderr_target, 0); + log_set_print_filename(osmo_stderr_target, 0); + + tall_pcu_ctx = talloc_named_const(NULL, 1, "moiji-mobile bitcompTest context"); + if (!tall_pcu_ctx) + abort(); + + test_EPDAN_decode_tree(); + + if (getenv("TALLOC_REPORT_FULL")) + talloc_report_full(tall_pcu_ctx, stderr); + talloc_free(tall_pcu_ctx); + return EXIT_SUCCESS; +} + +/* + * stubs that should not be reached + */ +extern "C" { +void l1if_pdch_req() { abort(); } +void l1if_connect_pdch() { abort(); } +void l1if_close_pdch() { abort(); } +void l1if_open_pdch() { abort(); } +} + diff --git a/tests/bitcomp/BitcompTest.err b/tests/bitcomp/BitcompTest.err new file mode 100644 index 0000000..7481d72 --- /dev/null +++ b/tests/bitcomp/BitcompTest.err @@ -0,0 +1,132 @@ + +Test:1 +Tree based decoding: +uncompressed data = 02 0c a0 30 cb 1a 0c e3 6c +len = 67 +Run_length = 29 +Run_length = 26 +Run_length = 30 +Run_length = 27 +Run_length = 31 +Run_length = 19 +Run_length = 32 + +expected data = ff ff ff f8 00 00 01 ff ff ff f8 00 00 00 ff ff ff fe 00 00 3f ff ff ff db +expected len = 194 +decoded data = ff ff ff f8 00 00 01 ff ff ff f8 00 00 00 ff ff ff fe 00 00 3f ff ff ff db +decoded len = 194 + +Test:2 +Tree based decoding: +uncompressed data = 53 06 c5 40 6d +len = 40 +Run_length = 50 +Run_length = 40 +Run_length = 51 +Run_length = 41 + +expected data = ff ff ff ff ff ff c0 00 00 00 00 3f ff ff ff ff ff f8 00 00 00 00 03 +expected len = 182 +decoded data = ff ff ff ff ff ff c0 00 00 00 00 3f ff ff ff ff ff f8 00 00 00 00 03 +decoded len = 182 + +Test:3 +Tree based decoding: +uncompressed data = 02 +len = 8 +Run_length = 29 + +expected data = ff ff ff f8 +expected len = 29 +decoded data = ff ff ff f8 +decoded len = 29 + +Test:4 +Tree based decoding: +uncompressed data = 02 0c e0 41 a0 0c 36 0d 03 71 b0 6e 24 +len = 103 +Run_length = 29 +Run_length = 19 +Run_length = 29 +Run_length = 20 +Run_length = 30 +Run_length = 21 +Run_length = 31 +Run_length = 22 +Run_length = 32 +Run_length = 22 +Run_length = 33 + +expected data = ff ff ff f8 00 00 ff ff ff f8 00 00 7f ff ff fe 00 00 0f ff ff ff e0 00 00 7f ff ff ff 80 00 01 ff ff ff ff +expected len = 288 +decoded data = ff ff ff f8 00 00 ff ff ff f8 00 00 7f ff ff fe 00 00 0f ff ff ff e0 00 00 7f ff ff ff 80 00 01 ff ff ff ff +decoded len = 288 + +Test:5 +Tree based decoding: +uncompressed data = de 88 75 65 80 +len = 35 +Run_length = 2 +Run_length = 2 +Run_length = 1 +Run_length = 3 +Run_length = 1 +Run_length = 1 +Run_length = 3 +Run_length = 4 +Run_length = 6 +Run_length = 5 + +expected data = 37 47 81 f0 +expected len = 28 +decoded data = 37 47 81 f0 +decoded len = 28 + +Test:6 +Tree based decoding: +uncompressed data = dd 41 00 +len = 18 +Run_length = 64 +Run_length = 16 +Run_length = 10 + +expected data = ff ff ff ff ff ff ff ff ff ff 00 00 +expected len = 90 +decoded data = ff ff ff ff ff ff ff ff ff ff 00 00 +decoded len = 90 + +Test:7 +Tree based decoding: +uncompressed data = 1e 70 c0 +len = 18 +Run_length = 1 +Run_length = 1 +Run_length = 2 +Run_length = 15 + +expected data = +expected len = 0 +decoded data = +decoded len = 19 + +Test:8 +Tree based decoding: +uncompressed data = 00 1e +len = 14 + +Failed to decode CRBB: length 14, data 00 1e +expected data = +expected len = 0 +decoded data = +decoded len = 0 + +Test:9 +Tree based decoding: +uncompressed data = 00 00 00 +len = 24 + +Failed to decode CRBB: length 24, data 00 00 00 +expected data = +expected len = 0 +decoded data = +decoded len = 0 diff --git a/tests/bitcomp/BitcompTest.ok b/tests/bitcomp/BitcompTest.ok new file mode 100644 index 0000000..f7720fc --- /dev/null +++ b/tests/bitcomp/BitcompTest.ok @@ -0,0 +1,2 @@ +=== start test_EPDAN_decode_tree === +=== end test_EPDAN_decode_tree === diff --git a/tests/testsuite.at b/tests/testsuite.at index 1049b31..3ab39cc 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -23,6 +23,14 @@ AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/tbf/TbfTest], [0], [expout], [experr]) AT_CLEANUP + +AT_SETUP([bitcomp]) +AT_KEYWORDS([bitcomp]) +cat $abs_srcdir/bitcomp/BitcompTest.ok > expout +cat $abs_srcdir/bitcomp/BitcompTest.err > experr +AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/bitcomp/BitcompTest], [0], [expout], [experr]) +AT_CLEANUP + AT_SETUP([edge]) AT_KEYWORDS([edge]) cat $abs_srcdir/edge/EdgeTest.ok > expout -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 22 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-Reviewer: pravin From gerrit-no-reply at lists.osmocom.org Mon Aug 29 13:56:28 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 13:56:28 +0000 Subject: [PATCH] osmo-iuh[master]: jenkins.sh: cosmetic: mark start of main build In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/775 to look at the new patch set (#2). jenkins.sh: cosmetic: mark start of main build Add function 'marker' so we don't repeat the five echos, use in build_dep and before main build. Change-Id: I58ab958414eb9e9b0fd7e214103578e5b4aa6ff2 --- M contrib/jenkins.sh 1 file changed, 9 insertions(+), 4 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/75/775/2 diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index 4b92861..c24bec2 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -9,16 +9,20 @@ mkdir "$deps" || true rm -rf "$inst" -build_dep() { - project="$1" - branch="$2" +marker() { set +x echo echo echo - echo " =============================== $project ===============================" + echo " =============================== $@ ===============================" echo set -x +} + +build_dep() { + project="$1" + branch="$2" + marker $project if [ -z "$project" ]; then echo "internal failure" exit 1 @@ -49,6 +53,7 @@ # the asn1c binary is used by the 'regen' target below build_dep asn1c aper-prefix +marker osmo-iuh cd "$base" # Build using the checked-in asn1 code autoreconf --install --force -- To view, visit https://gerrit.osmocom.org/775 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I58ab958414eb9e9b0fd7e214103578e5b4aa6ff2 Gerrit-PatchSet: 2 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 29 13:59:36 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 13:59:36 +0000 Subject: osmo-iuh[master]: jenkins.sh: cosmetic: mark start of main build In-Reply-To: References: Message-ID: Patch Set 2: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/775 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I58ab958414eb9e9b0fd7e214103578e5b4aa6ff2 Gerrit-PatchSet: 2 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 29 13:59:37 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 13:59:37 +0000 Subject: [MERGED] osmo-iuh[master]: jenkins.sh: cosmetic: mark start of main build In-Reply-To: References: Message-ID: Neels Hofmeyr has submitted this change and it was merged. Change subject: jenkins.sh: cosmetic: mark start of main build ...................................................................... jenkins.sh: cosmetic: mark start of main build Add function 'marker' so we don't repeat the five echos, use in build_dep and before main build. Change-Id: I58ab958414eb9e9b0fd7e214103578e5b4aa6ff2 --- M contrib/jenkins.sh 1 file changed, 9 insertions(+), 4 deletions(-) Approvals: Neels Hofmeyr: Looks good to me, approved Jenkins Builder: Verified diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index 4b92861..c24bec2 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -9,16 +9,20 @@ mkdir "$deps" || true rm -rf "$inst" -build_dep() { - project="$1" - branch="$2" +marker() { set +x echo echo echo - echo " =============================== $project ===============================" + echo " =============================== $@ ===============================" echo set -x +} + +build_dep() { + project="$1" + branch="$2" + marker $project if [ -z "$project" ]; then echo "internal failure" exit 1 @@ -49,6 +53,7 @@ # the asn1c binary is used by the 'regen' target below build_dep asn1c aper-prefix +marker osmo-iuh cd "$base" # Build using the checked-in asn1 code autoreconf --install --force -- To view, visit https://gerrit.osmocom.org/775 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I58ab958414eb9e9b0fd7e214103578e5b4aa6ff2 Gerrit-PatchSet: 2 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 29 14:00:30 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 14:00:30 +0000 Subject: [PATCH] osmo-iuh[master]: jenkins.sh: don't build twice Message-ID: Review at https://gerrit.osmocom.org/776 jenkins.sh: don't build twice Instead of building the same .c files twice, rather verify that the 'make regen' target produces identical .c files as are checked in. Change-Id: I18e7677d8596f61b883e9db57b4bdd2a5c154ec3 --- M contrib/jenkins.sh 1 file changed, 11 insertions(+), 9 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/76/776/1 diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index c24bec2..a9a9bbb 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -55,19 +55,21 @@ marker osmo-iuh cd "$base" -# Build using the checked-in asn1 code -autoreconf --install --force -./configure -$MAKE $PARALLEL_MAKE -LD_LIBRARY_PATH="$inst/lib" $MAKE check -# distcheck is broken -#LD_LIBRARY_PATH=$PWD/deps/install/lib $MAKE distcheck -make clean -# Build with regenerated asn1 code autoreconf --install --force ./configure + +# Verify that checked-in asn1 code is identical to regenerated asn1 code PATH="$inst/bin:$PATH" $MAKE $PARALLEL_MAKE -C src regen +if ! git diff-files --quiet --ignore-submodules -- ; then + echo "ERROR: 'make -C src regen' does not match committed asn1 code" + echo + git diff + echo + echo "ERROR: 'make -C src regen' does not match committed asn1 code" + exit 1 +fi + $MAKE $PARALLEL_MAKE LD_LIBRARY_PATH="$inst/lib" $MAKE check # distcheck is broken -- To view, visit https://gerrit.osmocom.org/776 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I18e7677d8596f61b883e9db57b4bdd2a5c154ec3 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 29 14:01:08 2016 From: gerrit-no-reply at lists.osmocom.org (pravin) Date: Mon, 29 Aug 2016 14:01:08 +0000 Subject: osmo-pcu[master]: EGPRS: Add EPDAN CRBB Tree based decoding In-Reply-To: References: Message-ID: Patch Set 22: (9 comments) https://gerrit.osmocom.org/#/c/416/21//COMMIT_MSG Commit Message: Line 7: EGPRS: Add EPDAN CRBB Tree based decoding > "EGPRS: Add EPDAN CRBB Tree based decoding" would be more better. Done https://gerrit.osmocom.org/#/c/416/21/src/egprs_rlc_compression.cpp File src/egprs_rlc_compression.cpp: Line 1: /* egprs_rlc_compression.h > Logs are missing from whole file. Can we have a debug logs at least at debu Done https://gerrit.osmocom.org/#/c/416/21/src/egprs_rlc_compression.h File src/egprs_rlc_compression.h: Line 17: int decompress_crbb(int8_t compress_bmap_len, uint8_t clr_code_bit, > can we move it to .cpp/.c file? Done Line 18: const uint8_t *orig_buf, bitvec *dest); > can we move it to .cpp/.c file? Done Line 26: > Can you use scope as private here? Done Line 38: > Keep Public first and then private. I have noticed in many .h file . Done https://gerrit.osmocom.org/#/c/416/21/tests/bitcomp/BitcompTest.cpp File tests/bitcomp/BitcompTest.cpp: Line 26: uint8_t crbb_data[MAX_CRBB_LEN]; /* compressed data */ > check for extra space Done Line 216: tall_pcu_ctx = talloc_named_const(NULL, 1, "moiji-mobile bitcompTest context"); > change TbfTest context Done Line 226: } > can you leave a empty line here? Done -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 22 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-Reviewer: pravin Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Mon Aug 29 14:03:30 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 14:03:30 +0000 Subject: [PATCH] osmo-iuh[master]: Not for merge -- jenkins test: dirty asn.1 files after regen Message-ID: Review at https://gerrit.osmocom.org/777 Not for merge -- jenkins test: dirty asn.1 files after regen Change-Id: Ib2f2495b62889410982ed5103d46fc61bc57d92f --- M src/hnbap/IE.c 1 file changed, 1 insertion(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/77/777/1 diff --git a/src/hnbap/IE.c b/src/hnbap/IE.c index 5e6763a..648c936 100644 --- a/src/hnbap/IE.c +++ b/src/hnbap/IE.c @@ -1,3 +1,4 @@ +dirty /* * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) * From ASN.1 module "HNBAP-PDU" -- To view, visit https://gerrit.osmocom.org/777 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ib2f2495b62889410982ed5103d46fc61bc57d92f Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 29 14:03:31 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 14:03:31 +0000 Subject: [PATCH] osmo-iuh[master]: Not for merge -- testing: jenkins.sh: don't build twice Message-ID: Review at https://gerrit.osmocom.org/778 Not for merge -- testing: jenkins.sh: don't build twice This is the same commit as https://gerrit.osmocom.org/776 This here is just testing whether it produces expected results when the regenerated asn.1 files differ from the checked-in ones. Change-Id: I7da4b62358674803a275e25233891c51ab020c6a --- M contrib/jenkins.sh 1 file changed, 11 insertions(+), 9 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/78/778/1 diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index c24bec2..a9a9bbb 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -55,19 +55,21 @@ marker osmo-iuh cd "$base" -# Build using the checked-in asn1 code -autoreconf --install --force -./configure -$MAKE $PARALLEL_MAKE -LD_LIBRARY_PATH="$inst/lib" $MAKE check -# distcheck is broken -#LD_LIBRARY_PATH=$PWD/deps/install/lib $MAKE distcheck -make clean -# Build with regenerated asn1 code autoreconf --install --force ./configure + +# Verify that checked-in asn1 code is identical to regenerated asn1 code PATH="$inst/bin:$PATH" $MAKE $PARALLEL_MAKE -C src regen +if ! git diff-files --quiet --ignore-submodules -- ; then + echo "ERROR: 'make -C src regen' does not match committed asn1 code" + echo + git diff + echo + echo "ERROR: 'make -C src regen' does not match committed asn1 code" + exit 1 +fi + $MAKE $PARALLEL_MAKE LD_LIBRARY_PATH="$inst/lib" $MAKE check # distcheck is broken -- To view, visit https://gerrit.osmocom.org/778 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I7da4b62358674803a275e25233891c51ab020c6a Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 29 14:13:13 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Mon, 29 Aug 2016 14:13:13 +0000 Subject: osmo-pcu[master]: EGPRS: Add EPDAN CRBB Tree based decoding In-Reply-To: References: Message-ID: Patch Set 22: Code-Review+1 -- To view, visit https://gerrit.osmocom.org/416 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce Gerrit-PatchSet: 22 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: pravin Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Max Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-Reviewer: pravin Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 29 14:26:43 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 14:26:43 +0000 Subject: [ABANDON] osmo-iuh[master]: Not for merge -- testing: jenkins.sh: don't build twice In-Reply-To: References: Message-ID: Neels Hofmeyr has abandoned this change. Change subject: Not for merge -- testing: jenkins.sh: don't build twice ...................................................................... Abandoned -- To view, visit https://gerrit.osmocom.org/778 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: abandon Gerrit-Change-Id: I7da4b62358674803a275e25233891c51ab020c6a Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 29 14:39:02 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 14:39:02 +0000 Subject: [PATCH] osmo-iuh[master]: jenkins.sh: don't build twice In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/776 to look at the new patch set (#2). jenkins.sh: don't build twice Instead of building the same .c files twice, rather verify that the 'make regen' target produces identical .c files as are checked in. Change-Id: I18e7677d8596f61b883e9db57b4bdd2a5c154ec3 --- M contrib/jenkins.sh 1 file changed, 13 insertions(+), 9 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/76/776/2 diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index c24bec2..793138d 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -55,19 +55,23 @@ marker osmo-iuh cd "$base" -# Build using the checked-in asn1 code -autoreconf --install --force -./configure -$MAKE $PARALLEL_MAKE -LD_LIBRARY_PATH="$inst/lib" $MAKE check -# distcheck is broken -#LD_LIBRARY_PATH=$PWD/deps/install/lib $MAKE distcheck -make clean -# Build with regenerated asn1 code autoreconf --install --force ./configure + +# Verify that checked-in asn1 code is identical to regenerated asn1 code PATH="$inst/bin:$PATH" $MAKE $PARALLEL_MAKE -C src regen +git diff | cat +git diff-files +git diff-files --quiet +echo $? +if ! git diff-files --quiet --ignore-submodules -- ; then + echo "ERROR: 'make -C src regen' does not match committed asn1 code" + git diff | cat + echo "ERROR: 'make -C src regen' does not match committed asn1 code" + exit 1 +fi + $MAKE $PARALLEL_MAKE LD_LIBRARY_PATH="$inst/lib" $MAKE check # distcheck is broken -- To view, visit https://gerrit.osmocom.org/776 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I18e7677d8596f61b883e9db57b4bdd2a5c154ec3 Gerrit-PatchSet: 2 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 29 14:39:24 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 14:39:24 +0000 Subject: osmo-iuh[master]: jenkins.sh: don't build twice In-Reply-To: References: Message-ID: Patch Set 2: > Uploaded patch set 2. (please ignore, testing) -- To view, visit https://gerrit.osmocom.org/776 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I18e7677d8596f61b883e9db57b4bdd2a5c154ec3 Gerrit-PatchSet: 2 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 29 14:43:45 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 14:43:45 +0000 Subject: [PATCH] osmo-iuh[master]: jenkins.sh: don't build twice In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/776 to look at the new patch set (#3). jenkins.sh: don't build twice Instead of building the same .c files twice, rather verify that the 'make regen' target produces identical .c files as are checked in. Change-Id: I18e7677d8596f61b883e9db57b4bdd2a5c154ec3 --- M contrib/jenkins.sh 1 file changed, 10 insertions(+), 9 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/76/776/3 diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index c24bec2..e59f54a 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -55,19 +55,20 @@ marker osmo-iuh cd "$base" -# Build using the checked-in asn1 code -autoreconf --install --force -./configure -$MAKE $PARALLEL_MAKE -LD_LIBRARY_PATH="$inst/lib" $MAKE check -# distcheck is broken -#LD_LIBRARY_PATH=$PWD/deps/install/lib $MAKE distcheck -make clean -# Build with regenerated asn1 code autoreconf --install --force ./configure + +# Verify that checked-in asn1 code is identical to regenerated asn1 code PATH="$inst/bin:$PATH" $MAKE $PARALLEL_MAKE -C src regen + +if ! git diff-files --quiet ; then + echo "ERROR: 'make -C src regen' does not match committed asn1 code" + git diff | cat + echo "ERROR: 'make -C src regen' does not match committed asn1 code" + exit 1 +fi + $MAKE $PARALLEL_MAKE LD_LIBRARY_PATH="$inst/lib" $MAKE check # distcheck is broken -- To view, visit https://gerrit.osmocom.org/776 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I18e7677d8596f61b883e9db57b4bdd2a5c154ec3 Gerrit-PatchSet: 3 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 29 14:43:45 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 14:43:45 +0000 Subject: [PATCH] osmo-iuh[master]: Not for merge -- jenkins test: dirty asn.1 files after regen In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/777 to look at the new patch set (#2). Not for merge -- jenkins test: dirty asn.1 files after regen Change-Id: Ib2f2495b62889410982ed5103d46fc61bc57d92f --- M src/hnbap/IE.c 1 file changed, 1 insertion(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/77/777/2 diff --git a/src/hnbap/IE.c b/src/hnbap/IE.c index 5e6763a..8b18eac 100644 --- a/src/hnbap/IE.c +++ b/src/hnbap/IE.c @@ -1,4 +1,5 @@ /* +dirty * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) * From ASN.1 module "HNBAP-PDU" * found in "../../asn1/hnbap/HNBAP-PDU.asn" -- To view, visit https://gerrit.osmocom.org/777 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ib2f2495b62889410982ed5103d46fc61bc57d92f Gerrit-PatchSet: 2 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 29 14:47:35 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 14:47:35 +0000 Subject: [PATCH] osmo-iuh[master]: jenkins.sh: don't build twice In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/776 to look at the new patch set (#4). jenkins.sh: don't build twice Instead of building the same .c files twice, rather verify that the 'make regen' target produces identical .c files as are checked in. Change-Id: I18e7677d8596f61b883e9db57b4bdd2a5c154ec3 --- M contrib/jenkins.sh 1 file changed, 13 insertions(+), 9 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/76/776/4 diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index c24bec2..d3dd5c7 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -55,19 +55,23 @@ marker osmo-iuh cd "$base" -# Build using the checked-in asn1 code -autoreconf --install --force -./configure -$MAKE $PARALLEL_MAKE -LD_LIBRARY_PATH="$inst/lib" $MAKE check -# distcheck is broken -#LD_LIBRARY_PATH=$PWD/deps/install/lib $MAKE distcheck -make clean -# Build with regenerated asn1 code autoreconf --install --force ./configure + +# Verify that checked-in asn1 code is identical to regenerated asn1 code PATH="$inst/bin:$PATH" $MAKE $PARALLEL_MAKE -C src regen + +git diff-files --quiet +echo $? + +git diff | cat + +if ! git diff-files --quiet ; then + echo "ERROR: 'make -C src regen' does not match committed asn1 code" + exit 1 +fi + $MAKE $PARALLEL_MAKE LD_LIBRARY_PATH="$inst/lib" $MAKE check # distcheck is broken -- To view, visit https://gerrit.osmocom.org/776 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I18e7677d8596f61b883e9db57b4bdd2a5c154ec3 Gerrit-PatchSet: 4 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 29 14:51:16 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 14:51:16 +0000 Subject: [PATCH] osmo-iuh[master]: jenkins.sh: don't build twice In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/776 to look at the new patch set (#5). jenkins.sh: don't build twice Instead of building the same .c files twice, rather verify that the 'make regen' target produces identical .c files as are checked in. Change-Id: I18e7677d8596f61b883e9db57b4bdd2a5c154ec3 --- M contrib/jenkins.sh 1 file changed, 12 insertions(+), 9 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/76/776/5 diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index c24bec2..86c0297 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -55,19 +55,22 @@ marker osmo-iuh cd "$base" -# Build using the checked-in asn1 code -autoreconf --install --force -./configure -$MAKE $PARALLEL_MAKE -LD_LIBRARY_PATH="$inst/lib" $MAKE check -# distcheck is broken -#LD_LIBRARY_PATH=$PWD/deps/install/lib $MAKE distcheck -make clean -# Build with regenerated asn1 code autoreconf --install --force ./configure + +# Verify that checked-in asn1 code is identical to regenerated asn1 code PATH="$inst/bin:$PATH" $MAKE $PARALLEL_MAKE -C src regen + +git diff-files + +git diff | cat + +if ! git diff-files --quiet ; then + echo "ERROR: 'make -C src regen' does not match committed asn1 code" + exit 1 +fi + $MAKE $PARALLEL_MAKE LD_LIBRARY_PATH="$inst/lib" $MAKE check # distcheck is broken -- To view, visit https://gerrit.osmocom.org/776 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I18e7677d8596f61b883e9db57b4bdd2a5c154ec3 Gerrit-PatchSet: 5 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 29 14:55:12 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 14:55:12 +0000 Subject: [PATCH] osmo-iuh[master]: jenkins.sh: don't build twice In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/776 to look at the new patch set (#6). jenkins.sh: don't build twice Instead of building the same .c files twice, rather verify that the 'make regen' target produces identical .c files as are checked in. Change-Id: I18e7677d8596f61b883e9db57b4bdd2a5c154ec3 --- M contrib/jenkins.sh 1 file changed, 14 insertions(+), 9 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/76/776/6 diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index c24bec2..72efdbc 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -55,19 +55,24 @@ marker osmo-iuh cd "$base" -# Build using the checked-in asn1 code -autoreconf --install --force -./configure -$MAKE $PARALLEL_MAKE -LD_LIBRARY_PATH="$inst/lib" $MAKE check -# distcheck is broken -#LD_LIBRARY_PATH=$PWD/deps/install/lib $MAKE distcheck -make clean -# Build with regenerated asn1 code autoreconf --install --force ./configure + +# Verify that checked-in asn1 code is identical to regenerated asn1 code PATH="$inst/bin:$PATH" $MAKE $PARALLEL_MAKE -C src regen + +# attempt to settle the file system +sleep 1 + +git status +git diff | cat + +if ! git diff-files --quiet ; then + echo "ERROR: 'make -C src regen' does not match committed asn1 code" + exit 1 +fi + $MAKE $PARALLEL_MAKE LD_LIBRARY_PATH="$inst/lib" $MAKE check # distcheck is broken -- To view, visit https://gerrit.osmocom.org/776 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I18e7677d8596f61b883e9db57b4bdd2a5c154ec3 Gerrit-PatchSet: 6 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 29 14:59:18 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 14:59:18 +0000 Subject: osmo-iuh[master]: Not for merge -- jenkins test: dirty asn.1 files after regen In-Reply-To: References: Message-ID: Patch Set 4: > Build Failed > > http://jenkins.osmocom.org/jenkins/job/osmo-iuh-gerrit/31/ : > FAILURE ok, the build successfully rejected a dirty state of an asn.1 generated file. -- To view, visit https://gerrit.osmocom.org/777 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ib2f2495b62889410982ed5103d46fc61bc57d92f Gerrit-PatchSet: 4 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 29 14:59:23 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 14:59:23 +0000 Subject: [ABANDON] osmo-iuh[master]: Not for merge -- jenkins test: dirty asn.1 files after regen In-Reply-To: References: Message-ID: Neels Hofmeyr has abandoned this change. Change subject: Not for merge -- jenkins test: dirty asn.1 files after regen ...................................................................... Abandoned -- To view, visit https://gerrit.osmocom.org/777 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: abandon Gerrit-Change-Id: Ib2f2495b62889410982ed5103d46fc61bc57d92f Gerrit-PatchSet: 4 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 29 14:59:42 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 14:59:42 +0000 Subject: osmo-iuh[master]: jenkins.sh: don't build twice In-Reply-To: References: Message-ID: Patch Set 6: Verified+1 by https://gerrit.osmocom.org/777 -- To view, visit https://gerrit.osmocom.org/776 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I18e7677d8596f61b883e9db57b4bdd2a5c154ec3 Gerrit-PatchSet: 6 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 29 15:00:57 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 15:00:57 +0000 Subject: [PATCH] osmo-iuh[master]: tests: don't log filename nor color in unit tests Message-ID: Review at https://gerrit.osmocom.org/779 tests: don't log filename nor color in unit tests In experr, we had line numbers in log output, which might change. Also, for make distcheck, the path of the source file might have some '../../' added in the log output (to indicate the src dir as seen from the build dir). Fix both by dropping source file and line. Also drop color while at it. Change-Id: Ie76384c4176ce0a7d89d093f2efb848fe3f19400 --- M src/tests/test-helpers.err M src/tests/test_common.c 2 files changed, 5 insertions(+), 3 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/79/779/1 diff --git a/src/tests/test-helpers.err b/src/tests/test-helpers.err index 81b79e1..891094a 100644 --- a/src/tests/test-helpers.err +++ b/src/tests/test-helpers.err @@ -1,3 +1,2 @@ -<0004> ranap_common.c:508 Invalid PLMN Identity size: should be 3, is 2 -<0004> ranap_common.c:522 Invalid LAC size: should be 2, is 1 - \ No newline at end of file +Invalid PLMN Identity size: should be 3, is 2 +Invalid LAC size: should be 2, is 1 diff --git a/src/tests/test_common.c b/src/tests/test_common.c index 4e4c10c..a79d5f5 100644 --- a/src/tests/test_common.c +++ b/src/tests/test_common.c @@ -85,4 +85,7 @@ exit(1); ranap_set_log_area(DRANAP); + + log_set_print_filename(osmo_stderr_target, 0); + log_set_use_color(osmo_stderr_target, 0); } -- To view, visit https://gerrit.osmocom.org/779 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ie76384c4176ce0a7d89d093f2efb848fe3f19400 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 29 15:00:58 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 15:00:58 +0000 Subject: [PATCH] osmo-iuh[master]: build: use tar-ustar to allow paths longer than 99 Message-ID: Review at https://gerrit.osmocom.org/780 build: use tar-ustar to allow paths longer than 99 Needed to fix these errors: tar: osmo-iuh-UNKNOWN-dirty/include/osmocom/ranap/RANAP_SourceeNodeB-ToTargeteNodeB-TransparentContainer.h: file name is too long (max 99); not dumped tar: osmo-iuh-UNKNOWN-dirty/include/osmocom/ranap/RANAP_LocationRelatedDataRequestTypeSpecificToGERANIuMode.h: file name is too long (max 99); not dumped tar: osmo-iuh-UNKNOWN-dirty/include/osmocom/ranap/RANAP_TargeteNodeB-ToSourceeNodeB-TransparentContainer.h: file name is too long (max 99); not dumped tar: osmo-iuh-UNKNOWN-dirty/include/osmocom/ranap/RANAP_Requested-RAB-Parameter-ExtendedGuaranteedBitrateList.h: file name is too long (max 99); not dumped Change-Id: Id41bca92810a81ac50697c0230a6caef490b0ffd --- M configure.ac 1 file changed, 4 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/80/780/1 diff --git a/configure.ac b/configure.ac index c3a65d6..0c3ba3e 100644 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,10 @@ LT_INIT -AM_INIT_AUTOMAKE([foreign dist-bzip2 no-dist-gzip 1.6 subdir-objects]) +AM_INIT_AUTOMAKE([foreign dist-bzip2 no-dist-gzip 1.9 subdir-objects tar-ustar]) +dnl tar-ustar: some asn1 filenames surpass the 99 char limit of tar, so we need +dnl to make tar allow longer filenames. + AC_CONFIG_TESTDIR(src/tests) dnl kernel style compile messages -- To view, visit https://gerrit.osmocom.org/780 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Id41bca92810a81ac50697c0230a6caef490b0ffd Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Mon Aug 29 15:00:58 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 15:00:58 +0000 Subject: [PATCH] osmo-iuh[master]: build: remove subdir-objects from configure.ac, it is broken Message-ID: Review at https://gerrit.osmocom.org/781 build: remove subdir-objects from configure.ac, it is broken This is a known autoconf bug, it creates odd directories named literally '$(top_srcdir)', potentially messing up dependency checking. Change-Id: Ia47b038d4ca4f6c345711fb17d074f71c80e4453 --- M configure.ac 1 file changed, 1 insertion(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/81/781/1 diff --git a/configure.ac b/configure.ac index 0c3ba3e..249701e 100644 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,7 @@ LT_INIT -AM_INIT_AUTOMAKE([foreign dist-bzip2 no-dist-gzip 1.9 subdir-objects tar-ustar]) +AM_INIT_AUTOMAKE([foreign dist-bzip2 no-dist-gzip 1.9 tar-ustar]) dnl tar-ustar: some asn1 filenames surpass the 99 char limit of tar, so we need dnl to make tar allow longer filenames. -- To view, visit https://gerrit.osmocom.org/781 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ia47b038d4ca4f6c345711fb17d074f71c80e4453 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 29 15:00:58 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 15:00:58 +0000 Subject: [PATCH] osmo-iuh[master]: build: fix ranap gen, use same for gen hnbap and rua gen Message-ID: Review at https://gerrit.osmocom.org/782 build: fix ranap gen, use same for gen hnbap and rua gen fix extraneous rebuild for each make invocation: touch the ranap.stamp file in src/ as the make target suggests. fix for 'make distcheck': ranap gen: move generated sources to builddir, not srcdir. Thus we also -I the builddir include to pick up those headers. hnbap and rua have the same situation as ranap (they generate numerous files from a single make rule). Use the same makefile semantics for those two (commit for ranap gen omitted the same changes for hnbap and rua). The generated headers are thus moved to include/osmocom/*/, so adjust #include statements accordingly (*_common.h, *_ies_defs.h). Also move hnbap_common.h to include/osmocom/hnbap and rua_common.h to include/osmocom/rua, since the *_ies_defs.h want to include them; and since *_ies_defs.h are now in include/osmocom/*, we want a '' include now. Also adjust gitignore. Change-Id: I32213666fcdfc144008fa7d46497c0938d093e86 --- M .gitignore M include/osmocom/hnbap/Makefile.am R include/osmocom/hnbap/hnbap_common.h M include/osmocom/ranap/Makefile.am M include/osmocom/rua/Makefile.am R include/osmocom/rua/rua_common.h M src/.gitignore M src/Makefile.am M src/hnbap_common.c M src/hnbgw_hnbap.c M src/hnbgw_rua.c M src/rua_common.c M src/rua_msg_factory.c M src/tests/Makefile.am M src/tests/hnb-test.c M src/tests/test-hnbap.c 16 files changed, 54 insertions(+), 27 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/82/782/1 diff --git a/.gitignore b/.gitignore index b2538a7..e1430f9 100644 --- a/.gitignore +++ b/.gitignore @@ -35,5 +35,9 @@ tags libosmo-ranap.pc m4 +gen_hnbap.stamp +gen_rua.stamp gen_ranap.stamp +include/osmocom/hnbap/hnbap_ies_defs.h +include/osmocom/rua/rua_ies_defs.h include/osmocom/ranap/ranap_ies_defs.h diff --git a/include/osmocom/hnbap/Makefile.am b/include/osmocom/hnbap/Makefile.am index 7ab5d7f..83654cb 100644 --- a/include/osmocom/hnbap/Makefile.am +++ b/include/osmocom/hnbap/Makefile.am @@ -1,4 +1,5 @@ noinst_HEADERS = \ + hnbap_common.h hnbap_ies_defs.h \ AccessResult.h \ Access-stratum-release-indicator.h \ AdditionalNeighbourInfoList.h \ diff --git a/src/hnbap_common.h b/include/osmocom/hnbap/hnbap_common.h similarity index 100% rename from src/hnbap_common.h rename to include/osmocom/hnbap/hnbap_common.h diff --git a/include/osmocom/ranap/Makefile.am b/include/osmocom/ranap/Makefile.am index 13f1e1c..4728ac8 100644 --- a/include/osmocom/ranap/Makefile.am +++ b/include/osmocom/ranap/Makefile.am @@ -3,8 +3,8 @@ # the build process wants this header file, it should first build # src/ranap_encoder.c and src/ranap_decoder.c. # This rule sucks: -ranap_ies_defs.h: $(top_builddir)/src/ranap_encoder.c - make -C $(top_builddir)/src/ ranap_encoder.c +ranap_ies_defs.h: + $(MAKE) -C $(top_builddir)/src/ gen_ranap.stamp ranap_HEADERS = \ ranap_ies_defs.h \ diff --git a/include/osmocom/rua/Makefile.am b/include/osmocom/rua/Makefile.am index 059dfb8..8e8896d 100644 --- a/include/osmocom/rua/Makefile.am +++ b/include/osmocom/rua/Makefile.am @@ -1,4 +1,5 @@ noinst_HEADERS = \ + rua_common.h rua_ies_defs.h \ RUA_Ansi-41-IDNNS.h \ RUA_Cause.h \ RUA_CauseMisc.h \ diff --git a/src/rua_common.h b/include/osmocom/rua/rua_common.h similarity index 100% rename from src/rua_common.h rename to include/osmocom/rua/rua_common.h diff --git a/src/.gitignore b/src/.gitignore index 9384c58..55bca01 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,13 +1,10 @@ hnbap_decoder.c hnbap_encoder.c -hnbap_ies_defs.h rua_decoder.c rua_encoder.c -rua_ies_defs.h ranap_decoder.c ranap_encoder.c -ranap_ies_defs.h hnbgw diff --git a/src/Makefile.am b/src/Makefile.am index 17e60e2..ffdfef8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,25 +3,48 @@ # Build {hnbap,rua,ranap}_{encoder,decoder}.c using asn1tostruct ASN1_ROOT = $(top_builddir)/asn1/ ASN1TOSTRUCT = $(ASN1_ROOT)/utils/asn1tostruct.py -BUILT_SOURCES = hnbap_decoder.c hnbap_encoder.c rua_decoder.c rua_encoder.c gen_ranap.stamp +BUILT_SOURCES = hnbap_decoder.c hnbap_encoder.c rua_decoder.c rua_encoder.c \ + gen_hnbap.stamp gen_rua.stamp gen_ranap.stamp -hnbap_encoder.c hnbap_decoder.c hnbap_ies_defs.h: $(ASN1_ROOT)/hnbap/HNBAP-PDU-Contents.asn $(ASN1TOSTRUCT) +gen_hnbap.stamp: $(ASN1_ROOT)/hnbap/HNBAP-PDU-Contents.asn $(ASN1TOSTRUCT) $(ASN1TOSTRUCT) -f $< +# We also need to replace the include in the newly generated .c files: + sed -i 's,^#include "hnbap_ies_defs.h",#include ,' hnbap_encoder.c hnbap_decoder.c + sed -i 's,^#include "hnbap_common.h",#include ,' hnbap_encoder.c hnbap_decoder.c hnbap_ies_defs.h + mv hnbap_ies_defs.h $(top_builddir)/include/osmocom/hnbap/ +# this is ugly ^. hnbap_ies_defs.h is generated from asn1tostruct.py here, but +# it should live in include/osmocom/hnbap/. + touch $(top_builddir)/src/$@ -rua_encoder.c rua_decoder.c rua_ies_defs.h: $(ASN1_ROOT)/rua/RUA-PDU-Contents.asn $(ASN1TOSTRUCT) +hnbap_decoder.c hnbap_encoder.c: gen_hnbap.stamp + +gen_rua.stamp: $(ASN1_ROOT)/rua/RUA-PDU-Contents.asn $(ASN1TOSTRUCT) $(ASN1TOSTRUCT) -p RUA_ -f $< +# We also need to replace the include in the newly generated .c files: + sed -i 's,^#include "rua_ies_defs.h",#include ,' rua_encoder.c rua_decoder.c + sed -i 's,^#include "rua_common.h",#include ,' rua_encoder.c rua_decoder.c rua_ies_defs.h + mv rua_ies_defs.h $(top_builddir)/include/osmocom/rua/ +# this is ugly ^. rua_ies_defs.h is generated from asn1tostruct.py here, but +# it should live in include/osmocom/rua/. + touch $(top_builddir)/src/$@ + +rua_decoder.c rua_encoder.c: gen_rua.stamp gen_ranap.stamp: $(ASN1_ROOT)/ranap/RANAP-PDU-Contents.asn $(ASN1TOSTRUCT) $(ASN1TOSTRUCT) -p RANAP_ -f $< # We also need to replace the include in the newly generated .c files: sed -i 's,^#include "ranap_ies_defs.h",#include ,' ranap_encoder.c ranap_decoder.c sed -i 's,^#include "ranap_common.h",#include ,' ranap_encoder.c ranap_decoder.c ranap_ies_defs.h - mv ranap_ies_defs.h $(top_srcdir)/include/osmocom/ranap/ + mv ranap_ies_defs.h $(top_builddir)/include/osmocom/ranap/ # this is ugly ^. ranap_ies_defs.h is generated from asn1tostruct.py here, but # it should live in include/osmocom/ranap/. - touch $(top_builddir)/$@ + touch $(top_builddir)/src/$@ -AM_CFLAGS = -I$(top_srcdir)/include $(OSMOCORE_CFLAGS) $(OSMOVTY_CFLAGS) $(OSMOGSM_CFLAGS) $(OSMONETIF_CFLAGS) $(ASN1C_CFLAGS) $(OSMOSIGTRAN_CFLAGS) +ranap_decoder.c ranap_encoder.c: gen_ranap.stamp + +AM_CFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include \ + $(OSMOCORE_CFLAGS) $(OSMOVTY_CFLAGS) $(OSMOGSM_CFLAGS) \ + $(OSMONETIF_CFLAGS) $(ASN1C_CFLAGS) $(OSMOSIGTRAN_CFLAGS) COMMON_LDADD = -lsctp # build the shared RANAP library @@ -37,9 +60,7 @@ # bin_PROGRAMS = osmo-hnbgw -noinst_HEADERS = hnbap_common.h hnbap_ies_defs.h \ - rua_common.h rua_ies_defs.h \ - context_map.h hnbgw.h hnbgw_cn.h \ +noinst_HEADERS = context_map.h hnbgw.h hnbgw_cn.h \ hnbgw_hnbap.h hnbgw_rua.h hnbgw_ranap.h osmo_hnbgw_SOURCES = hnbap_encoder.c hnbap_decoder.c hnbap_common.c \ diff --git a/src/hnbap_common.c b/src/hnbap_common.c index f321a1c..2cd6519 100644 --- a/src/hnbap_common.c +++ b/src/hnbap_common.c @@ -24,7 +24,7 @@ #include #include -#include "hnbap_common.h" +#include #include "hnbgw.h" static const struct value_string hnbap_cause_radio_vals[] = { diff --git a/src/hnbgw_hnbap.c b/src/hnbgw_hnbap.c index 8a0bc9b..da82608 100644 --- a/src/hnbgw_hnbap.c +++ b/src/hnbgw_hnbap.c @@ -28,11 +28,11 @@ #include #include "asn1helpers.h" +#include #include #include "hnbgw.h" -#include "hnbap_common.h" -#include "hnbap_ies_defs.h" +#include #define IU_MSG_NUM_IES 32 #define IU_MSG_NUM_EXT_IES 32 diff --git a/src/hnbgw_rua.c b/src/hnbgw_rua.c index a6f0100..fc22bfc 100644 --- a/src/hnbgw_rua.c +++ b/src/hnbgw_rua.c @@ -34,8 +34,8 @@ #include "hnbgw.h" #include "hnbgw_ranap.h" -#include "rua_common.h" -#include "rua_ies_defs.h" +#include +#include #include "context_map.h" static int hnbgw_rua_tx(struct hnb_context *ctx, struct msgb *msg) diff --git a/src/rua_common.c b/src/rua_common.c index fcb873e..a5ab044 100644 --- a/src/rua_common.c +++ b/src/rua_common.c @@ -23,7 +23,7 @@ #include -#include "rua_common.h" +#include #include "hnbgw.h" extern int asn1_xer_print; diff --git a/src/rua_msg_factory.c b/src/rua_msg_factory.c index b664509..0bce326 100644 --- a/src/rua_msg_factory.c +++ b/src/rua_msg_factory.c @@ -1,8 +1,8 @@ #include #include -#include "rua_common.h" -#include "rua_ies_defs.h" +#include +#include #include "rua_msg_factory.h" #include "asn1helpers.h" #include "hnbgw.h" diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index 0fd050f..8cd7bf7 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -1,4 +1,7 @@ -AM_CFLAGS = -g -I$(top_srcdir)/src -I$(top_srcdir)/include $(OSMOVTY_CFLAGS) $(OSMOCORE_CFLAGS) $(OSMOGSM_CFLAGS) $(OSMONETIF_CFLAGS) $(ASN1C_CFLAGS) $(OSMOSIGTRAN_CFLAGS) +AM_CFLAGS = -g -I$(top_srcdir)/src/tests \ + -I$(top_srcdir)/include -I$(top_builddir)/include \ + $(OSMOVTY_CFLAGS) $(OSMOCORE_CFLAGS) $(OSMOGSM_CFLAGS) \ + $(OSMONETIF_CFLAGS) $(ASN1C_CFLAGS) $(OSMOSIGTRAN_CFLAGS) COMMON_LIBS = $(OSMOVTY_LIBS) $(OSMOCORE_LIBS) $(OSMOGSM_LIBS) $(ASN1C_LIBS) $(OSMOSIGTRAN_LIBS) -lsctp diff --git a/src/tests/hnb-test.c b/src/tests/hnb-test.c index af87376..2c41199 100644 --- a/src/tests/hnb-test.c +++ b/src/tests/hnb-test.c @@ -52,8 +52,8 @@ #include "hnb-test.h" #include "hnb-test-layers.h" -#include "hnbap_common.h" -#include "hnbap_ies_defs.h" +#include +#include #include "rua_msg_factory.h" #include "asn1helpers.h" #include diff --git a/src/tests/test-hnbap.c b/src/tests/test-hnbap.c index c6e7d94..ef46070 100644 --- a/src/tests/test-hnbap.c +++ b/src/tests/test-hnbap.c @@ -22,8 +22,8 @@ #include #include "asn1helpers.h" -#include "hnbap_common.h" -#include "hnbap_ies_defs.h" +#include +#include #include "test_common.h" #include -- To view, visit https://gerrit.osmocom.org/782 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I32213666fcdfc144008fa7d46497c0938d093e86 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 29 15:00:58 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 15:00:58 +0000 Subject: [PATCH] osmo-iuh[master]: build: distcheck: add missing distclean files Message-ID: Review at https://gerrit.osmocom.org/783 build: distcheck: add missing distclean files Change-Id: I24d72b2b1bae52a1b2cf8a989396d2aac31d119e --- M include/osmocom/hnbap/Makefile.am M include/osmocom/ranap/Makefile.am M include/osmocom/rua/Makefile.am M src/Makefile.am M src/tests/Makefile.am 5 files changed, 22 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/83/783/1 diff --git a/include/osmocom/hnbap/Makefile.am b/include/osmocom/hnbap/Makefile.am index 83654cb..cd9b720 100644 --- a/include/osmocom/hnbap/Makefile.am +++ b/include/osmocom/hnbap/Makefile.am @@ -115,3 +115,6 @@ U-RNTIQueryRequest.h \ U-RNTIQueryResponse.h \ UTRANCellID.h + +DISTCLEANFILES = \ + hnbap_ies_defs.h diff --git a/include/osmocom/ranap/Makefile.am b/include/osmocom/ranap/Makefile.am index 4728ac8..0f83e03 100644 --- a/include/osmocom/ranap/Makefile.am +++ b/include/osmocom/ranap/Makefile.am @@ -593,3 +593,6 @@ RANAP_VoiceSupportMatchIndicator.h ranapdir = $(includedir)/osmocom/ranap + +DISTCLEANFILES = \ + ranap_ies_defs.h diff --git a/include/osmocom/rua/Makefile.am b/include/osmocom/rua/Makefile.am index 8e8896d..49e2150 100644 --- a/include/osmocom/rua/Makefile.am +++ b/include/osmocom/rua/Makefile.am @@ -35,3 +35,6 @@ RUA_TriggeringMessage.h \ RUA_TypeOfError.h \ RUA_UnsuccessfulOutcome.h + +DISTCLEANFILES = \ + rua_ies_defs.h diff --git a/src/Makefile.am b/src/Makefile.am index ffdfef8..3e309db 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -83,3 +83,14 @@ $(MAKE) -C hnbap regen $(MAKE) -C ranap regen $(MAKE) -C rua regen + +DISTCLEANFILES = \ + hnbap_decoder.c \ + hnbap_encoder.c \ + rua_decoder.c \ + rua_encoder.c \ + ranap_decoder.c \ + ranap_encoder.c \ + gen_hnbap.stamp \ + gen_rua.stamp \ + gen_ranap.stamp diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index 8cd7bf7..b0383f7 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -45,6 +45,8 @@ TESTSUITE = $(srcdir)/testsuite +DISTCLEANFILES = atconfig + check-local: atconfig $(TESTSUITE) $(SHELL) '$(TESTSUITE)' $(TESTSUITEFLAGS) -- To view, visit https://gerrit.osmocom.org/783 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I24d72b2b1bae52a1b2cf8a989396d2aac31d119e Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 29 15:00:58 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 15:00:58 +0000 Subject: [PATCH] osmo-iuh[master]: build: distcheck: look for asn1 in top_srcdir, not top_builddir Message-ID: Review at https://gerrit.osmocom.org/784 build: distcheck: look for asn1 in top_srcdir, not top_builddir Change-Id: Iebcff240ba2fae964dad2a2c481fcbfd29e14e69 --- M src/Makefile.am 1 file changed, 1 insertion(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/84/784/1 diff --git a/src/Makefile.am b/src/Makefile.am index 3e309db..2779315 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,7 @@ SUBDIRS = hnbap rua ranap tests # Build {hnbap,rua,ranap}_{encoder,decoder}.c using asn1tostruct -ASN1_ROOT = $(top_builddir)/asn1/ +ASN1_ROOT = $(top_srcdir)/asn1 ASN1TOSTRUCT = $(ASN1_ROOT)/utils/asn1tostruct.py BUILT_SOURCES = hnbap_decoder.c hnbap_encoder.c rua_decoder.c rua_encoder.c \ gen_hnbap.stamp gen_rua.stamp gen_ranap.stamp -- To view, visit https://gerrit.osmocom.org/784 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Iebcff240ba2fae964dad2a2c481fcbfd29e14e69 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 29 15:00:58 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 15:00:58 +0000 Subject: [PATCH] osmo-iuh[master]: build: distcheck: add missing bits for testsuite distcheck Message-ID: Review at https://gerrit.osmocom.org/785 build: distcheck: add missing bits for testsuite distcheck Got some errors during 'make distcheck', copying the way openbsc.git does these things. Change-Id: I13d76cd56dfb8fe4eb02d6fcada78a9e3311b51b --- M src/tests/Makefile.am 1 file changed, 10 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/85/785/1 diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index b0383f7..e435dab 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -44,12 +44,22 @@ } >'$(srcdir)/package.m4' TESTSUITE = $(srcdir)/testsuite +EXTRA_DIST = testsuite.at $(TESTSUITE) $(srcdir)/package.m4 \ + test-helpers.err test-helpers.ok test-hnbap.ok test-ranap.ok DISTCLEANFILES = atconfig check-local: atconfig $(TESTSUITE) $(SHELL) '$(TESTSUITE)' $(TESTSUITEFLAGS) +installcheck-local: atconfig $(TESTSUITE) + $(SHELL) '$(TESTSUITE)' AUTOTEST_PATH='$(bindir)' \ + $(TESTSUITEFLAGS) + +clean-local: + test ! -f '$(TESTSUITE)' || \ + $(SHELL) '$(TESTSUITE)' --clean + AUTOM4TE = $(SHELL) $(top_srcdir)/missing --run autom4te AUTOTEST = $(AUTOM4TE) --language=autotest -- To view, visit https://gerrit.osmocom.org/785 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I13d76cd56dfb8fe4eb02d6fcada78a9e3311b51b Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 29 15:00:58 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 15:00:58 +0000 Subject: [PATCH] osmo-iuh[master]: build: cosmetic: hnbap: undup asn1 src path Message-ID: Review at https://gerrit.osmocom.org/786 build: cosmetic: hnbap: undup asn1 src path Change-Id: I0507277995302261c87db1b0c48105065cf13ae4 --- M src/hnbap/Makefile.am 1 file changed, 3 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/86/786/1 diff --git a/src/hnbap/Makefile.am b/src/hnbap/Makefile.am index 131bef1..8a2c56a 100644 --- a/src/hnbap/Makefile.am +++ b/src/hnbap/Makefile.am @@ -234,6 +234,8 @@ AM_CFLAGS = -I$(top_srcdir)/include $(ASN1C_CFLAGS) $(OSMOCORE_CFLAGS) +HNBAP_ASN1 = $(top_srcdir)/asn1/hnbap + noinst_LIBRARIES=libosmo-asn1-hnbap.a libosmo_asn1_hnbap_a_SOURCES=$(ASN_MODULE_SOURCES) libosmo_asn1_hnbap_a_LIBADD=$(ASN1C_LDADD) @@ -241,7 +243,7 @@ regen: regenerate-from-asn1-source regenerate-from-asn1-source: - asn1c -gen-PER -fnative-types $(top_srcdir)/asn1/hnbap/HNBAP-CommonDataTypes.asn $(top_srcdir)/asn1/hnbap/HNBAP-Constants.asn $(top_srcdir)/asn1/hnbap/HNBAP-IEs.asn $(top_srcdir)/asn1/hnbap/HNBAP-PDU.asn + asn1c -gen-PER -fnative-types $(HNBAP_ASN1)/HNBAP-CommonDataTypes.asn $(HNBAP_ASN1)/HNBAP-Constants.asn $(HNBAP_ASN1)/HNBAP-IEs.asn $(HNBAP_ASN1)/HNBAP-PDU.asn # remove the local copy of the runtime code -rm ANY.* BOOLEAN.* INTEGER.* NativeEnumerated.* NativeInteger.* OBJECT_IDENTIFIER.* asn_* OCTET_STRING.* converter-sample.c per_* xer_* constr* der_* ber_* BIT_STRING.* # change include style to `#include ' -- To view, visit https://gerrit.osmocom.org/786 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I0507277995302261c87db1b0c48105065cf13ae4 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 29 15:00:59 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 15:00:59 +0000 Subject: [PATCH] osmo-iuh[master]: build: move headers to include/osmocom/* Message-ID: Review at https://gerrit.osmocom.org/787 build: move headers to include/osmocom/* This came up while fixing 'make distcheck'; this is certainly not the easiest way but it makes sense to have the headers in include/, like we do in openbsc. The easy alternative might be to add -I$(top_srcdir)/src to the Makefile.am. Change-Id: I5a82e029dcdc4df0a60a31271a4883393fe59234 --- M include/osmocom/iuh/Makefile.am R include/osmocom/iuh/context_map.h R include/osmocom/iuh/hnbgw.h R include/osmocom/iuh/hnbgw_cn.h R include/osmocom/iuh/hnbgw_hnbap.h R include/osmocom/iuh/hnbgw_ranap.h R include/osmocom/iuh/hnbgw_rua.h R include/osmocom/iuh/iu_common.h M include/osmocom/rua/Makefile.am R include/osmocom/rua/rua_msg_factory.h M src/Makefile.am M src/context_map.c M src/hnbap_common.c M src/hnbgw.c M src/hnbgw_cn.c M src/hnbgw_hnbap.c M src/hnbgw_ranap.c M src/hnbgw_rua.c M src/hnbgw_vty.c M src/ranap_common_cn.c M src/rua_common.c M src/rua_msg_factory.c M src/tests/Makefile.am M src/tests/dummy_cn_sua.c M src/tests/hnb-test-rua.c M src/tests/hnb-test.c M src/tests/test-ranap.c M src/tests/test_common.c 28 files changed, 38 insertions(+), 37 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/87/787/1 diff --git a/include/osmocom/iuh/Makefile.am b/include/osmocom/iuh/Makefile.am index e2f7126..b2a667d 100644 --- a/include/osmocom/iuh/Makefile.am +++ b/include/osmocom/iuh/Makefile.am @@ -1,2 +1,4 @@ noinst_HEADERS = \ - vty.h + vty.h \ + context_map.h hnbgw.h hnbgw_cn.h \ + hnbgw_hnbap.h hnbgw_rua.h hnbgw_ranap.h diff --git a/src/context_map.h b/include/osmocom/iuh/context_map.h similarity index 100% rename from src/context_map.h rename to include/osmocom/iuh/context_map.h diff --git a/src/hnbgw.h b/include/osmocom/iuh/hnbgw.h similarity index 100% rename from src/hnbgw.h rename to include/osmocom/iuh/hnbgw.h diff --git a/src/hnbgw_cn.h b/include/osmocom/iuh/hnbgw_cn.h similarity index 78% rename from src/hnbgw_cn.h rename to include/osmocom/iuh/hnbgw_cn.h index 469b3d4..d5bec04 100644 --- a/src/hnbgw_cn.h +++ b/include/osmocom/iuh/hnbgw_cn.h @@ -1,5 +1,5 @@ #pragma once -#include "hnbgw.h" +#include struct hnbgw_cnlink *hnbgw_cnlink_init(struct hnb_gw *gw, const char *host, uint16_t port, int is_ps); diff --git a/src/hnbgw_hnbap.h b/include/osmocom/iuh/hnbgw_hnbap.h similarity index 77% rename from src/hnbgw_hnbap.h rename to include/osmocom/iuh/hnbgw_hnbap.h index 955e0aa..cca3550 100644 --- a/src/hnbgw_hnbap.h +++ b/include/osmocom/iuh/hnbgw_hnbap.h @@ -1,6 +1,6 @@ #pragma once -#include "hnbgw.h" +#include int hnbgw_hnbap_rx(struct hnb_context *hnb, struct msgb *msg); int hnbgw_hnbap_init(void); diff --git a/src/hnbgw_ranap.h b/include/osmocom/iuh/hnbgw_ranap.h similarity index 77% rename from src/hnbgw_ranap.h rename to include/osmocom/iuh/hnbgw_ranap.h index 85a2f98..2c55964 100644 --- a/src/hnbgw_ranap.h +++ b/include/osmocom/iuh/hnbgw_ranap.h @@ -1,6 +1,6 @@ #pragma once -#include "hnbgw.h" +#include int hnbgw_ranap_rx(struct msgb *msg, uint8_t *data, size_t len); int hnbgw_ranap_init(void); diff --git a/src/hnbgw_rua.h b/include/osmocom/iuh/hnbgw_rua.h similarity index 93% rename from src/hnbgw_rua.h rename to include/osmocom/iuh/hnbgw_rua.h index d170190..6a890b7 100644 --- a/src/hnbgw_rua.h +++ b/include/osmocom/iuh/hnbgw_rua.h @@ -1,6 +1,6 @@ #pragma once -#include "hnbgw.h" +#include #include int hnbgw_rua_rx(struct hnb_context *hnb, struct msgb *msg); diff --git a/src/iu_common.h b/include/osmocom/iuh/iu_common.h similarity index 100% rename from src/iu_common.h rename to include/osmocom/iuh/iu_common.h diff --git a/include/osmocom/rua/Makefile.am b/include/osmocom/rua/Makefile.am index 49e2150..307f123 100644 --- a/include/osmocom/rua/Makefile.am +++ b/include/osmocom/rua/Makefile.am @@ -1,5 +1,5 @@ noinst_HEADERS = \ - rua_common.h rua_ies_defs.h \ + rua_common.h rua_ies_defs.h rua_msg_factory.h \ RUA_Ansi-41-IDNNS.h \ RUA_Cause.h \ RUA_CauseMisc.h \ diff --git a/src/rua_msg_factory.h b/include/osmocom/rua/rua_msg_factory.h similarity index 100% rename from src/rua_msg_factory.h rename to include/osmocom/rua/rua_msg_factory.h diff --git a/src/Makefile.am b/src/Makefile.am index 2779315..bb1ebbd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -60,9 +60,6 @@ # bin_PROGRAMS = osmo-hnbgw -noinst_HEADERS = context_map.h hnbgw.h hnbgw_cn.h \ - hnbgw_hnbap.h hnbgw_rua.h hnbgw_ranap.h - osmo_hnbgw_SOURCES = hnbap_encoder.c hnbap_decoder.c hnbap_common.c \ rua_encoder.c rua_decoder.c rua_common.c \ rua_msg_factory.c \ diff --git a/src/context_map.c b/src/context_map.c index 22eb605..052133c 100644 --- a/src/context_map.c +++ b/src/context_map.c @@ -24,8 +24,8 @@ #include -#include "hnbgw.h" -#include "context_map.h" +#include +#include /* is a given SCCP USER SAP Connection ID in use for a given CN link? */ static int cn_id_in_use(struct hnbgw_cnlink *cn, uint32_t id) diff --git a/src/hnbap_common.c b/src/hnbap_common.c index 2cd6519..f8cfb13 100644 --- a/src/hnbap_common.c +++ b/src/hnbap_common.c @@ -25,7 +25,7 @@ #include #include -#include "hnbgw.h" +#include static const struct value_string hnbap_cause_radio_vals[] = { { CauseRadioNetwork_overload, "overload" }, diff --git a/src/hnbgw.c b/src/hnbgw.c index 4f23e8d..d50e622 100644 --- a/src/hnbgw.c +++ b/src/hnbgw.c @@ -51,11 +51,11 @@ #include #include -#include "hnbgw.h" -#include "hnbgw_hnbap.h" -#include "hnbgw_rua.h" -#include "hnbgw_cn.h" -#include "context_map.h" +#include +#include +#include +#include +#include static const char * const osmo_hnbgw_copyright = "OsmoHNBGW - Osmocom Home Node B Gateway implementation\r\n" diff --git a/src/hnbgw_cn.c b/src/hnbgw_cn.c index 09b2726..e41788d 100644 --- a/src/hnbgw_cn.c +++ b/src/hnbgw_cn.c @@ -29,11 +29,11 @@ #include #include -#include "hnbgw.h" -#include "hnbgw_rua.h" +#include +#include #include #include -#include "context_map.h" +#include /*********************************************************************** * Outbound RANAP RESET to CN diff --git a/src/hnbgw_hnbap.c b/src/hnbgw_hnbap.c index da82608..2595913 100644 --- a/src/hnbgw_hnbap.c +++ b/src/hnbgw_hnbap.c @@ -31,7 +31,7 @@ #include #include -#include "hnbgw.h" +#include #include #define IU_MSG_NUM_IES 32 diff --git a/src/hnbgw_ranap.c b/src/hnbgw_ranap.c index dde1183..7a505a5 100644 --- a/src/hnbgw_ranap.c +++ b/src/hnbgw_ranap.c @@ -29,8 +29,8 @@ #include "asn1helpers.h" -#include "hnbgw.h" -#include "hnbgw_rua.h" +#include +#include #include #include #include diff --git a/src/hnbgw_rua.c b/src/hnbgw_rua.c index fc22bfc..3f245b5 100644 --- a/src/hnbgw_rua.c +++ b/src/hnbgw_rua.c @@ -32,11 +32,11 @@ #include "asn1helpers.h" -#include "hnbgw.h" -#include "hnbgw_ranap.h" +#include +#include #include #include -#include "context_map.h" +#include static int hnbgw_rua_tx(struct hnb_context *ctx, struct msgb *msg) { diff --git a/src/hnbgw_vty.c b/src/hnbgw_vty.c index 1673c0c..2e3d1e9 100644 --- a/src/hnbgw_vty.c +++ b/src/hnbgw_vty.c @@ -22,8 +22,8 @@ #include -#include "hnbgw.h" -#include "context_map.h" +#include +#include static void *tall_hnb_ctx = NULL; static struct hnb_gw *g_hnb_gw = NULL; diff --git a/src/ranap_common_cn.c b/src/ranap_common_cn.c index 2c80dd0..3736dce 100644 --- a/src/ranap_common_cn.c +++ b/src/ranap_common_cn.c @@ -29,7 +29,7 @@ #include #include -#include "hnbgw.h" +#include static int cn_ranap_rx_initiating_msg_co(void *ctx, RANAP_InitiatingMessage_t *imsg, ranap_message *message) diff --git a/src/rua_common.c b/src/rua_common.c index a5ab044..3c9d773 100644 --- a/src/rua_common.c +++ b/src/rua_common.c @@ -24,7 +24,7 @@ #include #include -#include "hnbgw.h" +#include extern int asn1_xer_print; diff --git a/src/rua_msg_factory.c b/src/rua_msg_factory.c index 0bce326..268f6ac 100644 --- a/src/rua_msg_factory.c +++ b/src/rua_msg_factory.c @@ -3,9 +3,9 @@ #include #include -#include "rua_msg_factory.h" +#include #include "asn1helpers.h" -#include "hnbgw.h" +#include struct msgb *rua_new_udt(struct msgb *inmsg) diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index e435dab..3a99681 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -7,6 +7,8 @@ check_PROGRAMS = test-ranap test-helpers test-hnbap hnb-test dummy-cn +noinst_HEADERS = test_common.h hnb-test.h hnb-test-layers.h + HNBAP_FILES = $(top_srcdir)/src/hnbap_common.c $(top_srcdir)/src/hnbap_decoder.c $(top_srcdir)/src/hnbap_encoder.c RUA_FILES = $(top_srcdir)/src/rua_common.c $(top_srcdir)/src/rua_decoder.c $(top_srcdir)/src/rua_encoder.c $(top_srcdir)/src/rua_msg_factory.c diff --git a/src/tests/dummy_cn_sua.c b/src/tests/dummy_cn_sua.c index c2fc712..f9b4244 100644 --- a/src/tests/dummy_cn_sua.c +++ b/src/tests/dummy_cn_sua.c @@ -24,7 +24,7 @@ #include #include #include -#include "hnbgw.h" +#include int asn1_xer_print = 1; const char *cmdline_bind_addr = "127.0.0.1"; diff --git a/src/tests/hnb-test-rua.c b/src/tests/hnb-test-rua.c index 69c41eb..a218852 100644 --- a/src/tests/hnb-test-rua.c +++ b/src/tests/hnb-test-rua.c @@ -1,6 +1,6 @@ #include -#include "../rua_ies_defs.h" +#include #include "hnb-test-layers.h" diff --git a/src/tests/hnb-test.c b/src/tests/hnb-test.c index 2c41199..d338077 100644 --- a/src/tests/hnb-test.c +++ b/src/tests/hnb-test.c @@ -54,7 +54,7 @@ #include "hnb-test-layers.h" #include #include -#include "rua_msg_factory.h" +#include #include "asn1helpers.h" #include #include "test_common.h" diff --git a/src/tests/test-ranap.c b/src/tests/test-ranap.c index 7b1f3bf..812a863 100644 --- a/src/tests/test-ranap.c +++ b/src/tests/test-ranap.c @@ -32,7 +32,7 @@ #include "test_common.h" -#include "hnbgw.h" +#include int asn1_xer_print = 1; diff --git a/src/tests/test_common.c b/src/tests/test_common.c index a79d5f5..5a37e7e 100644 --- a/src/tests/test_common.c +++ b/src/tests/test_common.c @@ -37,7 +37,7 @@ #include #include -#include "hnbgw.h" +#include void *talloc_asn1_ctx; -- To view, visit https://gerrit.osmocom.org/787 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I5a82e029dcdc4df0a60a31271a4883393fe59234 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Mon Aug 29 15:00:59 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 15:00:59 +0000 Subject: [PATCH] osmo-iuh[master]: build: parallel build: require ../libosmo-ranap.la from tests/ Message-ID: Review at https://gerrit.osmocom.org/788 build: parallel build: require ../libosmo-ranap.la from tests/ This rule is bad because it re-invokes $(MAKE), but it seems to fix the parallel build. It should probably be done differently. Change-Id: I8107e08e4c211f20d671f520bf6bab9356f3c90e --- M src/tests/Makefile.am 1 file changed, 3 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/88/788/1 diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index 3a99681..5b51262 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -27,6 +27,9 @@ dummy_cn_SOURCES = $(RANAP_FILES) test_common.c dummy_cn_sua.c dummy_cn_LDADD = $(COMMON_LIBS) $(top_builddir)/src/libosmo-ranap.la +$(top_builddir)/src/libosmo-ranap.la: + $(MAKE) -C $(top_builddir)/src libosmo-ranap.la + # The `:;' works around a Bash 3.2 bug when the output is not writeable. $(srcdir)/package.m4: $(top_srcdir)/configure.ac :;{ \ -- To view, visit https://gerrit.osmocom.org/788 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I8107e08e4c211f20d671f520bf6bab9356f3c90e Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 29 15:00:59 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 15:00:59 +0000 Subject: [PATCH] osmo-iuh[master]: jenkins.sh: enable make distcheck Message-ID: Review at https://gerrit.osmocom.org/789 jenkins.sh: enable make distcheck Change-Id: I967d4de9682cb2a45210f689ec076ef457841179 --- M contrib/jenkins.sh 1 file changed, 1 insertion(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/89/789/1 diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index 72efdbc..8021bbd 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -75,5 +75,4 @@ $MAKE $PARALLEL_MAKE LD_LIBRARY_PATH="$inst/lib" $MAKE check -# distcheck is broken -#LD_LIBRARY_PATH=$PWD/deps/install/lib $MAKE distcheck +LD_LIBRARY_PATH="$inst/lib" $MAKE distcheck -- To view, visit https://gerrit.osmocom.org/789 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I967d4de9682cb2a45210f689ec076ef457841179 Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 29 15:12:01 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 15:12:01 +0000 Subject: [PATCH] openbsc[master]: IuPS: osmo-sgsn: add core IuPS impl, call iu_init() In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/729 to look at the new patch set (#3). IuPS: osmo-sgsn: add core IuPS impl, call iu_init() Add: * gsm0408_gprs_rcvmsg_iu() * sgsn_mm_ctx_by_ue_ctx() * sgsn_mm_ctx_alloc_iu() * sgsn_ranap_iu_event() * sgsn_ranap_rab_ass_resp() Call iu_init() from sgsn_main.c. Add asn_debug impl ("extern" from libasn1c). osmo-sgsn build: add libiu and libasn1c, libosmo-sigtran, libosmo-ranap Change-Id: I469ae6ca9ef254d04ee0d2d79bdd65aebcd027b5 --- M openbsc/include/openbsc/gprs_gmm.h M openbsc/include/openbsc/gprs_sgsn.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/gprs_gmm.c M openbsc/src/gprs/gprs_sgsn.c M openbsc/src/gprs/sgsn_libgtp.c M openbsc/src/gprs/sgsn_main.c 7 files changed, 237 insertions(+), 3 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/29/729/3 diff --git a/openbsc/include/openbsc/gprs_gmm.h b/openbsc/include/openbsc/gprs_gmm.h index 8a3ffea..28467d7 100644 --- a/openbsc/include/openbsc/gprs_gmm.h +++ b/openbsc/include/openbsc/gprs_gmm.h @@ -14,6 +14,8 @@ int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme, bool drop_cipherable); +int gsm0408_gprs_rcvmsg_iu(struct msgb *msg, struct gprs_ra_id *ra_id, + uint16_t *sai); int gsm0408_gprs_force_reattach(struct sgsn_mm_ctx *mmctx); int gsm0408_gprs_force_reattach_oldmsg(struct msgb *msg, struct gprs_llc_llme *llme); diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h index b0dd75f..18cbab8 100644 --- a/openbsc/include/openbsc/gprs_sgsn.h +++ b/openbsc/include/openbsc/gprs_sgsn.h @@ -226,6 +226,7 @@ const struct gprs_ra_id *raid); struct sgsn_mm_ctx *sgsn_mm_ctx_by_ptmsi(uint32_t tmsi); struct sgsn_mm_ctx *sgsn_mm_ctx_by_imsi(const char *imsi); +struct sgsn_mm_ctx *sgsn_mm_ctx_by_ue_ctx(const void *uectx); /* look-up by matching TLLI and P-TMSI (think twice before using this) */ struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli_and_ptmsi(uint32_t tlli, @@ -234,6 +235,8 @@ /* Allocate a new SGSN MM context */ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t tlli, const struct gprs_ra_id *raid); +struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_iu(void *uectx); + void sgsn_mm_ctx_cleanup_free(struct sgsn_mm_ctx *ctx); struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx, diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 1b6de46..6a95315 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -3,6 +3,10 @@ $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOCTRL_CFLAGS) \ $(LIBOSMOABIS_CFLAGS) $(LIBOSMOGB_CFLAGS) $(COVERAGE_CFLAGS) \ $(LIBCARES_CFLAGS) $(LIBCRYPTO_CFLAGS) $(LIBGTP_CFLAGS) +if BUILD_IU +AM_CFLAGS += $(LIBASN1C_CFLAGS) $(LIBOSMOSIGTRAN_CFLAGS) $(LIBOSMORANAP_CFLAGS) +endif + OSMO_LIBS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) \ $(LIBOSMOCTRL_LIBS) $(LIBOSMOGB_LIBS) @@ -28,9 +32,15 @@ sgsn_cdr.c sgsn_ares.c \ oap.c oap_messages.c gprs_llc_xid.c osmo_sgsn_LDADD = \ - $(top_builddir)/src/libcommon/libcommon.a \ - -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ + $(top_builddir)/src/libcommon/libcommon.a +if BUILD_IU +osmo_sgsn_LDADD += $(top_builddir)/src/libiu/libiu.a +endif +osmo_sgsn_LDADD += -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ $(LIBCRYPTO_LIBS) -lrt +if BUILD_IU +osmo_sgsn_LDADD += $(LIBOSMOSIGTRAN_LIBS) $(LIBOSMORANAP_LIBS) $(LIBASN1C_LIBS) +endif osmo_gtphub_SOURCES = gtphub_main.c gtphub.c gtphub_sock.c gtphub_ares.c \ gtphub_vty.c sgsn_ares.c gprs_utils.c diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index 1efada9..4c44224 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -33,6 +33,8 @@ #include +#include "bscconfig.h" + #include #include #include @@ -44,6 +46,10 @@ #include #include + +#ifdef BUILD_IU +#include +#endif #include #include @@ -57,6 +63,10 @@ #include #include #include + +#ifdef BUILD_IU +#include +#endif #include @@ -96,6 +106,45 @@ }; static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx); + +#ifdef BUILD_IU +int sgsn_ranap_rab_ass_resp(struct sgsn_mm_ctx *ctx, RANAP_RAB_SetupOrModifiedItemIEs_t *setup_ies); +int sgsn_ranap_iu_event(struct ue_conn_ctx *ctx, enum iu_event_type type, void *data) +{ + struct sgsn_mm_ctx *mm; + int rc = -1; + + mm = sgsn_mm_ctx_by_ue_ctx(ctx); + if (!mm) { + LOGP(DRANAP, LOGL_NOTICE, "Cannot find mm ctx for IU event %i!\n", type); + return rc; + } + + switch (type) { + case IU_EVENT_RAB_ASSIGN: + rc = sgsn_ranap_rab_ass_resp(mm, (RANAP_RAB_SetupOrModifiedItemIEs_t *)data); + break; + case IU_EVENT_IU_RELEASE: + /* fall thru */ + case IU_EVENT_LINK_INVALIDATED: + /* Clean up ue_conn_ctx here */ + LOGMMCTXP(LOGL_INFO, mm, "IU release for imsi %s\n", mm->imsi); + rc = 0; + break; + case IU_EVENT_SECURITY_MODE_COMPLETE: + /* Continue authentication here */ + mm->iu.ue_ctx->integrity_active = 1; + rc = gsm48_gmm_authorize(mm); + break; + default: + LOGP(DRANAP, LOGL_NOTICE, "Unknown event received: %i\n", type); + rc = -1; + break; + } + return rc; +} +#endif + /* Our implementation, should be kept in SGSN */ @@ -2193,6 +2242,45 @@ return rc; } +/* Main entry point for incoming 04.08 GPRS messages from Iu */ +int gsm0408_gprs_rcvmsg_iu(struct msgb *msg, struct gprs_ra_id *ra_id, + uint16_t *sai) +{ + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); + uint8_t pdisc = gsm48_hdr_pdisc(gh); + struct sgsn_mm_ctx *mmctx; + int rc = -EINVAL; + + mmctx = sgsn_mm_ctx_by_ue_ctx(msg->dst); + if (mmctx) { + rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]); + if (ra_id) + memcpy(&mmctx->ra, ra_id, sizeof(mmctx->ra)); + } + + /* MMCTX can be NULL */ + + switch (pdisc) { + case GSM48_PDISC_MM_GPRS: + rc = gsm0408_rcv_gmm(mmctx, msg, NULL, false); +#warning "set drop_cipherable arg for gsm0408_rcv_gmm() from IuPS?" + break; + case GSM48_PDISC_SM_GPRS: + rc = gsm0408_rcv_gsm(mmctx, msg, NULL); + break; + default: + LOGMMCTXP(LOGL_NOTICE, mmctx, + "Unknown GSM 04.08 discriminator 0x%02x: %s\n", + pdisc, osmo_hexdump((uint8_t *)gh, msgb_l3len(msg))); + /* FIXME: return status message */ + break; + } + + /* MMCTX can be invalid */ + + return rc; +} + /* Main entry point for incoming 04.08 GPRS messages from Gb */ int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme, bool drop_cipherable) diff --git a/openbsc/src/gprs/gprs_sgsn.c b/openbsc/src/gprs/gprs_sgsn.c index 9cd992b..19b0a1b 100644 --- a/openbsc/src/gprs/gprs_sgsn.c +++ b/openbsc/src/gprs/gprs_sgsn.c @@ -39,6 +39,7 @@ #include #include #include "openbsc/gprs_llc.h" +#include #include @@ -130,6 +131,20 @@ sgsn->rate_ctrs = rate_ctr_group_alloc(tall_bsc_ctx, &sgsn_ctrg_desc, 0); } +/* look-up an SGSN MM context based on Iu UE context (struct ue_conn_ctx)*/ +struct sgsn_mm_ctx *sgsn_mm_ctx_by_ue_ctx(const void *uectx) +{ + struct sgsn_mm_ctx *ctx; + + llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) { + if (ctx->ran_type == MM_CTX_T_UTRAN_Iu + && uectx == ctx->iu.ue_ctx) + return ctx; + } + + return NULL; +} + /* look-up a SGSN MM context based on TLLI + RAI */ struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(uint32_t tlli, const struct gprs_ra_id *raid) @@ -218,6 +233,32 @@ return ctx; } +/* Allocate a new SGSN MM context */ +struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_iu(void *uectx) +{ + struct sgsn_mm_ctx *ctx; + + ctx = talloc_zero(tall_bsc_ctx, struct sgsn_mm_ctx); + if (!ctx) + return NULL; + + ctx->ran_type = MM_CTX_T_UTRAN_Iu; + ctx->iu.ue_ctx = uectx; + ctx->mm_state = GMM_DEREGISTERED; + ctx->auth_triplet.key_seq = GSM_KEY_SEQ_INVAL; + ctx->ctrg = rate_ctr_group_alloc(ctx, &mmctx_ctrg_desc, 0); + + /* Need to get RAID from IU conn */ + ctx->ra = ctx->iu.ue_ctx->ra_id; + + INIT_LLIST_HEAD(&ctx->pdp_list); + + llist_add(&ctx->list, &sgsn_mm_ctxts); + + return ctx; +} + + /* this is a hard _free_ function, it doesn't clean up the PDP contexts * in libgtp! */ static void sgsn_mm_ctx_free(struct sgsn_mm_ctx *mm) diff --git a/openbsc/src/gprs/sgsn_libgtp.c b/openbsc/src/gprs/sgsn_libgtp.c index be7637a..4a14cf6 100644 --- a/openbsc/src/gprs/sgsn_libgtp.c +++ b/openbsc/src/gprs/sgsn_libgtp.c @@ -34,6 +34,8 @@ #include #include +#include "bscconfig.h" + #include #include #include @@ -47,6 +49,11 @@ #include #include #include + +#ifdef BUILD_IU +#include +#include +#endif #include #include @@ -218,7 +225,10 @@ memcpy(pdp->gsnlc.v, &sgsn->cfg.gtp_listenaddr.sin_addr, sizeof(sgsn->cfg.gtp_listenaddr.sin_addr)); - /* SGSN address for user plane */ + /* SGSN address for user plane + * Default to the control plane addr for now. If we are connected to a + * hnbgw via IuPS we'll need to send a PDP context update with the + * correct IP address after the RAB Assignment is complete */ pdp->gsnlu.l = sizeof(sgsn->cfg.gtp_listenaddr.sin_addr); memcpy(pdp->gsnlu.v, &sgsn->cfg.gtp_listenaddr.sin_addr, sizeof(sgsn->cfg.gtp_listenaddr.sin_addr)); @@ -383,6 +393,72 @@ return EOF; } +#ifdef BUILD_IU +/* Callback for RAB assignment response */ +int sgsn_ranap_rab_ass_resp(struct sgsn_mm_ctx *ctx, RANAP_RAB_SetupOrModifiedItemIEs_t *setup_ies) +{ + uint8_t rab_id; + bool require_pdp_update = false; + struct sgsn_pdp_ctx *pdp = NULL; + RANAP_RAB_SetupOrModifiedItem_t *item = &setup_ies->raB_SetupOrModifiedItem; + + rab_id = item->rAB_ID.buf[0]; + + pdp = sgsn_pdp_ctx_by_nsapi(ctx, rab_id); + if (!pdp) { + LOGP(DRANAP, LOGL_ERROR, "RAB Assignment Response for unknown RAB/NSAPI=%u\n", rab_id); + return -1; + } + + if (item->transportLayerAddress) { + LOGPC(DRANAP, LOGL_INFO, " Setup: (%u/%s)", rab_id, osmo_hexdump(item->transportLayerAddress->buf, + item->transportLayerAddress->size)); + switch (item->transportLayerAddress->size) { + case 7: + /* It must be IPv4 inside a X213 NSAP */ + memcpy(pdp->lib->gsnlu.v, &item->transportLayerAddress->buf[3], 4); + break; + case 4: + /* It must be a raw IPv4 address */ + memcpy(pdp->lib->gsnlu.v, item->transportLayerAddress->buf, 4); + break; + case 16: + /* TODO: It must be a raw IPv6 address */ + case 19: + /* TODO: It must be IPv6 inside a X213 NSAP */ + default: + LOGP(DRANAP, LOGL_ERROR, "RAB Assignment Resp: Unknown " + "transport layer address size %u\n", + item->transportLayerAddress->size); + return -1; + } + require_pdp_update = true; + } + + /* The TEI on the RNC side might have changed, too */ + if (item->iuTransportAssociation && + item->iuTransportAssociation->present == RANAP_IuTransportAssociation_PR_gTP_TEI && + item->iuTransportAssociation->choice.gTP_TEI.buf && + item->iuTransportAssociation->choice.gTP_TEI.size >= 4) { + uint32_t tei = osmo_load32be(item->iuTransportAssociation->choice.gTP_TEI.buf); + LOGP(DRANAP, LOGL_DEBUG, "Updating TEID on RNC side from 0x%08x to 0x%08x\n", + pdp->lib->teid_own, tei); + pdp->lib->teid_own = tei; + require_pdp_update = true; + } + + if (require_pdp_update) + gtp_update_context(pdp->ggsn->gsn, pdp->lib, pdp, &pdp->lib->hisaddr0); + + if (pdp->state != PDP_STATE_CR_CONF) { + send_act_pdp_cont_acc(pdp); + pdp->state = PDP_STATE_CR_CONF; + } + return 0; + +} +#endif + /* Confirmation of a PDP Context Delete */ static int delete_pdp_conf(struct pdp_t *pdp, void *cbp, int cause) { diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c index 52fc985..0cea584 100644 --- a/openbsc/src/gprs/sgsn_main.c +++ b/openbsc/src/gprs/sgsn_main.c @@ -56,6 +56,8 @@ #include #include #include +#include + #include #include @@ -300,6 +302,13 @@ .num_cat = ARRAY_SIZE(gprs_categories), }; +/* Implement the extern asn_debug from libasn1c to indicate whether the ASN.1 + * binary code decoded and encoded during Iu communication should be logged to + * stderr. See osmocom's libasn1c, asn_internal.h, at "if (asn_debug)": + * http://git.osmocom.org/libasn1c/tree/include/asn1c/asn_internal.h */ +int asn_debug = 0; + +int sgsn_ranap_iu_event(struct ue_conn_ctx *ctx, enum iu_event_type type, void *data); int main(int argc, char **argv) { @@ -326,6 +335,7 @@ osmo_stats_vty_add_cmds(&gprs_log_info); sgsn_vty_init(); ctrl_vty_init(tall_bsc_ctx); + iu_vty_init(&asn_debug); handle_options(argc, argv); @@ -417,6 +427,10 @@ } } +#ifdef BUILD_IU + iu_init(tall_bsc_ctx, "127.0.0.2", 14001, gsm0408_gprs_rcvmsg_iu, sgsn_ranap_iu_event); +#endif + if (daemonize) { rc = osmo_daemonize(); if (rc < 0) { -- To view, visit https://gerrit.osmocom.org/729 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I469ae6ca9ef254d04ee0d2d79bdd65aebcd027b5 Gerrit-PatchSet: 3 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: daniel Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Mon Aug 29 15:12:01 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 15:12:01 +0000 Subject: [PATCH] openbsc[master]: IuPS: redirect Iu in various places, link Iu in sgsn-test In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/731 to look at the new patch set (#3). IuPS: redirect Iu in various places, link Iu in sgsn-test In gsm48_gmm_sendmsg(), redirect to iu_tx() for both cases of MM context present or not. In gsm48_rx_gmm_att_req(), compose an MM context marked as Iu for messages coming in from a ue_conn_ctx (passed in msg->dst). Also make sure cid is initialized to avoid introducing a compiler warning. In gsm48_rx_gmm_ra_upd_req(), look up an Iu MM context based on the presence of the ue_conn_ctx in msg->dst. In sgsn-test, add libiu and libasn1c, libosmo-sigtran, libosmo-ranap, which are now needed for an --enable-iu build. Change-Id: Ia47ffbfa6fa0f5a0cd76a379c57ef42faa0d80e3 --- M openbsc/src/gprs/gprs_gmm.c M openbsc/tests/sgsn/Makefile.am 2 files changed, 65 insertions(+), 6 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/31/731/3 diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index 4c44224..cc0caf4 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -185,8 +185,21 @@ static int gsm48_gmm_sendmsg(struct msgb *msg, int command, struct sgsn_mm_ctx *mm, bool encryptable) { - if (mm) + if (mm) { rate_ctr_inc(&mm->ctrg->ctr[GMM_CTR_PKTS_SIG_OUT]); +#ifdef BUILD_IU + if (mm->ran_type == MM_CTX_T_UTRAN_Iu) + return iu_tx(msg, GPRS_SAPI_GMM); +#endif + } + +#ifdef BUILD_IU + /* In Iu mode, msg->dst contains the ue_conn_ctx pointer, in Gb mode + * dst is empty. */ + /* FIXME: have a more explicit indicator for Iu messages */ + if (msg->dst) + return iu_tx(msg, GPRS_SAPI_GMM); +#endif /* caller needs to provide TLLI, BVCI and NSEI */ return gprs_llc_tx_ui(msg, GPRS_SAPI_GMM, command, mm, encryptable); @@ -907,7 +920,7 @@ uint32_t tmsi; char mi_string[GSM48_MI_SIZE]; struct gprs_ra_id ra_id; - uint16_t cid; + uint16_t cid = 0; enum gsm48_gmm_cause reject_cause; int rc; @@ -918,7 +931,13 @@ * with a foreign TLLI (P-TMSI that was allocated to the MS before), * or with random TLLI. */ - cid = bssgp_parse_cell_id(&ra_id, msgb_bcid(msg)); + /* In Iu mode, msg->dst contains the ue_conn_ctx pointer, in Gb mode + * dst is empty. */ + /* FIXME: have a more explicit indicator for Iu messages */ + if (!msg->dst) { + /* Gb mode */ + cid = bssgp_parse_cell_id(&ra_id, msgb_bcid(msg)); + } /* MS network capability 10.5.5.12 */ msnc_len = *cur++; @@ -972,7 +991,10 @@ #if 0 return gsm48_tx_gmm_att_rej(msg, GMM_CAUSE_IMSI_UNKNOWN); #else - ctx = sgsn_mm_ctx_alloc(0, &ra_id); + if (msg->dst) + ctx = sgsn_mm_ctx_alloc_iu(msg->dst); + else + ctx = sgsn_mm_ctx_alloc(0, &ra_id); if (!ctx) { reject_cause = GMM_CAUSE_NET_FAIL; goto rejected; @@ -995,7 +1017,10 @@ if (!ctx) { /* Allocate a context as most of our code expects one. * Context will not have an IMSI ultil ID RESP is received */ - ctx = sgsn_mm_ctx_alloc(msgb_tlli(msg), &ra_id); + if (msg->dst) + ctx = sgsn_mm_ctx_alloc_iu(msg->dst); + else + ctx = sgsn_mm_ctx_alloc(msgb_tlli(msg), &ra_id); ctx->p_tmsi = tmsi; } if (ctx->ran_type == MM_CTX_T_GERAN_Gb) { @@ -1272,7 +1297,31 @@ * is an optimization to avoid the RA reject (impl detached) * below, which will cause a new attach cycle. */ /* Look-up the MM context based on old RA-ID and TLLI */ - mmctx = sgsn_mm_ctx_by_tlli_and_ptmsi(msgb_tlli(msg), &old_ra_id); + /* In Iu mode, msg->dst contains the ue_conn_ctx pointer, in Gb + * mode dst is empty. */ + /* FIXME: have a more explicit indicator for Iu messages */ + if (!msg->dst) { + mmctx = sgsn_mm_ctx_by_tlli_and_ptmsi(msgb_tlli(msg), &old_ra_id); + } else if (TLVP_PRESENT(&tp, GSM48_IE_GMM_ALLOC_PTMSI)) { +#ifdef BUILD_IU + /* In Iu mode search only for ptmsi */ + char mi_string[GSM48_MI_SIZE]; + uint8_t mi_len = TLVP_LEN(&tp, GSM48_IE_GMM_ALLOC_PTMSI); + uint8_t *mi = TLVP_VAL(&tp, GSM48_IE_GMM_ALLOC_PTMSI); + uint8_t mi_type = *mi & GSM_MI_TYPE_MASK; + uint32_t tmsi; + + gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len); + + if (mi_type == GSM_MI_TYPE_TMSI) { + memcpy(&tmsi, mi+1, 4); + tmsi = ntohl(tmsi); + mmctx = sgsn_mm_ctx_by_ptmsi(tmsi); + } +#else + goto rejected; +#endif + } if (mmctx) { LOGMMCTXP(LOGL_INFO, mmctx, "Looked up by matching TLLI and P_TMSI. " diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 74af159..ce64429 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -1,5 +1,8 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) +if BUILD_IU +AM_CFLAGS += $(LIBASN1C_CFLAGS) $(LIBOSMOSIGTRAN_CFLAGS) $(LIBOSMORANAP_CFLAGS) +endif EXTRA_DIST = sgsn_test.ok @@ -39,4 +42,11 @@ $(LIBCARES_LIBS) \ $(LIBCRYPTO_LIBS) \ -lgtp -lrt +if BUILD_IU +sgsn_test_LDADD += \ + $(top_builddir)/src/libiu/libiu.a \ + $(LIBOSMORANAP_LIBS) \ + $(LIBOSMOSIGTRAN_LIBS) \ + $(LIBASN1C_LIBS) +endif -- To view, visit https://gerrit.osmocom.org/731 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia47ffbfa6fa0f5a0cd76a379c57ef42faa0d80e3 Gerrit-PatchSet: 3 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: daniel Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Mon Aug 29 15:12:02 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 15:12:02 +0000 Subject: [PATCH] openbsc[master]: IuPS: add VTY config for asn_debug Message-ID: Review at https://gerrit.osmocom.org/790 IuPS: add VTY config for asn_debug Add file iu_vty.c in libiu, and iu_vty_init() to initialize the new VTY command: log logging asn1-debug (on|off) Change-Id: If4e7d0ab3fc2ed0cdf4fb0a3fa077a9e34890918 --- M openbsc/include/openbsc/iu.h M openbsc/src/libiu/Makefile.am A openbsc/src/libiu/iu_vty.c 3 files changed, 51 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/90/790/1 diff --git a/openbsc/include/openbsc/iu.h b/openbsc/include/openbsc/iu.h index d0ab540..f973ac1 100644 --- a/openbsc/include/openbsc/iu.h +++ b/openbsc/include/openbsc/iu.h @@ -58,3 +58,5 @@ int iu_rab_deact(struct ue_conn_ctx *ue_ctx, uint8_t rab_id); int iu_tx_sec_mode_cmd(struct ue_conn_ctx *uectx, struct gsm_auth_tuple *tp, int send_ck, int new_key); + +void iu_vty_init(int *asn_debug_p); diff --git a/openbsc/src/libiu/Makefile.am b/openbsc/src/libiu/Makefile.am index 7b1ba4d..1968d3e 100644 --- a/openbsc/src/libiu/Makefile.am +++ b/openbsc/src/libiu/Makefile.am @@ -6,5 +6,5 @@ noinst_LIBRARIES = libiu.a -libiu_a_SOURCES = iu.c +libiu_a_SOURCES = iu.c iu_vty.c diff --git a/openbsc/src/libiu/iu_vty.c b/openbsc/src/libiu/iu_vty.c new file mode 100644 index 0000000..85464b3 --- /dev/null +++ b/openbsc/src/libiu/iu_vty.c @@ -0,0 +1,48 @@ +/* OpenBSC Iu related interface to quagga VTY */ +/* (C) 2016 by sysmocom s.m.f.c. GmbH + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include + +/* Pointer to the actual asn_debug value as passed from main scopes. */ +static int *g_asn_debug_p = NULL; + +DEFUN(logging_asn_debug, + logging_asn_debug_cmd, + "logging asn1-debug (on|off)", + LOGGING_STR + "Log human readable representations of all ASN.1 messages to stderr\n" + "Log decoded ASN.1 messages\n" + "Do not log decoded ASN.1 messages\n") +{ + if (!g_asn_debug_p) { + vty_out(vty, "%%ASN.1 debugging not available%s", VTY_NEWLINE); + return CMD_WARNING; + } + + *g_asn_debug_p = strcmp(argv[0], "on")? 0 : 1; + return CMD_SUCCESS; +} + +void iu_vty_init(int *asn_debug_p) +{ + g_asn_debug_p = asn_debug_p; + + install_element(CFG_LOG_NODE, &logging_asn_debug_cmd); +} -- To view, visit https://gerrit.osmocom.org/790 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: If4e7d0ab3fc2ed0cdf4fb0a3fa077a9e34890918 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 29 15:15:39 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 15:15:39 +0000 Subject: openbsc[master]: IuPS: osmo-sgsn: add core IuPS impl, call iu_init() In-Reply-To: References: Message-ID: Patch Set 3: Added a comment. Added a VTY command in new predecessor https://gerrit.osmocom.org/790 called here from sgsn_main.c. -- To view, visit https://gerrit.osmocom.org/729 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I469ae6ca9ef254d04ee0d2d79bdd65aebcd027b5 Gerrit-PatchSet: 3 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: daniel Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 29 15:16:49 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 15:16:49 +0000 Subject: [MERGED] openbsc[master]: IuPS: track msg->dst aka ue_conn_ctx, comment In-Reply-To: References: Message-ID: Neels Hofmeyr has submitted this change and it was merged. Change subject: IuPS: track msg->dst aka ue_conn_ctx, comment ...................................................................... IuPS: track msg->dst aka ue_conn_ctx, comment For Iu connections, msg->dst will point to the ue_conn_ctx, and we need to make sure to keep msg->dst intact when copying from/to msgb and from/to MM context. Change-Id: I90c7ca6c3655d447aaca958e0086ae6ce6f6045a --- M openbsc/src/gprs/gprs_gmm.c 1 file changed, 4 insertions(+), 0 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index efa25c6..1efada9 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -150,6 +150,7 @@ msgb_tlli(msg) = msgb_tlli(old); msgb_bvci(msg) = msgb_bvci(old); msgb_nsei(msg) = msgb_nsei(old); + msg->dst = old->dst; } /* Store BVCI/NSEI in MM context */ @@ -157,6 +158,8 @@ { mm->gb.bvci = msgb_bvci(msg); mm->gb.nsei = msgb_nsei(msg); + /* In case a Iu connection is reconnected we need to update the ue ctx */ + mm->iu.ue_ctx = msg->dst; } /* Store BVCI/NSEI in MM context */ @@ -165,6 +168,7 @@ msgb_tlli(msg) = mm->gb.tlli; msgb_bvci(msg) = mm->gb.bvci; msgb_nsei(msg) = mm->gb.nsei; + msg->dst = mm->iu.ue_ctx; } static void mm_ctx_cleanup_free(struct sgsn_mm_ctx *ctx, const char *log_text) -- To view, visit https://gerrit.osmocom.org/728 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I90c7ca6c3655d447aaca958e0086ae6ce6f6045a Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: daniel Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Mon Aug 29 15:16:49 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 15:16:49 +0000 Subject: [MERGED] openbsc[master]: gprs_gmm: Fix bit mask when determining update/attach type In-Reply-To: References: Message-ID: Neels Hofmeyr has submitted this change and it was merged. Change subject: gprs_gmm: Fix bit mask when determining update/attach type ...................................................................... gprs_gmm: Fix bit mask when determining update/attach type Bit 4 is reserved in 3GPP TS 04.08 so exclude it from the type. In 3GPP TS 24.008 it indicates if a follow-on request is pending by the MS, but only in Iu mode. According to the spec it is not required to react to that request with a follow-on proceed so this field can be ignored for now. See 3GPP TS 24.008 Ch. 4.4: "Unless it has specific permission from the network (follow-on proceed) the mobile station side should await the release of the RR connection used for a MM specific procedure before a new MM specific procedure or MM connection establishment is started." as well as Ch. 4.4.4.6: "If the network wishes to prolong the RR connection to allow the mobile station to initiate MM connection establishment (for example if the mobile station has indicated in the LOCATION UPDATING REQUEST that it has a follow-on request pending) the network shall send "follow on proceed" in the LOCATION UPDATING ACCEPT and start timer T3255." Change-Id: If1dff960c406060e257dafc54132687ffc42ad8f --- M openbsc/src/gprs/gprs_gmm.c 1 file changed, 6 insertions(+), 2 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index 036164f..efa25c6 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -874,8 +874,10 @@ goto err_inval; cur += msnc_len; + /* TODO: In iu mode - handle follow-on request */ + /* aTTACH Type 10.5.5.2 */ - att_type = *cur++ & 0x0f; + att_type = *cur++ & 0x07; /* DRX parameter 10.5.5.6 */ drx_par = *cur++ << 8; @@ -1171,8 +1173,10 @@ enum gsm48_gmm_cause reject_cause; int rc; + /* TODO: In iu mode - handle follow-on request */ + /* Update Type 10.5.5.18 */ - upd_type = *cur++ & 0x0f; + upd_type = *cur++ & 0x07; rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ROUTING_AREA_REQUEST]); LOGP(DMM, LOGL_INFO, "-> GMM RA UPDATE REQUEST type=\"%s\"\n", -- To view, visit https://gerrit.osmocom.org/727 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: If1dff960c406060e257dafc54132687ffc42ad8f Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: daniel Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Mon Aug 29 15:16:49 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 15:16:49 +0000 Subject: [MERGED] openbsc[master]: cosmetic: gprs_sgsn.c: move pdp.h include to top In-Reply-To: References: Message-ID: Neels Hofmeyr has submitted this change and it was merged. Change subject: cosmetic: gprs_sgsn.c: move pdp.h include to top ...................................................................... cosmetic: gprs_sgsn.c: move pdp.h include to top Change-Id: I9a9b34d714235462ba72cdb65b7c8c9824dfa9c6 --- M openbsc/src/gprs/gprs_sgsn.c 1 file changed, 2 insertions(+), 1 deletion(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/openbsc/src/gprs/gprs_sgsn.c b/openbsc/src/gprs/gprs_sgsn.c index 038e6f0..9cd992b 100644 --- a/openbsc/src/gprs/gprs_sgsn.c +++ b/openbsc/src/gprs/gprs_sgsn.c @@ -40,6 +40,8 @@ #include #include "openbsc/gprs_llc.h" +#include + #include #include @@ -337,7 +339,6 @@ return pdp; } -#include /* * This function will not trigger any GSM DEACT PDP ACK messages, so you * probably want to call sgsn_delete_pdp_ctx() instead if the connection -- To view, visit https://gerrit.osmocom.org/726 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I9a9b34d714235462ba72cdb65b7c8c9824dfa9c6 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Mon Aug 29 15:16:49 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 15:16:49 +0000 Subject: [MERGED] openbsc[master]: add libiu In-Reply-To: References: Message-ID: Neels Hofmeyr has submitted this change and it was merged. Change subject: add libiu ...................................................................... add libiu Co-Authored by dwillmann, laforge, nhofmeyr Change-Id: Iffc26f9c73cb15463948f7435b72ac1747aabdb3 --- M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/iu.h M openbsc/src/Makefile.am A openbsc/src/libiu/Makefile.am A openbsc/src/libiu/iu.c 6 files changed, 844 insertions(+), 3 deletions(-) Approvals: Neels Hofmeyr: Looks good to me, approved Jenkins Builder: Verified diff --git a/openbsc/configure.ac b/openbsc/configure.ac index fbf2930..f63d61f 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -203,6 +203,7 @@ src/libmgcp/Makefile src/libcommon/Makefile src/libfilter/Makefile + src/libiu/Makefile src/osmo-nitb/Makefile src/osmo-bsc/Makefile src/osmo-bsc_nat/Makefile diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index ce5f768..90aa364 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,8 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_llc_xid.h gprs_sndcp.h + gtphub.h gprs_llc_xid.h gprs_sndcp.h \ + iu.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/iu.h b/openbsc/include/openbsc/iu.h new file mode 100644 index 0000000..d0ab540 --- /dev/null +++ b/openbsc/include/openbsc/iu.h @@ -0,0 +1,60 @@ +#pragma once + +#include + +struct sgsn_pdp_ctx; +struct msgb; +struct gprs_ra_id; + +struct RANAP_RAB_SetupOrModifiedItemIEs_s; +struct RANAP_GlobalRNC_ID; + +struct ue_conn_ctx { + struct llist_head list; + struct osmo_sccp_link *link; + uint32_t conn_id; + int integrity_active; + struct gprs_ra_id ra_id; +}; + +enum iu_event_type { + IU_EVENT_RAB_ASSIGN, + IU_EVENT_SECURITY_MODE_COMPLETE, + IU_EVENT_IU_RELEASE, /* An actual Iu Release message was received */ + IU_EVENT_LINK_INVALIDATED, /* A SUA link was lost or closed down */ + /* FIXME: maybe IU_EVENT_IU_RELEASE and IU_EVENT_LINK_INVALIDATED + * should be combined to one generic event that simply means the + * ue_conn_ctx should no longer be used, for whatever reason. */ +}; + +extern const struct value_string iu_event_type_names[]; +static inline const char *iu_event_type_str(enum iu_event_type e) +{ + return get_value_string(iu_event_type_names, e); +} + +/* Implementations of iu_recv_cb_t shall find the ue_conn_ctx in msg->dst. */ +typedef int (* iu_recv_cb_t )(struct msgb *msg, struct gprs_ra_id *ra_id, + /* TODO "gprs_" in generic CS+PS domain ^ */ + uint16_t *sai); + +typedef int (* iu_event_cb_t )(struct ue_conn_ctx *ue_ctx, + enum iu_event_type type, void *data); + +typedef int (* iu_rab_ass_resp_cb_t )(struct ue_conn_ctx *ue_ctx, uint8_t rab_id, + struct RANAP_RAB_SetupOrModifiedItemIEs_s *setup_ies); + +int iu_init(void *ctx, const char *listen_addr, uint16_t listen_port, + iu_recv_cb_t iu_recv_cb, iu_event_cb_t iu_event_cb); + +void iu_link_del(struct osmo_sccp_link *link); + +int iu_tx(struct msgb *msg, uint8_t sapi); + +int iu_page_cs(const char *imsi, const uint32_t *tmsi, uint16_t lac); +int iu_page_ps(const char *imsi, const uint32_t *ptmsi, uint16_t lac, uint8_t rac); + +int iu_rab_act(struct ue_conn_ctx *ue_ctx, struct msgb *msg); +int iu_rab_deact(struct ue_conn_ctx *ue_ctx, uint8_t rab_id); +int iu_tx_sec_mode_cmd(struct ue_conn_ctx *uectx, struct gsm_auth_tuple *tp, + int send_ck, int new_key); diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 6f6174e..4aa880f 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -2,9 +2,18 @@ AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(COVERAGE_CFLAGS) AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(COVERAGE_LDFLAGS) -SUBDIRS = libcommon libmgcp libbsc libmsc libtrau libfilter osmo-nitb osmo-bsc_mgcp utils ipaccess gprs +# Libraries +SUBDIRS = libcommon libmgcp libbsc libmsc libtrau libfilter -# Conditional modules +# Conditional Libraries +if BUILD_IU +SUBDIRS += libiu +endif + +# Programs +SUBDIRS += osmo-nitb osmo-bsc_mgcp utils ipaccess gprs + +# Conditional Programs if BUILD_NAT SUBDIRS += osmo-bsc_nat endif diff --git a/openbsc/src/libiu/Makefile.am b/openbsc/src/libiu/Makefile.am new file mode 100644 index 0000000..7b1ba4d --- /dev/null +++ b/openbsc/src/libiu/Makefile.am @@ -0,0 +1,10 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) +AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) \ + $(LIBOSMOGSM_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) $(LIBCRYPTO_CFLAGS) \ + $(LIBASN1C_CFLAGS) \ + $(LIBOSMOSIGTRAN_CFLAGS) $(LIBOSMORANAP_CFLAGS) + +noinst_LIBRARIES = libiu.a + +libiu_a_SOURCES = iu.c + diff --git a/openbsc/src/libiu/iu.c b/openbsc/src/libiu/iu.c new file mode 100644 index 0000000..837385e --- /dev/null +++ b/openbsc/src/libiu/iu.c @@ -0,0 +1,760 @@ +/* Common parts of IuCS and IuPS interfaces implementation */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +/* Parsed global RNC id. See also struct RANAP_GlobalRNC_ID, and note that the + * PLMN identity is a BCD representation of the MCC and MNC. + * See iu_grnc_id_parse(). */ +struct iu_grnc_id { + uint16_t mcc; + uint16_t mnc; + uint16_t rnc_id; +}; + +/* A remote RNC (Radio Network Controller, like BSC but for UMTS) that has + * called us and is currently reachable at the given osmo_sccp_link. So, when we + * know a LAC for a subscriber, we can page it at the RNC matching that LAC or + * RAC. An HNB-GW typically presents itself as if it were a single RNC, even + * though it may have several RNCs in hNodeBs connected to it. Those will then + * share the same RNC id, which they actually receive and adopt from the HNB-GW + * in the HNBAP HNB REGISTER ACCEPT message. */ +struct iu_rnc { + struct llist_head entry; + + uint16_t rnc_id; + uint16_t lac; /* Location Area Code (used for CS and PS) */ + uint8_t rac; /* Routing Area Code (used for PS only) */ + struct osmo_sccp_link *link; +}; + +void *talloc_iu_ctx; + +int asn1_xer_print = 1; +void *talloc_asn1_ctx; + +iu_recv_cb_t global_iu_recv_cb = NULL; +iu_event_cb_t global_iu_event_cb = NULL; + +static LLIST_HEAD(ue_conn_ctx_list); +static LLIST_HEAD(rnc_list); + +const struct value_string iu_event_type_names[] = { +#define IU_EVT_STR(X) { X, #X } + IU_EVT_STR(IU_EVENT_RAB_ASSIGN), + IU_EVT_STR(IU_EVENT_SECURITY_MODE_COMPLETE), + IU_EVT_STR(IU_EVENT_IU_RELEASE), + IU_EVT_STR(IU_EVENT_LINK_INVALIDATED), +#undef IU_EVT_STR +}; + +struct ue_conn_ctx *ue_conn_ctx_alloc(struct osmo_sccp_link *link, uint32_t conn_id) +{ + struct ue_conn_ctx *ctx = talloc_zero(talloc_iu_ctx, struct ue_conn_ctx); + + ctx->link = link; + ctx->conn_id = conn_id; + llist_add(&ctx->list, &ue_conn_ctx_list); + + return ctx; +} + +struct ue_conn_ctx *ue_conn_ctx_find(struct osmo_sccp_link *link, + uint32_t conn_id) +{ + struct ue_conn_ctx *ctx; + + llist_for_each_entry(ctx, &ue_conn_ctx_list, list) { + if (ctx->link == link && ctx->conn_id == conn_id) + return ctx; + } + return NULL; +} + +static struct iu_rnc *iu_rnc_alloc(uint16_t rnc_id, uint16_t lac, uint8_t rac, + struct osmo_sccp_link *link) +{ + struct iu_rnc *rnc = talloc_zero(talloc_iu_ctx, struct iu_rnc); + + rnc->rnc_id = rnc_id; + rnc->lac = lac; + rnc->rac = rac; + rnc->link = link; + llist_add(&rnc->entry, &rnc_list); + + LOGP(DRANAP, LOGL_NOTICE, "New RNC %d (LAC=%d RAC=%d)\n", + rnc->rnc_id, rnc->lac, rnc->rac); + + return rnc; +} + +static struct iu_rnc *iu_rnc_register(uint16_t rnc_id, uint16_t lac, + uint8_t rac, struct osmo_sccp_link *link) +{ + struct iu_rnc *rnc; + llist_for_each_entry(rnc, &rnc_list, entry) { + if (rnc->rnc_id != rnc_id) + continue; + + /* We have this RNC Id registered already. Make sure that the + * details match. */ + + /* TODO should a mismatch be an error? */ + if (rnc->lac != lac || rnc->rac != rac) + LOGP(DRANAP, LOGL_NOTICE, "RNC %d changes its details:" + " LAC=%d RAC=%d --> LAC=%d RAC=%d\n", + rnc->rnc_id, rnc->lac, rnc->rac, + lac, rac); + rnc->lac = lac; + rnc->rac = rac; + + if (link && rnc->link != link) + LOGP(DRANAP, LOGL_NOTICE, "RNC %d on new link" + " (LAC=%d RAC=%d)\n", + rnc->rnc_id, rnc->lac, rnc->rac); + rnc->link = link; + return rnc; + } + + /* Not found, make a new one. */ + return iu_rnc_alloc(rnc_id, lac, rac, link); +} + +/* Discard/invalidate all ue_conn_ctx and iu_rnc entries that reference the + * given link, since this link is invalid and about to be deallocated. For + * each ue_conn_ctx, invoke the iu_event_cb_t with IU_EVENT_LINK_INVALIDATED. + */ +void iu_link_del(struct osmo_sccp_link *link) +{ + struct iu_rnc *rnc, *rnc_next; + llist_for_each_entry_safe(rnc, rnc_next, &rnc_list, entry) { + if (!rnc->link) + continue; + if (rnc->link != link) + continue; + rnc->link = NULL; + llist_del(&rnc->entry); + talloc_free(rnc); + } + + struct ue_conn_ctx *uec, *uec_next; + llist_for_each_entry_safe(uec, uec_next, &ue_conn_ctx_list, list) { + if (uec->link != link) + continue; + uec->link = NULL; + global_iu_event_cb(uec, IU_EVENT_LINK_INVALIDATED, NULL); + } +} + +/*********************************************************************** + * RANAP handling + ***********************************************************************/ + +int iu_rab_act(struct ue_conn_ctx *ue_ctx, struct msgb *msg) +{ + struct osmo_scu_prim *prim; + + /* wrap RANAP message in SCCP N-DATA.req */ + prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim)); + prim->u.data.conn_id = ue_ctx->conn_id; + osmo_prim_init(&prim->oph, + SCCP_SAP_USER, + OSMO_SCU_PRIM_N_DATA, + PRIM_OP_REQUEST, + msg); + return osmo_sua_user_link_down(ue_ctx->link, &prim->oph); +} + +int iu_rab_deact(struct ue_conn_ctx *ue_ctx, uint8_t rab_id) +{ + /* FIXME */ + return -1; +} + +int iu_tx_sec_mode_cmd(struct ue_conn_ctx *uectx, struct gsm_auth_tuple *tp, + int send_ck, int new_key) +{ + struct osmo_scu_prim *prim; + struct msgb *msg; + uint8_t ik[16]; + uint8_t ck[16]; + unsigned int i; + + /* C5 function to derive IK from Kc */ + for (i = 0; i < 4; i++) + ik[i] = tp->vec.kc[i] ^ tp->vec.kc[i+4]; + memcpy(ik+4, tp->vec.kc, 8); + for (i = 12; i < 16; i++) + ik[i] = ik[i-12]; + + if (send_ck) { + /* C4 function to derive CK from Kc */ + memcpy(ck, tp->vec.kc, 8); + memcpy(ck+8, tp->vec.kc, 8); + } + + /* create RANAP message */ + msg = ranap_new_msg_sec_mod_cmd(ik, send_ck? ck : NULL, new_key ? RANAP_KeyStatus_new : RANAP_KeyStatus_old); + msg->l2h = msg->data; + /* wrap RANAP message in SCCP N-DATA.req */ + prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim)); + prim->u.data.conn_id = uectx->conn_id; + osmo_prim_init(&prim->oph, SCCP_SAP_USER, + OSMO_SCU_PRIM_N_DATA, + PRIM_OP_REQUEST, msg); + osmo_sua_user_link_down(uectx->link, &prim->oph); + + return 0; +} + +static int iu_grnc_id_parse(struct iu_grnc_id *dst, + struct RANAP_GlobalRNC_ID *src) +{ + /* The size is coming from arbitrary sender, check it gracefully */ + if (src->pLMNidentity.size != 3) { + LOGP(DRANAP, LOGL_ERROR, "Invalid PLMN Identity size:" + " should be 3, is %d\n", src->pLMNidentity.size); + return -1; + } + gsm48_mcc_mnc_from_bcd(&src->pLMNidentity.buf[0], + &dst->mcc, &dst->mnc); + dst->rnc_id = (uint16_t)src->rNC_ID; + return 0; +} + +#if 0 + -- not used at present -- +static int iu_grnc_id_compose(struct iu_grnc_id *src, + struct RANAP_GlobalRNC_ID *dst) +{ + /* The caller must ensure proper size */ + OSMO_ASSERT(dst->pLMNidentity.size == 3); + gsm48_mcc_mnc_to_bcd(&dst->pLMNidentity.buf[0], + src->mcc, src->mnc); + dst->rNC_ID = src->rnc_id; + return 0; +} +#endif + +static int ranap_handle_co_initial_ue(void *ctx, RANAP_InitialUE_MessageIEs_t *ies) +{ + struct ue_conn_ctx *ue_conn = ctx; + struct gprs_ra_id ra_id; + struct iu_grnc_id grnc_id; + uint16_t sai; + struct msgb *msg = msgb_alloc(256, "RANAP->NAS"); + + if (ranap_parse_lai(&ra_id, &ies->lai) != 0) { + LOGP(DRANAP, LOGL_ERROR, "Failed to parse RANAP LAI IE\n"); + return -1; + } + + if (ies->presenceMask & INITIALUE_MESSAGEIES_RANAP_RAC_PRESENT) { + ra_id.rac = asn1str_to_u8(&ies->rac); + } + + if (iu_grnc_id_parse(&grnc_id, &ies->globalRNC_ID) != 0) { + LOGP(DRANAP, LOGL_ERROR, + "Failed to parse RANAP Global-RNC-ID IE\n"); + return -1; + } + + sai = asn1str_to_u16(&ies->sai.sAC); + msgb_gmmh(msg) = msgb_put(msg, ies->nas_pdu.size); + memcpy(msgb_gmmh(msg), ies->nas_pdu.buf, ies->nas_pdu.size); + + /* Make sure we know the RNC Id and LAC+RAC coming in on this connection. */ + iu_rnc_register(grnc_id.rnc_id, ra_id.lac, ra_id.rac, ue_conn->link); + ue_conn->ra_id = ra_id; + + /* Feed into the MM layer */ + msg->dst = ctx; + global_iu_recv_cb(msg, &ra_id, &sai); + + msgb_free(msg); + + return 0; +} + +static int ranap_handle_co_dt(void *ctx, RANAP_DirectTransferIEs_t *ies) +{ + struct gprs_ra_id _ra_id, *ra_id = NULL; + uint16_t _sai, *sai = NULL; + struct msgb *msg = msgb_alloc(256, "RANAP->NAS"); + + if (ies->presenceMask & DIRECTTRANSFERIES_RANAP_LAI_PRESENT) { + if (ranap_parse_lai(&_ra_id, &ies->lai) != 0) { + LOGP(DRANAP, LOGL_ERROR, "Failed to parse RANAP LAI IE\n"); + return -1; + } + ra_id = &_ra_id; + if (ies->presenceMask & DIRECTTRANSFERIES_RANAP_RAC_PRESENT) { + _ra_id.rac = asn1str_to_u8(&ies->rac); + } + if (ies->presenceMask & DIRECTTRANSFERIES_RANAP_SAI_PRESENT) { + _sai = asn1str_to_u16(&ies->sai.sAC); + sai = &_sai; + } + } + + msgb_gmmh(msg) = msgb_put(msg, ies->nas_pdu.size); + memcpy(msgb_gmmh(msg), ies->nas_pdu.buf, ies->nas_pdu.size); + + /* Feed into the MM/CC/SMS-CP layer */ + msg->dst = ctx; + global_iu_recv_cb(msg, ra_id, sai); + + msgb_free(msg); + + return 0; +} + +static int ranap_handle_co_err_ind(void *ctx, RANAP_ErrorIndicationIEs_t *ies) +{ + if (ies->presenceMask & ERRORINDICATIONIES_RANAP_CAUSE_PRESENT) + LOGP(DRANAP, LOGL_ERROR, "Rx Error Indication (%s)\n", + ranap_cause_str(&ies->cause)); + else + LOGP(DRANAP, LOGL_ERROR, "Rx Error Indication\n"); + + return 0; +} + +int iu_tx(struct msgb *msg_nas, uint8_t sapi) +{ + struct ue_conn_ctx *uectx = msg_nas->dst; + struct msgb *msg; + struct osmo_scu_prim *prim; + + LOGP(DRANAP, LOGL_INFO, "Transmitting L3 Message as RANAP DT (SUA link %p conn_id %u)\n", + uectx->link, uectx->conn_id); + + msg = ranap_new_msg_dt(sapi, msg_nas->data, msgb_length(msg_nas)); + msgb_free(msg_nas); + msg->l2h = msg->data; + prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim)); + prim->u.data.conn_id = uectx->conn_id; + osmo_prim_init(&prim->oph, SCCP_SAP_USER, + OSMO_SCU_PRIM_N_DATA, + PRIM_OP_REQUEST, msg); + osmo_sua_user_link_down(uectx->link, &prim->oph); + return 0; +} + +static int ranap_handle_co_iu_rel_req(struct ue_conn_ctx *ctx, RANAP_Iu_ReleaseRequestIEs_t *ies) +{ + struct msgb *msg; + struct osmo_scu_prim *prim; + + LOGP(DRANAP, LOGL_INFO, "Received Iu Release Request, Sending Release Command\n"); + msg = ranap_new_msg_iu_rel_cmd(&ies->cause); + msg->l2h = msg->data; + prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim)); + prim->u.data.conn_id = ctx->conn_id; + osmo_prim_init(&prim->oph, SCCP_SAP_USER, + OSMO_SCU_PRIM_N_DATA, + PRIM_OP_REQUEST, msg); + osmo_sua_user_link_down(ctx->link, &prim->oph); + return 0; +} + +static int ranap_handle_co_rab_ass_resp(struct ue_conn_ctx *ctx, RANAP_RAB_AssignmentResponseIEs_t *ies) +{ + int rc = -1; + + LOGP(DRANAP, LOGL_INFO, "RAB Asignment Response:"); + if (ies->presenceMask & RAB_ASSIGNMENTRESPONSEIES_RANAP_RAB_SETUPORMODIFIEDLIST_PRESENT) { + /* TODO: Iterate over list of SetupOrModifiedList IEs and handle each one */ + RANAP_IE_t *ranap_ie = ies->raB_SetupOrModifiedList.raB_SetupOrModifiedList_ies.list.array[0]; + RANAP_RAB_SetupOrModifiedItemIEs_t setup_ies; + + rc = ranap_decode_rab_setupormodifieditemies_fromlist(&setup_ies, &ranap_ie->value); + if (rc) { + LOGP(DRANAP, LOGL_ERROR, "Error in ranap_decode_rab_setupormodifieditemies()\n"); + return rc; + } + + rc = global_iu_event_cb(ctx, IU_EVENT_RAB_ASSIGN, &setup_ies); + + ranap_free_rab_setupormodifieditemies(&setup_ies); + } + + LOGPC(DRANAP, LOGL_INFO, "\n"); + + return rc; +} + +/* Entry point for connection-oriented RANAP message */ +static void cn_ranap_handle_co(void *ctx, ranap_message *message) +{ + int rc; + + LOGP(DRANAP, LOGL_NOTICE, "handle_co(dir=%u, proc=%u)\n", message->direction, message->procedureCode); + + switch (message->direction) { + case RANAP_RANAP_PDU_PR_initiatingMessage: + switch (message->procedureCode) { + case RANAP_ProcedureCode_id_InitialUE_Message: + rc = ranap_handle_co_initial_ue(ctx, &message->msg.initialUE_MessageIEs); + break; + case RANAP_ProcedureCode_id_DirectTransfer: + rc = ranap_handle_co_dt(ctx, &message->msg.directTransferIEs); + break; + case RANAP_ProcedureCode_id_ErrorIndication: + rc = ranap_handle_co_err_ind(ctx, &message->msg.errorIndicationIEs); + break; + case RANAP_ProcedureCode_id_Iu_ReleaseRequest: + /* Iu Release Request */ + rc = ranap_handle_co_iu_rel_req(ctx, &message->msg.iu_ReleaseRequestIEs); + break; + default: + LOGP(DRANAP, LOGL_ERROR, "Received Initiating Message: unknown Procedure Code %d\n", + message->procedureCode); + rc = -1; + break; + } + break; + case RANAP_RANAP_PDU_PR_successfulOutcome: + switch (message->procedureCode) { + case RANAP_ProcedureCode_id_SecurityModeControl: + /* Security Mode Complete */ + rc = global_iu_event_cb(ctx, IU_EVENT_SECURITY_MODE_COMPLETE, NULL); + break; + case RANAP_ProcedureCode_id_Iu_Release: + /* Iu Release Complete */ + rc = global_iu_event_cb(ctx, IU_EVENT_IU_RELEASE, NULL); + if (rc) { + LOGP(DRANAP, LOGL_ERROR, "Iu Release event: Iu Event callback returned %d\n", + rc); + } + break; + default: + LOGP(DRANAP, LOGL_ERROR, "Received Successful Outcome: unknown Procedure Code %d\n", + message->procedureCode); + rc = -1; + break; + } + break; + case RANAP_RANAP_PDU_PR_outcome: + switch (message->procedureCode) { + case RANAP_ProcedureCode_id_RAB_Assignment: + /* RAB Assignment Response */ + rc = ranap_handle_co_rab_ass_resp(ctx, &message->msg.raB_AssignmentResponseIEs); + break; + default: + LOGP(DRANAP, LOGL_ERROR, "Received Outcome: unknown Procedure Code %d\n", + message->procedureCode); + rc = -1; + break; + } + break; + case RANAP_RANAP_PDU_PR_unsuccessfulOutcome: + default: + LOGP(DRANAP, LOGL_ERROR, "Received Unsuccessful Outcome: Procedure Code %d\n", + message->procedureCode); + rc = -1; + break; + } + + if (rc) { + LOGP(DRANAP, LOGL_ERROR, "Error in cn_ranap_handle_co (%d)\n", + rc); + /* TODO handling of the error? */ + } +} + +static int ranap_handle_cl_reset_req(void *ctx, RANAP_ResetIEs_t *ies) +{ + /* FIXME: send reset response */ + return -1; +} + +static int ranap_handle_cl_err_ind(void *ctx, RANAP_ErrorIndicationIEs_t *ies) +{ + if (ies->presenceMask & ERRORINDICATIONIES_RANAP_CAUSE_PRESENT) + LOGP(DRANAP, LOGL_ERROR, "Rx Error Indication (%s)\n", + ranap_cause_str(&ies->cause)); + else + LOGP(DRANAP, LOGL_ERROR, "Rx Error Indication\n"); + + return 0; +} + +/* Entry point for connection-less RANAP message */ +static void cn_ranap_handle_cl(void *ctx, ranap_message *message) +{ + int rc; + + switch (message->direction) { + case RANAP_RANAP_PDU_PR_initiatingMessage: + switch (message->procedureCode) { + case RANAP_ProcedureCode_id_Reset: + /* received reset.req, send reset.resp */ + rc = ranap_handle_cl_reset_req(ctx, &message->msg.resetIEs); + break; + case RANAP_ProcedureCode_id_ErrorIndication: + rc = ranap_handle_cl_err_ind(ctx, &message->msg.errorIndicationIEs); + break; + default: + rc = -1; + break; + } + break; + case RANAP_RANAP_PDU_PR_successfulOutcome: + case RANAP_RANAP_PDU_PR_unsuccessfulOutcome: + case RANAP_RANAP_PDU_PR_outcome: + default: + rc = -1; + break; + } + + if (rc) { + LOGP(DRANAP, LOGL_ERROR, "Error in cn_ranap_handle_cl (%d)\n", + rc); + /* TODO handling of the error? */ + } +} + +/*********************************************************************** + * Paging + ***********************************************************************/ + +/* Send a paging command down a given SUA link. tmsi and paging_cause are + * optional and may be passed NULL and 0, respectively, to disable their use. + * See enum RANAP_PagingCause. + * + * If TMSI is given, the IMSI is not sent over the air interface. Nevertheless, + * the IMSI is still required for resolution in the HNB-GW and/or(?) RNC. */ +static int iu_tx_paging_cmd(struct osmo_sccp_link *link, + const char *imsi, const uint32_t *tmsi, + bool is_ps, uint32_t paging_cause) +{ + struct msgb *msg; + msg = ranap_new_msg_paging_cmd(imsi, tmsi, is_ps? 1 : 0, paging_cause); + msg->l2h = msg->data; + return osmo_sccp_tx_unitdata_ranap(link, 1, 2, msg->data, + msgb_length(msg)); +} + +static int iu_page(const char *imsi, const uint32_t *tmsi_or_ptimsi, + uint16_t lac, uint8_t rac, bool is_ps) +{ + struct iu_rnc *rnc; + int pagings_sent = 0; + + if (tmsi_or_ptimsi) { + LOGP(DRANAP, LOGL_DEBUG, "%s: Looking for RNCs to page for IMSI %s" + " (paging will use %s %x)\n", + is_ps? "IuPS" : "IuCS", + imsi, + is_ps? "PTMSI" : "TMSI", + *tmsi_or_ptimsi); + } else { + LOGP(DRANAP, LOGL_DEBUG, "%s: Looking for RNCs to page for IMSI %s" + " (paging will use IMSI)\n", + is_ps? "IuPS" : "IuCS", + imsi + ); + } + + llist_for_each_entry(rnc, &rnc_list, entry) { + if (!rnc->link) { + /* Not actually connected, don't count it. */ + continue; + } + if (rnc->lac != lac) + continue; + if (is_ps && rnc->rac != rac) + continue; + + /* Found a match! */ + if (iu_tx_paging_cmd(rnc->link, imsi, tmsi_or_ptimsi, is_ps, 0) + == 0) { + LOGP(DRANAP, LOGL_DEBUG, + "%s: Paged for IMSI %s on RNC %d, on SUA link %p\n", + is_ps? "IuPS" : "IuCS", + imsi, rnc->rnc_id, rnc->link); + pagings_sent ++; + } + } + + /* Some logging... */ + if (pagings_sent > 0) { + LOGP(DRANAP, LOGL_DEBUG, + "%s: %d RNCs were paged for IMSI %s.\n", + is_ps? "IuPS" : "IuCS", + pagings_sent, imsi); + } + else { + if (is_ps) { + LOGP(DRANAP, LOGL_ERROR, "IuPS: Found no RNC to page for" + " LAC %d RAC %d (would have paged IMSI %s)\n", + lac, rac, imsi); + } + else { + LOGP(DRANAP, LOGL_ERROR, "IuCS: Found no RNC to page for" + " LAC %d (would have paged IMSI %s)\n", + lac, imsi); + } + } + + return pagings_sent; +} + +int iu_page_cs(const char *imsi, const uint32_t *tmsi, uint16_t lac) +{ + return iu_page(imsi, tmsi, lac, 0, false); +} + +int iu_page_ps(const char *imsi, const uint32_t *ptmsi, uint16_t lac, uint8_t rac) +{ + return iu_page(imsi, ptmsi, lac, rac, true); +} + + +/*********************************************************************** + * + ***********************************************************************/ + +int tx_unitdata(struct osmo_sccp_link *link); +int tx_conn_req(struct osmo_sccp_link *link, uint32_t conn_id); + +struct osmo_prim_hdr *make_conn_req(uint32_t conn_id); +struct osmo_prim_hdr *make_dt1_req(uint32_t conn_id, const uint8_t *data, unsigned int len); + +struct osmo_prim_hdr *make_conn_resp(struct osmo_scu_connect_param *param) +{ + struct msgb *msg = msgb_alloc(1024, "conn_resp"); + struct osmo_scu_prim *prim; + + prim = (struct osmo_scu_prim *) msgb_put(msg, sizeof(*prim)); + osmo_prim_init(&prim->oph, SCCP_SAP_USER, + OSMO_SCU_PRIM_N_CONNECT, + PRIM_OP_RESPONSE, msg); + memcpy(&prim->u.connect, param, sizeof(prim->u.connect)); + return &prim->oph; +} + +static int sccp_sap_up(struct osmo_prim_hdr *oph, void *link) +{ + struct osmo_scu_prim *prim = (struct osmo_scu_prim *) oph; + struct osmo_prim_hdr *resp = NULL; + int rc; + struct ue_conn_ctx *ue; + + DEBUGP(DRANAP, "sccp_sap_up(%s)\n", osmo_scu_prim_name(oph)); + + switch (OSMO_PRIM_HDR(oph)) { + case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_CONFIRM): + /* confirmation of outbound connection */ + rc = -1; + break; + case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_INDICATION): + /* indication of new inbound connection request*/ + DEBUGP(DRANAP, "N-CONNECT.ind(X->%u)\n", prim->u.connect.conn_id); + if (/* prim->u.connect.called_addr.ssn != OSMO_SCCP_SSN_RANAP || */ + !msgb_l2(oph->msg) || msgb_l2len(oph->msg) == 0) { + LOGP(DRANAP, LOGL_NOTICE, + "Received invalid N-CONNECT.ind\n"); + return 0; + } + ue = ue_conn_ctx_alloc(link, prim->u.connect.conn_id); + /* first ensure the local SUA/SCCP socket is ACTIVE */ + resp = make_conn_resp(&prim->u.connect); + osmo_sua_user_link_down(link, resp); + /* then handle the RANAP payload */ + rc = ranap_cn_rx_co(cn_ranap_handle_co, ue, msgb_l2(oph->msg), msgb_l2len(oph->msg)); + break; + case OSMO_PRIM(OSMO_SCU_PRIM_N_DISCONNECT, PRIM_OP_INDICATION): + /* indication of disconnect */ + DEBUGP(DRANAP, "N-DISCONNECT.ind(%u)\n", + prim->u.disconnect.conn_id); + ue = ue_conn_ctx_find(link, prim->u.disconnect.conn_id); + rc = ranap_cn_rx_co(cn_ranap_handle_co, ue, msgb_l2(oph->msg), msgb_l2len(oph->msg)); + break; + case OSMO_PRIM(OSMO_SCU_PRIM_N_DATA, PRIM_OP_INDICATION): + /* connection-oriented data received */ + DEBUGP(DRANAP, "N-DATA.ind(%u, %s)\n", prim->u.data.conn_id, + osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg))); + /* resolve UE context */ + ue = ue_conn_ctx_find(link, prim->u.data.conn_id); + rc = ranap_cn_rx_co(cn_ranap_handle_co, ue, msgb_l2(oph->msg), msgb_l2len(oph->msg)); + break; + case OSMO_PRIM(OSMO_SCU_PRIM_N_UNITDATA, PRIM_OP_INDICATION): + /* connection-less data received */ + DEBUGP(DRANAP, "N-UNITDATA.ind(%s)\n", + osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg))); + rc = ranap_cn_rx_cl(cn_ranap_handle_cl, link, msgb_l2(oph->msg), msgb_l2len(oph->msg)); + break; + default: + rc = -1; + break; + } + + msgb_free(oph->msg); + return rc; +} + +int iu_init(void *ctx, const char *listen_addr, uint16_t listen_port, + iu_recv_cb_t iu_recv_cb, iu_event_cb_t iu_event_cb) +{ + struct osmo_sccp_user *user; + talloc_iu_ctx = talloc_named_const(ctx, 1, "iu"); + talloc_asn1_ctx = talloc_named_const(talloc_iu_ctx, 1, "asn1"); + + global_iu_recv_cb = iu_recv_cb; + global_iu_event_cb = iu_event_cb; + osmo_sua_set_log_area(DSUA); + user = osmo_sua_user_create(talloc_iu_ctx, sccp_sap_up, talloc_iu_ctx); + return osmo_sua_server_listen(user, listen_addr, listen_port); +} + -- To view, visit https://gerrit.osmocom.org/192 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: Iffc26f9c73cb15463948f7435b72ac1747aabdb3 Gerrit-PatchSet: 8 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Mon Aug 29 15:53:43 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 15:53:43 +0000 Subject: [PATCH] openbsc[master]: libmsc/bsc: split rate counters into bsc and msc group In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/646 to look at the new patch set (#4). libmsc/bsc: split rate counters into bsc and msc group Tweaked-By: Neels Hofmeyr Change-Id: I7361033cd1eb919ec3c2ea2652f40ab8c75b2f99 --- M openbsc/include/openbsc/gsm_data.h M openbsc/src/libbsc/abis_rsl.c M openbsc/src/libbsc/bsc_init.c M openbsc/src/libbsc/bsc_vty.c M openbsc/src/libbsc/gsm_04_08_utils.c M openbsc/src/libbsc/handover_logic.c M openbsc/src/libbsc/net_init.c M openbsc/src/libbsc/paging.c M openbsc/src/libmsc/gsm_04_08.c M openbsc/src/libmsc/gsm_04_11.c M openbsc/src/libmsc/vty_interface_layer3.c 11 files changed, 112 insertions(+), 96 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/46/646/4 diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 9221913..bfb7a60 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -150,25 +150,49 @@ #include "gsm_data_shared.h" -/* Some statistics of our network */ enum { - MSC_CTR_CHREQ_TOTAL, - MSC_CTR_CHREQ_NO_CHANNEL, - MSC_CTR_HANDOVER_ATTEMPTED, - MSC_CTR_HANDOVER_NO_CHANNEL, - MSC_CTR_HANDOVER_TIMEOUT, - MSC_CTR_HANDOVER_COMPLETED, - MSC_CTR_HANDOVER_FAILED, + BSC_CTR_CHREQ_TOTAL, + BSC_CTR_CHREQ_NO_CHANNEL, + BSC_CTR_HANDOVER_ATTEMPTED, + BSC_CTR_HANDOVER_NO_CHANNEL, + BSC_CTR_HANDOVER_TIMEOUT, + BSC_CTR_HANDOVER_COMPLETED, + BSC_CTR_HANDOVER_FAILED, + BSC_CTR_PAGING_ATTEMPTED, + BSC_CTR_PAGING_DETACHED, + BSC_CTR_PAGING_COMPLETED, + BSC_CTR_PAGING_EXPIRED, + BSC_CTR_CHAN_RF_FAIL, + BSC_CTR_CHAN_RLL_ERR, + BSC_CTR_BTS_OML_FAIL, + BSC_CTR_BTS_RSL_FAIL, +}; + +static const struct rate_ctr_desc bsc_ctr_description[] = { + [BSC_CTR_CHREQ_TOTAL] = {"chreq.total", "Received channel requests."}, + [BSC_CTR_CHREQ_NO_CHANNEL] = {"chreq.no_channel", "Sent to MS no channel available."}, + [BSC_CTR_HANDOVER_ATTEMPTED] = {"handover.attempted", "Received handover attempts."}, + [BSC_CTR_HANDOVER_NO_CHANNEL] = {"handover.no_channel", "Sent no channel available responses."}, + [BSC_CTR_HANDOVER_TIMEOUT] = {"handover.timeout", "Count the amount of timeouts of timer T3103."}, + [BSC_CTR_HANDOVER_COMPLETED] = {"handover.completed", "Received handover completed."}, + [BSC_CTR_HANDOVER_FAILED] = {"handover.failed", "Receive HO FAIL messages."}, + [BSC_CTR_PAGING_ATTEMPTED] = {"paging.attempted", "Paging attempts for a MS."}, + [BSC_CTR_PAGING_DETACHED] = {"paging.detached", "Counts the amount of paging attempts which couldn't sent out any paging request because no responsible bts found."}, + [BSC_CTR_PAGING_COMPLETED] = {"paging.completed", "Paging successful completed."}, + [BSC_CTR_PAGING_EXPIRED] = {"paging.expired", "Paging Request expired because of timeout T3113."}, + [BSC_CTR_CHAN_RF_FAIL] = {"chan.rf_fail", "Received a RF failure indication from BTS."}, + [BSC_CTR_CHAN_RLL_ERR] = {"chan.rll_err", "Received a RLL failure with T200 cause from BTS."}, + [BSC_CTR_BTS_OML_FAIL] = {"bts.oml_fail", "Received a TEI down on a OML link."}, + [BSC_CTR_BTS_RSL_FAIL] = {"bts.rsl_fail", "Received a TEI down on a OML link."}, +}; + +enum { MSC_CTR_LOC_UPDATE_TYPE_ATTACH, MSC_CTR_LOC_UPDATE_TYPE_NORMAL, MSC_CTR_LOC_UPDATE_TYPE_PERIODIC, MSC_CTR_LOC_UPDATE_TYPE_DETACH, MSC_CTR_LOC_UPDATE_RESP_REJECT, MSC_CTR_LOC_UPDATE_RESP_ACCEPT, - MSC_CTR_PAGING_ATTEMPTED, - MSC_CTR_PAGING_DETACHED, - MSC_CTR_PAGING_COMPLETED, - MSC_CTR_PAGING_EXPIRED, MSC_CTR_SMS_SUBMITTED, MSC_CTR_SMS_NO_RECEIVER, MSC_CTR_SMS_DELIVERED, @@ -179,30 +203,15 @@ MSC_CTR_CALL_MO_CONNECT_ACK, MSC_CTR_CALL_MT_SETUP, MSC_CTR_CALL_MT_CONNECT, - MSC_CTR_CHAN_RF_FAIL, - MSC_CTR_CHAN_RLL_ERR, - MSC_CTR_BTS_OML_FAIL, - MSC_CTR_BTS_RSL_FAIL, }; static const struct rate_ctr_desc msc_ctr_description[] = { - [MSC_CTR_CHREQ_TOTAL] = {"chreq.total", "Received channel requests."}, - [MSC_CTR_CHREQ_NO_CHANNEL] = {"chreq.no_channel", "Sent to MS no channel available."}, - [MSC_CTR_HANDOVER_ATTEMPTED] = {"handover.attempted", "Received handover attempts."}, - [MSC_CTR_HANDOVER_NO_CHANNEL] = {"handover.no_channel", "Sent no channel available responses."}, - [MSC_CTR_HANDOVER_TIMEOUT] = {"handover.timeout", "Count the amount of timeouts of timer T3103."}, - [MSC_CTR_HANDOVER_COMPLETED] = {"handover.completed", "Received handover completed."}, - [MSC_CTR_HANDOVER_FAILED] = {"handover.failed", "Receive HO FAIL messages."}, [MSC_CTR_LOC_UPDATE_TYPE_ATTACH] = {"loc_update_type.attach", "Received location update imsi attach requests."}, [MSC_CTR_LOC_UPDATE_TYPE_NORMAL] = {"loc_update_type.normal", "Received location update normal requests."}, [MSC_CTR_LOC_UPDATE_TYPE_PERIODIC] = {"loc_update_type.periodic", "Received location update periodic requests."}, [MSC_CTR_LOC_UPDATE_TYPE_DETACH] = {"loc_update_type.detach", "Received location update detach indication."}, [MSC_CTR_LOC_UPDATE_RESP_REJECT] = {"loc_update_resp.reject", "Sent location update reject responses."}, [MSC_CTR_LOC_UPDATE_RESP_ACCEPT] = {"loc_update_resp.accept", "Sent location update accept responses."}, - [MSC_CTR_PAGING_ATTEMPTED] = {"paging.attempted", "Paging attempts for a MS."}, - [MSC_CTR_PAGING_DETACHED] = {"paging.detached", "Counts the amount of paging attempts which couldn't sent out any paging request because no responsible bts found."}, - [MSC_CTR_PAGING_COMPLETED] = {"paging.completed", "Paging successful completed."}, - [MSC_CTR_PAGING_EXPIRED] = {"paging.expired", "Paging Request expired because of timeout T3113."}, [MSC_CTR_SMS_SUBMITTED] = {"sms.submitted", "Received a RPDU from a MS (MO)."}, [MSC_CTR_SMS_NO_RECEIVER] = {"sms.no_receiver", "Counts SMS which couldn't routed because no receiver found."}, [MSC_CTR_SMS_DELIVERED] = {"sms.delivered", "Global SMS Deliver attempts."}, @@ -214,10 +223,15 @@ [MSC_CTR_CALL_MO_CONNECT_ACK] = {"call.mo_connect_ack", "Received a connect ack from MS of a MO call. Call is now succesful connected up."}, [MSC_CTR_CALL_MT_SETUP] = {"call.mt_setup", "Sent setup requests to the MS (MT)."}, [MSC_CTR_CALL_MT_CONNECT] = {"call.mt_connect", "Sent a connect to the MS (MT)."}, - [MSC_CTR_CHAN_RF_FAIL] = {"chan.rf_fail", "Received a RF failure indication from BTS."}, - [MSC_CTR_CHAN_RLL_ERR] = {"chan.rll_err", "Received a RLL failure with T200 cause from BTS."}, - [MSC_CTR_BTS_OML_FAIL] = {"bts.oml_fail", "Received a TEI down on a OML link."}, - [MSC_CTR_BTS_RSL_FAIL] = {"bts.rsl_fail", "Received a TEI down on a OML link."}, +}; + + +static const struct rate_ctr_group_desc bsc_ctrg_desc = { + "bsc", + "base station controller", + OSMO_STATS_CLASS_GLOBAL, + ARRAY_SIZE(bsc_ctr_description), + bsc_ctr_description, }; static const struct rate_ctr_group_desc msc_ctrg_desc = { @@ -270,7 +284,8 @@ unsigned int max_distance; /* TA values */ } handover; - struct rate_ctr_group *ratectrs; + struct rate_ctr_group *bsc_ctrs; + struct rate_ctr_group *msc_ctrs; /* layer 4 */ diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index 9af986a..4c8448e 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -1229,7 +1229,7 @@ TLVP_LEN(&tp, RSL_IE_CAUSE)); LOGPC(DRSL, LOGL_NOTICE, "\n"); - rate_ctr_inc(&msg->lchan->ts->trx->bts->network->ratectrs->ctr[MSC_CTR_CHAN_RF_FAIL]); + rate_ctr_inc(&msg->lchan->ts->trx->bts->network->bsc_ctrs->ctr[BSC_CTR_CHAN_RF_FAIL]); return rsl_rf_chan_release_err(msg->lchan); } @@ -1663,7 +1663,7 @@ lctype = get_ctype_by_chreq(bts->network, rqd_ref->ra); chreq_reason = get_reason_by_chreq(rqd_ref->ra, bts->network->neci); - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_CHREQ_TOTAL]); + rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_CHREQ_TOTAL]); /* * We want LOCATION UPDATES to succeed and will assign a TCH @@ -1676,7 +1676,7 @@ if (!lchan) { LOGP(DRSL, LOGL_NOTICE, "BTS %d CHAN RQD: no resources for %s 0x%x\n", msg->lchan->ts->trx->bts->nr, gsm_lchant_name(lctype), rqd_ref->ra); - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_CHREQ_NO_CHANNEL]); + rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_CHREQ_NO_CHANNEL]); /* FIXME gather multiple CHAN RQD and reject up to 4 at the same time */ if (bts->network->T3122) rsl_send_imm_ass_rej(bts, 1, rqd_ref, bts->network->T3122 & 0xff); @@ -1859,7 +1859,7 @@ rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_ERR_IND); if (rlm_cause == RLL_CAUSE_T200_EXPIRED) { - rate_ctr_inc(&msg->lchan->ts->trx->bts->network->ratectrs->ctr[MSC_CTR_CHAN_RLL_ERR]); + rate_ctr_inc(&msg->lchan->ts->trx->bts->network->bsc_ctrs->ctr[BSC_CTR_CHAN_RLL_ERR]); return rsl_rf_chan_release_err(msg->lchan); } diff --git a/openbsc/src/libbsc/bsc_init.c b/openbsc/src/libbsc/bsc_init.c index 5ea85d0..989fca8 100644 --- a/openbsc/src/libbsc/bsc_init.c +++ b/openbsc/src/libbsc/bsc_init.c @@ -340,9 +340,9 @@ LOGP(DLMI, LOGL_ERROR, "Lost some E1 TEI link: %d %p\n", isd->link_type, trx); if (isd->link_type == E1INP_SIGN_OML) - rate_ctr_inc(&trx->bts->network->ratectrs->ctr[MSC_CTR_BTS_OML_FAIL]); + rate_ctr_inc(&trx->bts->network->bsc_ctrs->ctr[BSC_CTR_BTS_OML_FAIL]); else if (isd->link_type == E1INP_SIGN_RSL) - rate_ctr_inc(&trx->bts->network->ratectrs->ctr[MSC_CTR_BTS_RSL_FAIL]); + rate_ctr_inc(&trx->bts->network->bsc_ctrs->ctr[BSC_CTR_BTS_RSL_FAIL]); /* * free all allocated channels. change the nm_state so the diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c index fbaf06b..8116af1 100644 --- a/openbsc/src/libbsc/bsc_vty.c +++ b/openbsc/src/libbsc/bsc_vty.c @@ -3784,21 +3784,21 @@ void openbsc_vty_print_statistics(struct vty *vty, struct gsm_network *net) { vty_out(vty, "Channel Requests : %lu total, %lu no channel%s", - net->ratectrs->ctr[MSC_CTR_CHREQ_TOTAL].current, - net->ratectrs->ctr[MSC_CTR_CHREQ_NO_CHANNEL].current, + net->bsc_ctrs->ctr[BSC_CTR_CHREQ_TOTAL].current, + net->bsc_ctrs->ctr[BSC_CTR_CHREQ_NO_CHANNEL].current, VTY_NEWLINE); vty_out(vty, "Channel Failures : %lu rf_failures, %lu rll failures%s", - net->ratectrs->ctr[MSC_CTR_CHAN_RF_FAIL].current, - net->ratectrs->ctr[MSC_CTR_CHAN_RLL_ERR].current, + net->bsc_ctrs->ctr[BSC_CTR_CHAN_RF_FAIL].current, + net->bsc_ctrs->ctr[BSC_CTR_CHAN_RLL_ERR].current, VTY_NEWLINE); vty_out(vty, "Paging : %lu attempted, %lu complete, %lu expired%s", - net->ratectrs->ctr[MSC_CTR_PAGING_ATTEMPTED].current, - net->ratectrs->ctr[MSC_CTR_PAGING_COMPLETED].current, - net->ratectrs->ctr[MSC_CTR_PAGING_EXPIRED].current, + net->bsc_ctrs->ctr[BSC_CTR_PAGING_ATTEMPTED].current, + net->bsc_ctrs->ctr[BSC_CTR_PAGING_COMPLETED].current, + net->bsc_ctrs->ctr[BSC_CTR_PAGING_EXPIRED].current, VTY_NEWLINE); vty_out(vty, "BTS failures : %lu OML, %lu RSL%s", - net->ratectrs->ctr[MSC_CTR_BTS_OML_FAIL].current, - net->ratectrs->ctr[MSC_CTR_BTS_RSL_FAIL].current, + net->bsc_ctrs->ctr[BSC_CTR_BTS_OML_FAIL].current, + net->bsc_ctrs->ctr[BSC_CTR_BTS_RSL_FAIL].current, VTY_NEWLINE); } diff --git a/openbsc/src/libbsc/gsm_04_08_utils.c b/openbsc/src/libbsc/gsm_04_08_utils.c index d4eca4a..46df108 100644 --- a/openbsc/src/libbsc/gsm_04_08_utils.c +++ b/openbsc/src/libbsc/gsm_04_08_utils.c @@ -304,7 +304,7 @@ subscr = conn->subscr; } - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_PAGING_COMPLETED]); + rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_PAGING_COMPLETED]); /* Stop paging on the bts we received the paging response */ paging_request_stop(conn->bts, subscr, conn, msg); diff --git a/openbsc/src/libbsc/handover_logic.c b/openbsc/src/libbsc/handover_logic.c index 5424e27..ffcca66 100644 --- a/openbsc/src/libbsc/handover_logic.c +++ b/openbsc/src/libbsc/handover_logic.c @@ -103,7 +103,7 @@ DEBUGP(DHO, "(old_lchan on BTS %u, new BTS %u)\n", old_lchan->ts->trx->bts->nr, bts->nr); - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_HANDOVER_ATTEMPTED]); + rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_HANDOVER_ATTEMPTED]); if (!old_lchan->conn) { LOGP(DHO, LOGL_ERROR, "Old lchan lacks connection data.\n"); @@ -113,7 +113,7 @@ new_lchan = lchan_alloc(bts, old_lchan->type, 0); if (!new_lchan) { LOGP(DHO, LOGL_NOTICE, "No free channel\n"); - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_HANDOVER_NO_CHANNEL]); + rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_HANDOVER_NO_CHANNEL]); return -ENOSPC; } @@ -188,7 +188,7 @@ struct gsm_network *net = ho->new_lchan->ts->trx->bts->network; DEBUGP(DHO, "HO T3103 expired\n"); - rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_HANDOVER_TIMEOUT]); + rate_ctr_inc(&net->bsc_ctrs->ctr[BSC_CTR_HANDOVER_TIMEOUT]); ho->new_lchan->conn->ho_lchan = NULL; ho->new_lchan->conn = NULL; @@ -265,7 +265,7 @@ ho->old_lchan->ts->trx->bts->nr, new_lchan->ts->trx->bts->nr, ho->old_lchan->ts->trx->arfcn, new_lchan->ts->trx->arfcn); - rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_HANDOVER_COMPLETED]); + rate_ctr_inc(&net->bsc_ctrs->ctr[BSC_CTR_HANDOVER_COMPLETED]); osmo_timer_del(&ho->T3103); @@ -303,7 +303,7 @@ return -ENODEV; } - rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_HANDOVER_FAILED]); + rate_ctr_inc(&net->bsc_ctrs->ctr[BSC_CTR_HANDOVER_FAILED]); new_lchan = ho->new_lchan; diff --git a/openbsc/src/libbsc/net_init.c b/openbsc/src/libbsc/net_init.c index b99f3d2..37ba3c0 100644 --- a/openbsc/src/libbsc/net_init.c +++ b/openbsc/src/libbsc/net_init.c @@ -81,7 +81,8 @@ INIT_LLIST_HEAD(&net->bts_list); /* init statistics */ - net->ratectrs = rate_ctr_group_alloc(net, &msc_ctrg_desc, 0); + net->bsc_ctrs = rate_ctr_group_alloc(net, &bsc_ctrg_desc, 0); + net->bsc_ctrs = rate_ctr_group_alloc(net, &msc_ctrg_desc, 0); net->mncc_recv = mncc_recv; net->ext_min = GSM_MIN_EXTEN; diff --git a/openbsc/src/libbsc/paging.c b/openbsc/src/libbsc/paging.c index 03c91fd..fcb4deb 100644 --- a/openbsc/src/libbsc/paging.c +++ b/openbsc/src/libbsc/paging.c @@ -260,7 +260,7 @@ req, req->subscr->imsi); /* must be destroyed before calling cbfn, to prevent double free */ - rate_ctr_inc(&req->bts->network->ratectrs->ctr[MSC_CTR_PAGING_EXPIRED]); + rate_ctr_inc(&req->bts->network->bsc_ctrs->ctr[BSC_CTR_PAGING_EXPIRED]); cbfn_param = req->cbfn_param; cbfn = req->cbfn; @@ -330,7 +330,7 @@ struct gsm_bts *bts = NULL; int num_pages = 0; - rate_ctr_inc(&network->ratectrs->ctr[MSC_CTR_PAGING_ATTEMPTED]); + rate_ctr_inc(&network->bsc_ctrs->ctr[BSC_CTR_PAGING_ATTEMPTED]); /* start paging subscriber on all BTS within Location Area */ do { @@ -349,7 +349,7 @@ } while (1); if (num_pages == 0) - rate_ctr_inc(&network->ratectrs->ctr[MSC_CTR_PAGING_DETACHED]); + rate_ctr_inc(&network->bsc_ctrs->ctr[BSC_CTR_PAGING_DETACHED]); return num_pages; } diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c index c4ecf1c..c30fbb0 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/src/libmsc/gsm_04_08.c @@ -457,7 +457,7 @@ struct gsm_bts *bts = conn->bts; struct msgb *msg; - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_REJECT]); + rate_ctr_inc(&bts->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_RESP_REJECT]); msg = gsm48_create_loc_upd_rej(cause); if (!msg) { @@ -506,7 +506,7 @@ DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n"); - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_ACCEPT]); + rate_ctr_inc(&bts->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_RESP_ACCEPT]); return gsm48_conn_sendmsg(msg, conn, NULL); } @@ -637,13 +637,13 @@ switch (lu->type) { case GSM48_LUPD_NORMAL: - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_NORMAL]); + rate_ctr_inc(&bts->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_NORMAL]); break; case GSM48_LUPD_IMSI_ATT: - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_ATTACH]); + rate_ctr_inc(&bts->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_ATTACH]); break; case GSM48_LUPD_PERIODIC: - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_PERIODIC]); + rate_ctr_inc(&bts->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_PERIODIC]); break; } @@ -1063,7 +1063,7 @@ DEBUGP(DMM, "IMSI DETACH INDICATION: MI(%s)=%s", gsm48_mi_type_name(mi_type), mi_string); - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_DETACH]); + rate_ctr_inc(&bts->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_DETACH]); switch (mi_type) { case GSM_MI_TYPE_TMSI: @@ -2002,7 +2002,7 @@ subscr_name(trans->subscr), trans->subscr->extension, setup.called.number); - rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MO_SETUP]); + rate_ctr_inc(&trans->net->msc_ctrs->ctr[MSC_CTR_CALL_MO_SETUP]); /* indicate setup to MNCC */ mncc_recvmsg(trans->net, trans, MNCC_SETUP_IND, &setup); @@ -2080,7 +2080,7 @@ new_cc_state(trans, GSM_CSTATE_CALL_PRESENT); - rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MT_SETUP]); + rate_ctr_inc(&trans->net->msc_ctrs->ctr[MSC_CTR_CALL_MT_SETUP]); return gsm48_conn_sendmsg(msg, trans->conn, trans); } @@ -2306,7 +2306,7 @@ } new_cc_state(trans, GSM_CSTATE_CONNECT_REQUEST); - rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MT_CONNECT]); + rate_ctr_inc(&trans->net->msc_ctrs->ctr[MSC_CTR_CALL_MT_CONNECT]); return mncc_recvmsg(trans->net, trans, MNCC_SETUP_CNF, &connect); } @@ -2319,7 +2319,7 @@ gsm48_stop_cc_timer(trans); new_cc_state(trans, GSM_CSTATE_ACTIVE); - rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MO_CONNECT_ACK]); + rate_ctr_inc(&trans->net->msc_ctrs->ctr[MSC_CTR_CALL_MO_CONNECT_ACK]); memset(&connect_ack, 0, sizeof(struct gsm_mncc)); connect_ack.callref = trans->callref; diff --git a/openbsc/src/libmsc/gsm_04_11.c b/openbsc/src/libmsc/gsm_04_11.c index 619ff42..bf70971 100644 --- a/openbsc/src/libmsc/gsm_04_11.c +++ b/openbsc/src/libmsc/gsm_04_11.c @@ -297,7 +297,7 @@ if (rc < 0) { LOGP(DLSMS, LOGL_ERROR, "While trying to deliver a SMS the error code %d received. Sending rp err cause 41 to ms\n", rc); rc = GSM411_RP_CAUSE_MO_TEMP_FAIL; /* cause 41: Temporary failure */ - rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_DELIVER_UNKNOWN_ERROR]); + rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_DELIVER_UNKNOWN_ERROR]); } return rc; } @@ -312,22 +312,22 @@ #ifdef BUILD_SMPP /* Avoid a second look-up */ if (smpp_first) { - rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); + rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); return 1; /* cause 1: unknown subscriber */ } rc = smpp_try_deliver(gsms, conn); if (rc == 1) { rc = 1; /* cause 1: unknown subscriber */ - rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); + rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); } else if (rc < 0) { LOGP(DLSMS, LOGL_ERROR, "While trying to deliver a SMS the error code %d received. Sending rp err cause 41 to ms\n", rc); rc = GSM411_RP_CAUSE_MO_TEMP_FAIL; /* cause 41: Temporary failure */ - rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_DELIVER_UNKNOWN_ERROR]); + rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_DELIVER_UNKNOWN_ERROR]); } #else rc = 1; /* cause 1: unknown subscriber */ - rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); + rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); #endif return rc; } @@ -368,7 +368,7 @@ uint8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */ int rc = 0; - rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_SUBMITTED]); + rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_SUBMITTED]); gsms = sms_alloc(); if (!gsms) @@ -638,10 +638,10 @@ * to store this in our database and wait for a SMMA message */ /* FIXME */ send_signal(S_SMS_MEM_EXCEEDED, trans, sms, 0); - rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_MEM]); + rate_ctr_inc(&net->msc_ctrs->ctr[MSC_CTR_SMS_RP_ERR_MEM]); } else { send_signal(S_SMS_UNKNOWN_ERROR, trans, sms, 0); - rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_OTHER]); + rate_ctr_inc(&net->msc_ctrs->ctr[MSC_CTR_SMS_RP_ERR_OTHER]); } sms_free(sms); @@ -937,7 +937,7 @@ DEBUGP(DLSMS, "TX: SMS DELIVER\n"); - rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_DELIVERED]); + rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_DELIVERED]); db_sms_inc_deliver_attempts(trans->sms.sms); return gsm411_rp_sendmsg(&trans->sms.smr_inst, msg, diff --git a/openbsc/src/libmsc/vty_interface_layer3.c b/openbsc/src/libmsc/vty_interface_layer3.c index d1041b3..e7ff0a9 100644 --- a/openbsc/src/libmsc/vty_interface_layer3.c +++ b/openbsc/src/libmsc/vty_interface_layer3.c @@ -795,41 +795,41 @@ openbsc_vty_print_statistics(vty, net); vty_out(vty, "Location Update : %lu attach, %lu normal, %lu periodic%s", - net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_ATTACH].current, - net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_NORMAL].current, - net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_PERIODIC].current, + net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_ATTACH].current, + net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_NORMAL].current, + net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_PERIODIC].current, VTY_NEWLINE); vty_out(vty, "IMSI Detach Indications : %lu%s", - net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_DETACH].current, + net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_DETACH].current, VTY_NEWLINE); vty_out(vty, "Location Update Response: %lu accept, %lu reject%s", - net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_ACCEPT].current, - net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_REJECT].current, + net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_RESP_ACCEPT].current, + net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_RESP_REJECT].current, VTY_NEWLINE); vty_out(vty, "Handover : %lu attempted, %lu no_channel, %lu timeout, " "%lu completed, %lu failed%s", - net->ratectrs->ctr[MSC_CTR_HANDOVER_ATTEMPTED].current, - net->ratectrs->ctr[MSC_CTR_HANDOVER_NO_CHANNEL].current, - net->ratectrs->ctr[MSC_CTR_HANDOVER_TIMEOUT].current, - net->ratectrs->ctr[MSC_CTR_HANDOVER_COMPLETED].current, - net->ratectrs->ctr[MSC_CTR_HANDOVER_FAILED].current, + net->msc_ctrs->ctr[BSC_CTR_HANDOVER_ATTEMPTED].current, + net->msc_ctrs->ctr[BSC_CTR_HANDOVER_NO_CHANNEL].current, + net->msc_ctrs->ctr[BSC_CTR_HANDOVER_TIMEOUT].current, + net->msc_ctrs->ctr[BSC_CTR_HANDOVER_COMPLETED].current, + net->msc_ctrs->ctr[BSC_CTR_HANDOVER_FAILED].current, VTY_NEWLINE); vty_out(vty, "SMS MO : %lu submitted, %lu no receiver%s", - net->ratectrs->ctr[MSC_CTR_SMS_SUBMITTED].current, - net->ratectrs->ctr[MSC_CTR_SMS_NO_RECEIVER].current, + net->msc_ctrs->ctr[MSC_CTR_SMS_SUBMITTED].current, + net->msc_ctrs->ctr[MSC_CTR_SMS_NO_RECEIVER].current, VTY_NEWLINE); vty_out(vty, "SMS MT : %lu delivered, %lu no memory, %lu other error%s", - net->ratectrs->ctr[MSC_CTR_SMS_DELIVERED].current, - net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_MEM].current, - net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_OTHER].current, + net->msc_ctrs->ctr[MSC_CTR_SMS_DELIVERED].current, + net->msc_ctrs->ctr[MSC_CTR_SMS_RP_ERR_MEM].current, + net->msc_ctrs->ctr[MSC_CTR_SMS_RP_ERR_OTHER].current, VTY_NEWLINE); vty_out(vty, "MO Calls : %lu setup, %lu connect ack%s", - net->ratectrs->ctr[MSC_CTR_CALL_MO_SETUP].current, - net->ratectrs->ctr[MSC_CTR_CALL_MO_CONNECT_ACK].current, + net->msc_ctrs->ctr[MSC_CTR_CALL_MO_SETUP].current, + net->msc_ctrs->ctr[MSC_CTR_CALL_MO_CONNECT_ACK].current, VTY_NEWLINE); vty_out(vty, "MT Calls : %lu setup, %lu connect%s", - net->ratectrs->ctr[MSC_CTR_CALL_MT_SETUP].current, - net->ratectrs->ctr[MSC_CTR_CALL_MT_CONNECT].current, + net->msc_ctrs->ctr[MSC_CTR_CALL_MT_SETUP].current, + net->msc_ctrs->ctr[MSC_CTR_CALL_MT_CONNECT].current, VTY_NEWLINE); return CMD_SUCCESS; } -- To view, visit https://gerrit.osmocom.org/646 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I7361033cd1eb919ec3c2ea2652f40ab8c75b2f99 Gerrit-PatchSet: 4 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 29 15:53:44 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 15:53:44 +0000 Subject: [PATCH] openbsc[master]: cosmetic: transaction.h: 1 comment typo, 1 whitespace Message-ID: Review at https://gerrit.osmocom.org/791 cosmetic: transaction.h: 1 comment typo, 1 whitespace Change-Id: Ia2629f9d9887b50b25c6996531b7ef518fb33335 --- M openbsc/include/openbsc/transaction.h 1 file changed, 2 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/91/791/1 diff --git a/openbsc/include/openbsc/transaction.h b/openbsc/include/openbsc/transaction.h index 6ef1612..9a87d04 100644 --- a/openbsc/include/openbsc/transaction.h +++ b/openbsc/include/openbsc/transaction.h @@ -14,7 +14,7 @@ /* Entry in list of all transactions */ struct llist_head entry; - /* Back pointer to the netweork struct */ + /* Back pointer to the network struct */ struct gsm_network *net; /* The protocol within which we live */ @@ -22,7 +22,7 @@ /* The current transaction ID */ uint8_t transaction_id; - + /* To whom we belong, unique identifier of remote MM entity */ struct gsm_subscriber *subscr; -- To view, visit https://gerrit.osmocom.org/791 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ia2629f9d9887b50b25c6996531b7ef518fb33335 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 29 15:55:57 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 15:55:57 +0000 Subject: openbsc[master]: libmsc/bsc: split rate counters into bsc and msc group In-Reply-To: References: Message-ID: Patch Set 4: Code-Review+2 I need this to sanely rebase the 3G CSCN branch onto master, and since you're taking very long, I fixed the place I commented on myself. Since the unrelated change is gone now, adding my +2. -- To view, visit https://gerrit.osmocom.org/646 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I7361033cd1eb919ec3c2ea2652f40ab8c75b2f99 Gerrit-PatchSet: 4 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 29 16:05:27 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 16:05:27 +0000 Subject: [PATCH] osmo-iuh[master]: build: move headers to include/osmocom/* In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/787 to look at the new patch set (#2). build: move headers to include/osmocom/* This came up while fixing 'make distcheck'; this is certainly not the easiest way but it makes sense to have the headers in include/, like we do in openbsc. The easy alternative might be to add -I$(top_srcdir)/src to src/Makefile.am. Remove -I$(top_srcdir)/src from src/tests/Makefile.am, no longer needed. Change-Id: I5a82e029dcdc4df0a60a31271a4883393fe59234 --- M include/osmocom/iuh/Makefile.am R include/osmocom/iuh/context_map.h R include/osmocom/iuh/hnbgw.h R include/osmocom/iuh/hnbgw_cn.h R include/osmocom/iuh/hnbgw_hnbap.h R include/osmocom/iuh/hnbgw_ranap.h R include/osmocom/iuh/hnbgw_rua.h R include/osmocom/iuh/iu_common.h M include/osmocom/rua/Makefile.am R include/osmocom/rua/rua_msg_factory.h M src/Makefile.am M src/context_map.c M src/hnbap_common.c M src/hnbgw.c M src/hnbgw_cn.c M src/hnbgw_hnbap.c M src/hnbgw_ranap.c M src/hnbgw_rua.c M src/hnbgw_vty.c M src/ranap_common_cn.c M src/rua_common.c M src/rua_msg_factory.c M src/tests/Makefile.am M src/tests/dummy_cn_sua.c M src/tests/hnb-test-rua.c M src/tests/hnb-test.c M src/tests/test-ranap.c M src/tests/test_common.c 28 files changed, 42 insertions(+), 38 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/87/787/2 diff --git a/include/osmocom/iuh/Makefile.am b/include/osmocom/iuh/Makefile.am index e2f7126..b2a667d 100644 --- a/include/osmocom/iuh/Makefile.am +++ b/include/osmocom/iuh/Makefile.am @@ -1,2 +1,4 @@ noinst_HEADERS = \ - vty.h + vty.h \ + context_map.h hnbgw.h hnbgw_cn.h \ + hnbgw_hnbap.h hnbgw_rua.h hnbgw_ranap.h diff --git a/src/context_map.h b/include/osmocom/iuh/context_map.h similarity index 100% rename from src/context_map.h rename to include/osmocom/iuh/context_map.h diff --git a/src/hnbgw.h b/include/osmocom/iuh/hnbgw.h similarity index 100% rename from src/hnbgw.h rename to include/osmocom/iuh/hnbgw.h diff --git a/src/hnbgw_cn.h b/include/osmocom/iuh/hnbgw_cn.h similarity index 78% rename from src/hnbgw_cn.h rename to include/osmocom/iuh/hnbgw_cn.h index 469b3d4..d5bec04 100644 --- a/src/hnbgw_cn.h +++ b/include/osmocom/iuh/hnbgw_cn.h @@ -1,5 +1,5 @@ #pragma once -#include "hnbgw.h" +#include struct hnbgw_cnlink *hnbgw_cnlink_init(struct hnb_gw *gw, const char *host, uint16_t port, int is_ps); diff --git a/src/hnbgw_hnbap.h b/include/osmocom/iuh/hnbgw_hnbap.h similarity index 77% rename from src/hnbgw_hnbap.h rename to include/osmocom/iuh/hnbgw_hnbap.h index 955e0aa..cca3550 100644 --- a/src/hnbgw_hnbap.h +++ b/include/osmocom/iuh/hnbgw_hnbap.h @@ -1,6 +1,6 @@ #pragma once -#include "hnbgw.h" +#include int hnbgw_hnbap_rx(struct hnb_context *hnb, struct msgb *msg); int hnbgw_hnbap_init(void); diff --git a/src/hnbgw_ranap.h b/include/osmocom/iuh/hnbgw_ranap.h similarity index 77% rename from src/hnbgw_ranap.h rename to include/osmocom/iuh/hnbgw_ranap.h index 85a2f98..2c55964 100644 --- a/src/hnbgw_ranap.h +++ b/include/osmocom/iuh/hnbgw_ranap.h @@ -1,6 +1,6 @@ #pragma once -#include "hnbgw.h" +#include int hnbgw_ranap_rx(struct msgb *msg, uint8_t *data, size_t len); int hnbgw_ranap_init(void); diff --git a/src/hnbgw_rua.h b/include/osmocom/iuh/hnbgw_rua.h similarity index 93% rename from src/hnbgw_rua.h rename to include/osmocom/iuh/hnbgw_rua.h index d170190..6a890b7 100644 --- a/src/hnbgw_rua.h +++ b/include/osmocom/iuh/hnbgw_rua.h @@ -1,6 +1,6 @@ #pragma once -#include "hnbgw.h" +#include #include int hnbgw_rua_rx(struct hnb_context *hnb, struct msgb *msg); diff --git a/src/iu_common.h b/include/osmocom/iuh/iu_common.h similarity index 100% rename from src/iu_common.h rename to include/osmocom/iuh/iu_common.h diff --git a/include/osmocom/rua/Makefile.am b/include/osmocom/rua/Makefile.am index 49e2150..307f123 100644 --- a/include/osmocom/rua/Makefile.am +++ b/include/osmocom/rua/Makefile.am @@ -1,5 +1,5 @@ noinst_HEADERS = \ - rua_common.h rua_ies_defs.h \ + rua_common.h rua_ies_defs.h rua_msg_factory.h \ RUA_Ansi-41-IDNNS.h \ RUA_Cause.h \ RUA_CauseMisc.h \ diff --git a/src/rua_msg_factory.h b/include/osmocom/rua/rua_msg_factory.h similarity index 100% rename from src/rua_msg_factory.h rename to include/osmocom/rua/rua_msg_factory.h diff --git a/src/Makefile.am b/src/Makefile.am index 2779315..bb1ebbd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -60,9 +60,6 @@ # bin_PROGRAMS = osmo-hnbgw -noinst_HEADERS = context_map.h hnbgw.h hnbgw_cn.h \ - hnbgw_hnbap.h hnbgw_rua.h hnbgw_ranap.h - osmo_hnbgw_SOURCES = hnbap_encoder.c hnbap_decoder.c hnbap_common.c \ rua_encoder.c rua_decoder.c rua_common.c \ rua_msg_factory.c \ diff --git a/src/context_map.c b/src/context_map.c index 22eb605..052133c 100644 --- a/src/context_map.c +++ b/src/context_map.c @@ -24,8 +24,8 @@ #include -#include "hnbgw.h" -#include "context_map.h" +#include +#include /* is a given SCCP USER SAP Connection ID in use for a given CN link? */ static int cn_id_in_use(struct hnbgw_cnlink *cn, uint32_t id) diff --git a/src/hnbap_common.c b/src/hnbap_common.c index 2cd6519..f8cfb13 100644 --- a/src/hnbap_common.c +++ b/src/hnbap_common.c @@ -25,7 +25,7 @@ #include #include -#include "hnbgw.h" +#include static const struct value_string hnbap_cause_radio_vals[] = { { CauseRadioNetwork_overload, "overload" }, diff --git a/src/hnbgw.c b/src/hnbgw.c index 4f23e8d..d50e622 100644 --- a/src/hnbgw.c +++ b/src/hnbgw.c @@ -51,11 +51,11 @@ #include #include -#include "hnbgw.h" -#include "hnbgw_hnbap.h" -#include "hnbgw_rua.h" -#include "hnbgw_cn.h" -#include "context_map.h" +#include +#include +#include +#include +#include static const char * const osmo_hnbgw_copyright = "OsmoHNBGW - Osmocom Home Node B Gateway implementation\r\n" diff --git a/src/hnbgw_cn.c b/src/hnbgw_cn.c index 09b2726..e41788d 100644 --- a/src/hnbgw_cn.c +++ b/src/hnbgw_cn.c @@ -29,11 +29,11 @@ #include #include -#include "hnbgw.h" -#include "hnbgw_rua.h" +#include +#include #include #include -#include "context_map.h" +#include /*********************************************************************** * Outbound RANAP RESET to CN diff --git a/src/hnbgw_hnbap.c b/src/hnbgw_hnbap.c index da82608..2595913 100644 --- a/src/hnbgw_hnbap.c +++ b/src/hnbgw_hnbap.c @@ -31,7 +31,7 @@ #include #include -#include "hnbgw.h" +#include #include #define IU_MSG_NUM_IES 32 diff --git a/src/hnbgw_ranap.c b/src/hnbgw_ranap.c index dde1183..7a505a5 100644 --- a/src/hnbgw_ranap.c +++ b/src/hnbgw_ranap.c @@ -29,8 +29,8 @@ #include "asn1helpers.h" -#include "hnbgw.h" -#include "hnbgw_rua.h" +#include +#include #include #include #include diff --git a/src/hnbgw_rua.c b/src/hnbgw_rua.c index fc22bfc..3f245b5 100644 --- a/src/hnbgw_rua.c +++ b/src/hnbgw_rua.c @@ -32,11 +32,11 @@ #include "asn1helpers.h" -#include "hnbgw.h" -#include "hnbgw_ranap.h" +#include +#include #include #include -#include "context_map.h" +#include static int hnbgw_rua_tx(struct hnb_context *ctx, struct msgb *msg) { diff --git a/src/hnbgw_vty.c b/src/hnbgw_vty.c index 1673c0c..2e3d1e9 100644 --- a/src/hnbgw_vty.c +++ b/src/hnbgw_vty.c @@ -22,8 +22,8 @@ #include -#include "hnbgw.h" -#include "context_map.h" +#include +#include static void *tall_hnb_ctx = NULL; static struct hnb_gw *g_hnb_gw = NULL; diff --git a/src/ranap_common_cn.c b/src/ranap_common_cn.c index 2c80dd0..3736dce 100644 --- a/src/ranap_common_cn.c +++ b/src/ranap_common_cn.c @@ -29,7 +29,7 @@ #include #include -#include "hnbgw.h" +#include static int cn_ranap_rx_initiating_msg_co(void *ctx, RANAP_InitiatingMessage_t *imsg, ranap_message *message) diff --git a/src/rua_common.c b/src/rua_common.c index a5ab044..3c9d773 100644 --- a/src/rua_common.c +++ b/src/rua_common.c @@ -24,7 +24,7 @@ #include #include -#include "hnbgw.h" +#include extern int asn1_xer_print; diff --git a/src/rua_msg_factory.c b/src/rua_msg_factory.c index 0bce326..268f6ac 100644 --- a/src/rua_msg_factory.c +++ b/src/rua_msg_factory.c @@ -3,9 +3,9 @@ #include #include -#include "rua_msg_factory.h" +#include #include "asn1helpers.h" -#include "hnbgw.h" +#include struct msgb *rua_new_udt(struct msgb *inmsg) diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index 2ba3e89..3a99681 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -1,9 +1,14 @@ -AM_CFLAGS = -g -I$(top_srcdir)/src -I$(top_srcdir)/include $(OSMOVTY_CFLAGS) $(OSMOCORE_CFLAGS) $(OSMOGSM_CFLAGS) $(OSMONETIF_CFLAGS) $(ASN1C_CFLAGS) $(OSMOSIGTRAN_CFLAGS) +AM_CFLAGS = -g -I$(top_srcdir)/src/tests \ + -I$(top_srcdir)/include -I$(top_builddir)/include \ + $(OSMOVTY_CFLAGS) $(OSMOCORE_CFLAGS) $(OSMOGSM_CFLAGS) \ + $(OSMONETIF_CFLAGS) $(ASN1C_CFLAGS) $(OSMOSIGTRAN_CFLAGS) COMMON_LIBS = $(OSMOVTY_LIBS) $(OSMOCORE_LIBS) $(OSMOGSM_LIBS) $(ASN1C_LIBS) $(OSMOSIGTRAN_LIBS) -lsctp check_PROGRAMS = test-ranap test-helpers test-hnbap hnb-test dummy-cn +noinst_HEADERS = test_common.h hnb-test.h hnb-test-layers.h + HNBAP_FILES = $(top_srcdir)/src/hnbap_common.c $(top_srcdir)/src/hnbap_decoder.c $(top_srcdir)/src/hnbap_encoder.c RUA_FILES = $(top_srcdir)/src/rua_common.c $(top_srcdir)/src/rua_decoder.c $(top_srcdir)/src/rua_encoder.c $(top_srcdir)/src/rua_msg_factory.c diff --git a/src/tests/dummy_cn_sua.c b/src/tests/dummy_cn_sua.c index c2fc712..f9b4244 100644 --- a/src/tests/dummy_cn_sua.c +++ b/src/tests/dummy_cn_sua.c @@ -24,7 +24,7 @@ #include #include #include -#include "hnbgw.h" +#include int asn1_xer_print = 1; const char *cmdline_bind_addr = "127.0.0.1"; diff --git a/src/tests/hnb-test-rua.c b/src/tests/hnb-test-rua.c index 69c41eb..a218852 100644 --- a/src/tests/hnb-test-rua.c +++ b/src/tests/hnb-test-rua.c @@ -1,6 +1,6 @@ #include -#include "../rua_ies_defs.h" +#include #include "hnb-test-layers.h" diff --git a/src/tests/hnb-test.c b/src/tests/hnb-test.c index 2c41199..d338077 100644 --- a/src/tests/hnb-test.c +++ b/src/tests/hnb-test.c @@ -54,7 +54,7 @@ #include "hnb-test-layers.h" #include #include -#include "rua_msg_factory.h" +#include #include "asn1helpers.h" #include #include "test_common.h" diff --git a/src/tests/test-ranap.c b/src/tests/test-ranap.c index 7b1f3bf..812a863 100644 --- a/src/tests/test-ranap.c +++ b/src/tests/test-ranap.c @@ -32,7 +32,7 @@ #include "test_common.h" -#include "hnbgw.h" +#include int asn1_xer_print = 1; diff --git a/src/tests/test_common.c b/src/tests/test_common.c index a79d5f5..5a37e7e 100644 --- a/src/tests/test_common.c +++ b/src/tests/test_common.c @@ -37,7 +37,7 @@ #include #include -#include "hnbgw.h" +#include void *talloc_asn1_ctx; -- To view, visit https://gerrit.osmocom.org/787 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I5a82e029dcdc4df0a60a31271a4883393fe59234 Gerrit-PatchSet: 2 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Mon Aug 29 16:05:27 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 16:05:27 +0000 Subject: [PATCH] osmo-iuh[master]: build: parallel build: require ../libosmo-ranap.la from tests/ In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/788 to look at the new patch set (#2). build: parallel build: require ../libosmo-ranap.la from tests/ This rule is bad because it re-invokes $(MAKE), but it seems to fix the parallel build. It should probably be done differently. Change-Id: I8107e08e4c211f20d671f520bf6bab9356f3c90e --- M src/tests/Makefile.am 1 file changed, 3 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/88/788/2 diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index 3a99681..5b51262 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -27,6 +27,9 @@ dummy_cn_SOURCES = $(RANAP_FILES) test_common.c dummy_cn_sua.c dummy_cn_LDADD = $(COMMON_LIBS) $(top_builddir)/src/libosmo-ranap.la +$(top_builddir)/src/libosmo-ranap.la: + $(MAKE) -C $(top_builddir)/src libosmo-ranap.la + # The `:;' works around a Bash 3.2 bug when the output is not writeable. $(srcdir)/package.m4: $(top_srcdir)/configure.ac :;{ \ -- To view, visit https://gerrit.osmocom.org/788 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I8107e08e4c211f20d671f520bf6bab9356f3c90e Gerrit-PatchSet: 2 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 29 16:05:27 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 16:05:27 +0000 Subject: [PATCH] osmo-iuh[master]: jenkins.sh: enable make distcheck In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/789 to look at the new patch set (#2). jenkins.sh: enable make distcheck Change-Id: I967d4de9682cb2a45210f689ec076ef457841179 --- M contrib/jenkins.sh 1 file changed, 1 insertion(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/89/789/2 diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index 72efdbc..8021bbd 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -75,5 +75,4 @@ $MAKE $PARALLEL_MAKE LD_LIBRARY_PATH="$inst/lib" $MAKE check -# distcheck is broken -#LD_LIBRARY_PATH=$PWD/deps/install/lib $MAKE distcheck +LD_LIBRARY_PATH="$inst/lib" $MAKE distcheck -- To view, visit https://gerrit.osmocom.org/789 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I967d4de9682cb2a45210f689ec076ef457841179 Gerrit-PatchSet: 2 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 29 16:05:27 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 16:05:27 +0000 Subject: [PATCH] osmo-iuh[master]: build: fix ranap gen, use same for gen hnbap and rua gen In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/782 to look at the new patch set (#2). build: fix ranap gen, use same for gen hnbap and rua gen fix extraneous rebuild for each make invocation: touch the ranap.stamp file in src/ as the make target suggests. fix for 'make distcheck': ranap gen: move generated sources to builddir, not srcdir. Thus we also -I the builddir include to pick up those headers. hnbap and rua have the same situation as ranap (they generate numerous files from a single make rule). Use the same makefile semantics for those two (commit for ranap gen omitted the same changes for hnbap and rua). The generated headers are thus moved to include/osmocom/*/, so adjust #include statements accordingly (*_common.h, *_ies_defs.h). Also move hnbap_common.h to include/osmocom/hnbap and rua_common.h to include/osmocom/rua, since the *_ies_defs.h want to include them; and since *_ies_defs.h are now in include/osmocom/*, we want a '' include now. Also adjust gitignore. Change-Id: I32213666fcdfc144008fa7d46497c0938d093e86 --- M .gitignore M include/osmocom/hnbap/Makefile.am R include/osmocom/hnbap/hnbap_common.h M include/osmocom/ranap/Makefile.am M include/osmocom/rua/Makefile.am R include/osmocom/rua/rua_common.h M src/.gitignore M src/Makefile.am M src/hnbap_common.c M src/hnbgw_hnbap.c M src/hnbgw_rua.c M src/rua_common.c M src/rua_msg_factory.c M src/tests/hnb-test.c M src/tests/test-hnbap.c 15 files changed, 50 insertions(+), 26 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/82/782/2 diff --git a/.gitignore b/.gitignore index b2538a7..e1430f9 100644 --- a/.gitignore +++ b/.gitignore @@ -35,5 +35,9 @@ tags libosmo-ranap.pc m4 +gen_hnbap.stamp +gen_rua.stamp gen_ranap.stamp +include/osmocom/hnbap/hnbap_ies_defs.h +include/osmocom/rua/rua_ies_defs.h include/osmocom/ranap/ranap_ies_defs.h diff --git a/include/osmocom/hnbap/Makefile.am b/include/osmocom/hnbap/Makefile.am index 7ab5d7f..83654cb 100644 --- a/include/osmocom/hnbap/Makefile.am +++ b/include/osmocom/hnbap/Makefile.am @@ -1,4 +1,5 @@ noinst_HEADERS = \ + hnbap_common.h hnbap_ies_defs.h \ AccessResult.h \ Access-stratum-release-indicator.h \ AdditionalNeighbourInfoList.h \ diff --git a/src/hnbap_common.h b/include/osmocom/hnbap/hnbap_common.h similarity index 100% rename from src/hnbap_common.h rename to include/osmocom/hnbap/hnbap_common.h diff --git a/include/osmocom/ranap/Makefile.am b/include/osmocom/ranap/Makefile.am index 13f1e1c..4728ac8 100644 --- a/include/osmocom/ranap/Makefile.am +++ b/include/osmocom/ranap/Makefile.am @@ -3,8 +3,8 @@ # the build process wants this header file, it should first build # src/ranap_encoder.c and src/ranap_decoder.c. # This rule sucks: -ranap_ies_defs.h: $(top_builddir)/src/ranap_encoder.c - make -C $(top_builddir)/src/ ranap_encoder.c +ranap_ies_defs.h: + $(MAKE) -C $(top_builddir)/src/ gen_ranap.stamp ranap_HEADERS = \ ranap_ies_defs.h \ diff --git a/include/osmocom/rua/Makefile.am b/include/osmocom/rua/Makefile.am index 059dfb8..8e8896d 100644 --- a/include/osmocom/rua/Makefile.am +++ b/include/osmocom/rua/Makefile.am @@ -1,4 +1,5 @@ noinst_HEADERS = \ + rua_common.h rua_ies_defs.h \ RUA_Ansi-41-IDNNS.h \ RUA_Cause.h \ RUA_CauseMisc.h \ diff --git a/src/rua_common.h b/include/osmocom/rua/rua_common.h similarity index 100% rename from src/rua_common.h rename to include/osmocom/rua/rua_common.h diff --git a/src/.gitignore b/src/.gitignore index 9384c58..55bca01 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,13 +1,10 @@ hnbap_decoder.c hnbap_encoder.c -hnbap_ies_defs.h rua_decoder.c rua_encoder.c -rua_ies_defs.h ranap_decoder.c ranap_encoder.c -ranap_ies_defs.h hnbgw diff --git a/src/Makefile.am b/src/Makefile.am index 17e60e2..ffdfef8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,25 +3,48 @@ # Build {hnbap,rua,ranap}_{encoder,decoder}.c using asn1tostruct ASN1_ROOT = $(top_builddir)/asn1/ ASN1TOSTRUCT = $(ASN1_ROOT)/utils/asn1tostruct.py -BUILT_SOURCES = hnbap_decoder.c hnbap_encoder.c rua_decoder.c rua_encoder.c gen_ranap.stamp +BUILT_SOURCES = hnbap_decoder.c hnbap_encoder.c rua_decoder.c rua_encoder.c \ + gen_hnbap.stamp gen_rua.stamp gen_ranap.stamp -hnbap_encoder.c hnbap_decoder.c hnbap_ies_defs.h: $(ASN1_ROOT)/hnbap/HNBAP-PDU-Contents.asn $(ASN1TOSTRUCT) +gen_hnbap.stamp: $(ASN1_ROOT)/hnbap/HNBAP-PDU-Contents.asn $(ASN1TOSTRUCT) $(ASN1TOSTRUCT) -f $< +# We also need to replace the include in the newly generated .c files: + sed -i 's,^#include "hnbap_ies_defs.h",#include ,' hnbap_encoder.c hnbap_decoder.c + sed -i 's,^#include "hnbap_common.h",#include ,' hnbap_encoder.c hnbap_decoder.c hnbap_ies_defs.h + mv hnbap_ies_defs.h $(top_builddir)/include/osmocom/hnbap/ +# this is ugly ^. hnbap_ies_defs.h is generated from asn1tostruct.py here, but +# it should live in include/osmocom/hnbap/. + touch $(top_builddir)/src/$@ -rua_encoder.c rua_decoder.c rua_ies_defs.h: $(ASN1_ROOT)/rua/RUA-PDU-Contents.asn $(ASN1TOSTRUCT) +hnbap_decoder.c hnbap_encoder.c: gen_hnbap.stamp + +gen_rua.stamp: $(ASN1_ROOT)/rua/RUA-PDU-Contents.asn $(ASN1TOSTRUCT) $(ASN1TOSTRUCT) -p RUA_ -f $< +# We also need to replace the include in the newly generated .c files: + sed -i 's,^#include "rua_ies_defs.h",#include ,' rua_encoder.c rua_decoder.c + sed -i 's,^#include "rua_common.h",#include ,' rua_encoder.c rua_decoder.c rua_ies_defs.h + mv rua_ies_defs.h $(top_builddir)/include/osmocom/rua/ +# this is ugly ^. rua_ies_defs.h is generated from asn1tostruct.py here, but +# it should live in include/osmocom/rua/. + touch $(top_builddir)/src/$@ + +rua_decoder.c rua_encoder.c: gen_rua.stamp gen_ranap.stamp: $(ASN1_ROOT)/ranap/RANAP-PDU-Contents.asn $(ASN1TOSTRUCT) $(ASN1TOSTRUCT) -p RANAP_ -f $< # We also need to replace the include in the newly generated .c files: sed -i 's,^#include "ranap_ies_defs.h",#include ,' ranap_encoder.c ranap_decoder.c sed -i 's,^#include "ranap_common.h",#include ,' ranap_encoder.c ranap_decoder.c ranap_ies_defs.h - mv ranap_ies_defs.h $(top_srcdir)/include/osmocom/ranap/ + mv ranap_ies_defs.h $(top_builddir)/include/osmocom/ranap/ # this is ugly ^. ranap_ies_defs.h is generated from asn1tostruct.py here, but # it should live in include/osmocom/ranap/. - touch $(top_builddir)/$@ + touch $(top_builddir)/src/$@ -AM_CFLAGS = -I$(top_srcdir)/include $(OSMOCORE_CFLAGS) $(OSMOVTY_CFLAGS) $(OSMOGSM_CFLAGS) $(OSMONETIF_CFLAGS) $(ASN1C_CFLAGS) $(OSMOSIGTRAN_CFLAGS) +ranap_decoder.c ranap_encoder.c: gen_ranap.stamp + +AM_CFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include \ + $(OSMOCORE_CFLAGS) $(OSMOVTY_CFLAGS) $(OSMOGSM_CFLAGS) \ + $(OSMONETIF_CFLAGS) $(ASN1C_CFLAGS) $(OSMOSIGTRAN_CFLAGS) COMMON_LDADD = -lsctp # build the shared RANAP library @@ -37,9 +60,7 @@ # bin_PROGRAMS = osmo-hnbgw -noinst_HEADERS = hnbap_common.h hnbap_ies_defs.h \ - rua_common.h rua_ies_defs.h \ - context_map.h hnbgw.h hnbgw_cn.h \ +noinst_HEADERS = context_map.h hnbgw.h hnbgw_cn.h \ hnbgw_hnbap.h hnbgw_rua.h hnbgw_ranap.h osmo_hnbgw_SOURCES = hnbap_encoder.c hnbap_decoder.c hnbap_common.c \ diff --git a/src/hnbap_common.c b/src/hnbap_common.c index f321a1c..2cd6519 100644 --- a/src/hnbap_common.c +++ b/src/hnbap_common.c @@ -24,7 +24,7 @@ #include #include -#include "hnbap_common.h" +#include #include "hnbgw.h" static const struct value_string hnbap_cause_radio_vals[] = { diff --git a/src/hnbgw_hnbap.c b/src/hnbgw_hnbap.c index 8a0bc9b..da82608 100644 --- a/src/hnbgw_hnbap.c +++ b/src/hnbgw_hnbap.c @@ -28,11 +28,11 @@ #include #include "asn1helpers.h" +#include #include #include "hnbgw.h" -#include "hnbap_common.h" -#include "hnbap_ies_defs.h" +#include #define IU_MSG_NUM_IES 32 #define IU_MSG_NUM_EXT_IES 32 diff --git a/src/hnbgw_rua.c b/src/hnbgw_rua.c index a6f0100..fc22bfc 100644 --- a/src/hnbgw_rua.c +++ b/src/hnbgw_rua.c @@ -34,8 +34,8 @@ #include "hnbgw.h" #include "hnbgw_ranap.h" -#include "rua_common.h" -#include "rua_ies_defs.h" +#include +#include #include "context_map.h" static int hnbgw_rua_tx(struct hnb_context *ctx, struct msgb *msg) diff --git a/src/rua_common.c b/src/rua_common.c index fcb873e..a5ab044 100644 --- a/src/rua_common.c +++ b/src/rua_common.c @@ -23,7 +23,7 @@ #include -#include "rua_common.h" +#include #include "hnbgw.h" extern int asn1_xer_print; diff --git a/src/rua_msg_factory.c b/src/rua_msg_factory.c index b664509..0bce326 100644 --- a/src/rua_msg_factory.c +++ b/src/rua_msg_factory.c @@ -1,8 +1,8 @@ #include #include -#include "rua_common.h" -#include "rua_ies_defs.h" +#include +#include #include "rua_msg_factory.h" #include "asn1helpers.h" #include "hnbgw.h" diff --git a/src/tests/hnb-test.c b/src/tests/hnb-test.c index af87376..2c41199 100644 --- a/src/tests/hnb-test.c +++ b/src/tests/hnb-test.c @@ -52,8 +52,8 @@ #include "hnb-test.h" #include "hnb-test-layers.h" -#include "hnbap_common.h" -#include "hnbap_ies_defs.h" +#include +#include #include "rua_msg_factory.h" #include "asn1helpers.h" #include diff --git a/src/tests/test-hnbap.c b/src/tests/test-hnbap.c index c6e7d94..ef46070 100644 --- a/src/tests/test-hnbap.c +++ b/src/tests/test-hnbap.c @@ -22,8 +22,8 @@ #include #include "asn1helpers.h" -#include "hnbap_common.h" -#include "hnbap_ies_defs.h" +#include +#include #include "test_common.h" #include -- To view, visit https://gerrit.osmocom.org/782 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I32213666fcdfc144008fa7d46497c0938d093e86 Gerrit-PatchSet: 2 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 29 16:14:52 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 16:14:52 +0000 Subject: [PATCH] openbsc[master]: IuPS: osmo-sgsn: add core IuPS impl, call iu_init() In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/729 to look at the new patch set (#4). IuPS: osmo-sgsn: add core IuPS impl, call iu_init() Add: * gsm0408_gprs_rcvmsg_iu() * sgsn_mm_ctx_by_ue_ctx() * sgsn_mm_ctx_alloc_iu() * sgsn_ranap_iu_event() * sgsn_ranap_rab_ass_resp() Call iu_init() from sgsn_main.c. Add asn_debug impl ("extern" from libasn1c). Initialize asn_debug VTY command (iu_vty_init()). osmo-sgsn build: add libiu and libasn1c, libosmo-sigtran, libosmo-ranap Change-Id: I469ae6ca9ef254d04ee0d2d79bdd65aebcd027b5 --- M openbsc/include/openbsc/gprs_gmm.h M openbsc/include/openbsc/gprs_sgsn.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/gprs_gmm.c M openbsc/src/gprs/gprs_sgsn.c M openbsc/src/gprs/sgsn_libgtp.c M openbsc/src/gprs/sgsn_main.c 7 files changed, 239 insertions(+), 3 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/29/729/4 diff --git a/openbsc/include/openbsc/gprs_gmm.h b/openbsc/include/openbsc/gprs_gmm.h index 8a3ffea..28467d7 100644 --- a/openbsc/include/openbsc/gprs_gmm.h +++ b/openbsc/include/openbsc/gprs_gmm.h @@ -14,6 +14,8 @@ int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme, bool drop_cipherable); +int gsm0408_gprs_rcvmsg_iu(struct msgb *msg, struct gprs_ra_id *ra_id, + uint16_t *sai); int gsm0408_gprs_force_reattach(struct sgsn_mm_ctx *mmctx); int gsm0408_gprs_force_reattach_oldmsg(struct msgb *msg, struct gprs_llc_llme *llme); diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h index b0dd75f..18cbab8 100644 --- a/openbsc/include/openbsc/gprs_sgsn.h +++ b/openbsc/include/openbsc/gprs_sgsn.h @@ -226,6 +226,7 @@ const struct gprs_ra_id *raid); struct sgsn_mm_ctx *sgsn_mm_ctx_by_ptmsi(uint32_t tmsi); struct sgsn_mm_ctx *sgsn_mm_ctx_by_imsi(const char *imsi); +struct sgsn_mm_ctx *sgsn_mm_ctx_by_ue_ctx(const void *uectx); /* look-up by matching TLLI and P-TMSI (think twice before using this) */ struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli_and_ptmsi(uint32_t tlli, @@ -234,6 +235,8 @@ /* Allocate a new SGSN MM context */ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t tlli, const struct gprs_ra_id *raid); +struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_iu(void *uectx); + void sgsn_mm_ctx_cleanup_free(struct sgsn_mm_ctx *ctx); struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx, diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 1b6de46..6a95315 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -3,6 +3,10 @@ $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOCTRL_CFLAGS) \ $(LIBOSMOABIS_CFLAGS) $(LIBOSMOGB_CFLAGS) $(COVERAGE_CFLAGS) \ $(LIBCARES_CFLAGS) $(LIBCRYPTO_CFLAGS) $(LIBGTP_CFLAGS) +if BUILD_IU +AM_CFLAGS += $(LIBASN1C_CFLAGS) $(LIBOSMOSIGTRAN_CFLAGS) $(LIBOSMORANAP_CFLAGS) +endif + OSMO_LIBS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) \ $(LIBOSMOCTRL_LIBS) $(LIBOSMOGB_LIBS) @@ -28,9 +32,15 @@ sgsn_cdr.c sgsn_ares.c \ oap.c oap_messages.c gprs_llc_xid.c osmo_sgsn_LDADD = \ - $(top_builddir)/src/libcommon/libcommon.a \ - -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ + $(top_builddir)/src/libcommon/libcommon.a +if BUILD_IU +osmo_sgsn_LDADD += $(top_builddir)/src/libiu/libiu.a +endif +osmo_sgsn_LDADD += -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ $(LIBCRYPTO_LIBS) -lrt +if BUILD_IU +osmo_sgsn_LDADD += $(LIBOSMOSIGTRAN_LIBS) $(LIBOSMORANAP_LIBS) $(LIBASN1C_LIBS) +endif osmo_gtphub_SOURCES = gtphub_main.c gtphub.c gtphub_sock.c gtphub_ares.c \ gtphub_vty.c sgsn_ares.c gprs_utils.c diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index 1efada9..4c44224 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -33,6 +33,8 @@ #include +#include "bscconfig.h" + #include #include #include @@ -44,6 +46,10 @@ #include #include + +#ifdef BUILD_IU +#include +#endif #include #include @@ -57,6 +63,10 @@ #include #include #include + +#ifdef BUILD_IU +#include +#endif #include @@ -96,6 +106,45 @@ }; static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx); + +#ifdef BUILD_IU +int sgsn_ranap_rab_ass_resp(struct sgsn_mm_ctx *ctx, RANAP_RAB_SetupOrModifiedItemIEs_t *setup_ies); +int sgsn_ranap_iu_event(struct ue_conn_ctx *ctx, enum iu_event_type type, void *data) +{ + struct sgsn_mm_ctx *mm; + int rc = -1; + + mm = sgsn_mm_ctx_by_ue_ctx(ctx); + if (!mm) { + LOGP(DRANAP, LOGL_NOTICE, "Cannot find mm ctx for IU event %i!\n", type); + return rc; + } + + switch (type) { + case IU_EVENT_RAB_ASSIGN: + rc = sgsn_ranap_rab_ass_resp(mm, (RANAP_RAB_SetupOrModifiedItemIEs_t *)data); + break; + case IU_EVENT_IU_RELEASE: + /* fall thru */ + case IU_EVENT_LINK_INVALIDATED: + /* Clean up ue_conn_ctx here */ + LOGMMCTXP(LOGL_INFO, mm, "IU release for imsi %s\n", mm->imsi); + rc = 0; + break; + case IU_EVENT_SECURITY_MODE_COMPLETE: + /* Continue authentication here */ + mm->iu.ue_ctx->integrity_active = 1; + rc = gsm48_gmm_authorize(mm); + break; + default: + LOGP(DRANAP, LOGL_NOTICE, "Unknown event received: %i\n", type); + rc = -1; + break; + } + return rc; +} +#endif + /* Our implementation, should be kept in SGSN */ @@ -2193,6 +2242,45 @@ return rc; } +/* Main entry point for incoming 04.08 GPRS messages from Iu */ +int gsm0408_gprs_rcvmsg_iu(struct msgb *msg, struct gprs_ra_id *ra_id, + uint16_t *sai) +{ + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); + uint8_t pdisc = gsm48_hdr_pdisc(gh); + struct sgsn_mm_ctx *mmctx; + int rc = -EINVAL; + + mmctx = sgsn_mm_ctx_by_ue_ctx(msg->dst); + if (mmctx) { + rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]); + if (ra_id) + memcpy(&mmctx->ra, ra_id, sizeof(mmctx->ra)); + } + + /* MMCTX can be NULL */ + + switch (pdisc) { + case GSM48_PDISC_MM_GPRS: + rc = gsm0408_rcv_gmm(mmctx, msg, NULL, false); +#warning "set drop_cipherable arg for gsm0408_rcv_gmm() from IuPS?" + break; + case GSM48_PDISC_SM_GPRS: + rc = gsm0408_rcv_gsm(mmctx, msg, NULL); + break; + default: + LOGMMCTXP(LOGL_NOTICE, mmctx, + "Unknown GSM 04.08 discriminator 0x%02x: %s\n", + pdisc, osmo_hexdump((uint8_t *)gh, msgb_l3len(msg))); + /* FIXME: return status message */ + break; + } + + /* MMCTX can be invalid */ + + return rc; +} + /* Main entry point for incoming 04.08 GPRS messages from Gb */ int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme, bool drop_cipherable) diff --git a/openbsc/src/gprs/gprs_sgsn.c b/openbsc/src/gprs/gprs_sgsn.c index 9cd992b..19b0a1b 100644 --- a/openbsc/src/gprs/gprs_sgsn.c +++ b/openbsc/src/gprs/gprs_sgsn.c @@ -39,6 +39,7 @@ #include #include #include "openbsc/gprs_llc.h" +#include #include @@ -130,6 +131,20 @@ sgsn->rate_ctrs = rate_ctr_group_alloc(tall_bsc_ctx, &sgsn_ctrg_desc, 0); } +/* look-up an SGSN MM context based on Iu UE context (struct ue_conn_ctx)*/ +struct sgsn_mm_ctx *sgsn_mm_ctx_by_ue_ctx(const void *uectx) +{ + struct sgsn_mm_ctx *ctx; + + llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) { + if (ctx->ran_type == MM_CTX_T_UTRAN_Iu + && uectx == ctx->iu.ue_ctx) + return ctx; + } + + return NULL; +} + /* look-up a SGSN MM context based on TLLI + RAI */ struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(uint32_t tlli, const struct gprs_ra_id *raid) @@ -218,6 +233,32 @@ return ctx; } +/* Allocate a new SGSN MM context */ +struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_iu(void *uectx) +{ + struct sgsn_mm_ctx *ctx; + + ctx = talloc_zero(tall_bsc_ctx, struct sgsn_mm_ctx); + if (!ctx) + return NULL; + + ctx->ran_type = MM_CTX_T_UTRAN_Iu; + ctx->iu.ue_ctx = uectx; + ctx->mm_state = GMM_DEREGISTERED; + ctx->auth_triplet.key_seq = GSM_KEY_SEQ_INVAL; + ctx->ctrg = rate_ctr_group_alloc(ctx, &mmctx_ctrg_desc, 0); + + /* Need to get RAID from IU conn */ + ctx->ra = ctx->iu.ue_ctx->ra_id; + + INIT_LLIST_HEAD(&ctx->pdp_list); + + llist_add(&ctx->list, &sgsn_mm_ctxts); + + return ctx; +} + + /* this is a hard _free_ function, it doesn't clean up the PDP contexts * in libgtp! */ static void sgsn_mm_ctx_free(struct sgsn_mm_ctx *mm) diff --git a/openbsc/src/gprs/sgsn_libgtp.c b/openbsc/src/gprs/sgsn_libgtp.c index be7637a..4a14cf6 100644 --- a/openbsc/src/gprs/sgsn_libgtp.c +++ b/openbsc/src/gprs/sgsn_libgtp.c @@ -34,6 +34,8 @@ #include #include +#include "bscconfig.h" + #include #include #include @@ -47,6 +49,11 @@ #include #include #include + +#ifdef BUILD_IU +#include +#include +#endif #include #include @@ -218,7 +225,10 @@ memcpy(pdp->gsnlc.v, &sgsn->cfg.gtp_listenaddr.sin_addr, sizeof(sgsn->cfg.gtp_listenaddr.sin_addr)); - /* SGSN address for user plane */ + /* SGSN address for user plane + * Default to the control plane addr for now. If we are connected to a + * hnbgw via IuPS we'll need to send a PDP context update with the + * correct IP address after the RAB Assignment is complete */ pdp->gsnlu.l = sizeof(sgsn->cfg.gtp_listenaddr.sin_addr); memcpy(pdp->gsnlu.v, &sgsn->cfg.gtp_listenaddr.sin_addr, sizeof(sgsn->cfg.gtp_listenaddr.sin_addr)); @@ -383,6 +393,72 @@ return EOF; } +#ifdef BUILD_IU +/* Callback for RAB assignment response */ +int sgsn_ranap_rab_ass_resp(struct sgsn_mm_ctx *ctx, RANAP_RAB_SetupOrModifiedItemIEs_t *setup_ies) +{ + uint8_t rab_id; + bool require_pdp_update = false; + struct sgsn_pdp_ctx *pdp = NULL; + RANAP_RAB_SetupOrModifiedItem_t *item = &setup_ies->raB_SetupOrModifiedItem; + + rab_id = item->rAB_ID.buf[0]; + + pdp = sgsn_pdp_ctx_by_nsapi(ctx, rab_id); + if (!pdp) { + LOGP(DRANAP, LOGL_ERROR, "RAB Assignment Response for unknown RAB/NSAPI=%u\n", rab_id); + return -1; + } + + if (item->transportLayerAddress) { + LOGPC(DRANAP, LOGL_INFO, " Setup: (%u/%s)", rab_id, osmo_hexdump(item->transportLayerAddress->buf, + item->transportLayerAddress->size)); + switch (item->transportLayerAddress->size) { + case 7: + /* It must be IPv4 inside a X213 NSAP */ + memcpy(pdp->lib->gsnlu.v, &item->transportLayerAddress->buf[3], 4); + break; + case 4: + /* It must be a raw IPv4 address */ + memcpy(pdp->lib->gsnlu.v, item->transportLayerAddress->buf, 4); + break; + case 16: + /* TODO: It must be a raw IPv6 address */ + case 19: + /* TODO: It must be IPv6 inside a X213 NSAP */ + default: + LOGP(DRANAP, LOGL_ERROR, "RAB Assignment Resp: Unknown " + "transport layer address size %u\n", + item->transportLayerAddress->size); + return -1; + } + require_pdp_update = true; + } + + /* The TEI on the RNC side might have changed, too */ + if (item->iuTransportAssociation && + item->iuTransportAssociation->present == RANAP_IuTransportAssociation_PR_gTP_TEI && + item->iuTransportAssociation->choice.gTP_TEI.buf && + item->iuTransportAssociation->choice.gTP_TEI.size >= 4) { + uint32_t tei = osmo_load32be(item->iuTransportAssociation->choice.gTP_TEI.buf); + LOGP(DRANAP, LOGL_DEBUG, "Updating TEID on RNC side from 0x%08x to 0x%08x\n", + pdp->lib->teid_own, tei); + pdp->lib->teid_own = tei; + require_pdp_update = true; + } + + if (require_pdp_update) + gtp_update_context(pdp->ggsn->gsn, pdp->lib, pdp, &pdp->lib->hisaddr0); + + if (pdp->state != PDP_STATE_CR_CONF) { + send_act_pdp_cont_acc(pdp); + pdp->state = PDP_STATE_CR_CONF; + } + return 0; + +} +#endif + /* Confirmation of a PDP Context Delete */ static int delete_pdp_conf(struct pdp_t *pdp, void *cbp, int cause) { diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c index 52fc985..7d533c0 100644 --- a/openbsc/src/gprs/sgsn_main.c +++ b/openbsc/src/gprs/sgsn_main.c @@ -56,6 +56,8 @@ #include #include #include +#include + #include #include @@ -300,6 +302,13 @@ .num_cat = ARRAY_SIZE(gprs_categories), }; +/* Implement the extern asn_debug from libasn1c to indicate whether the ASN.1 + * binary code decoded and encoded during Iu communication should be logged to + * stderr. See osmocom's libasn1c, asn_internal.h, at "if (asn_debug)": + * http://git.osmocom.org/libasn1c/tree/include/asn1c/asn_internal.h */ +int asn_debug = 0; + +int sgsn_ranap_iu_event(struct ue_conn_ctx *ctx, enum iu_event_type type, void *data); int main(int argc, char **argv) { @@ -326,6 +335,9 @@ osmo_stats_vty_add_cmds(&gprs_log_info); sgsn_vty_init(); ctrl_vty_init(tall_bsc_ctx); +#ifdef BUILD_IU + iu_vty_init(&asn_debug); +#endif handle_options(argc, argv); @@ -417,6 +429,10 @@ } } +#ifdef BUILD_IU + iu_init(tall_bsc_ctx, "127.0.0.2", 14001, gsm0408_gprs_rcvmsg_iu, sgsn_ranap_iu_event); +#endif + if (daemonize) { rc = osmo_daemonize(); if (rc < 0) { -- To view, visit https://gerrit.osmocom.org/729 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I469ae6ca9ef254d04ee0d2d79bdd65aebcd027b5 Gerrit-PatchSet: 4 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: daniel Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Mon Aug 29 16:24:23 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 16:24:23 +0000 Subject: [PATCH] osmo-iuh[master]: build: move headers to include/osmocom/* In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/787 to look at the new patch set (#3). build: move headers to include/osmocom/* This came up while fixing 'make distcheck'; this is certainly not the easiest way but it makes sense to have the headers in include/, like we do in openbsc. The easy alternative might be to add -I$(top_srcdir)/src to src/Makefile.am. Remove -I$(top_srcdir)/src from src/tests/Makefile.am, no longer needed. Change-Id: I5a82e029dcdc4df0a60a31271a4883393fe59234 --- M include/osmocom/iuh/Makefile.am R include/osmocom/iuh/context_map.h R include/osmocom/iuh/hnbgw.h R include/osmocom/iuh/hnbgw_cn.h R include/osmocom/iuh/hnbgw_hnbap.h R include/osmocom/iuh/hnbgw_ranap.h R include/osmocom/iuh/hnbgw_rua.h R include/osmocom/iuh/iu_common.h M include/osmocom/rua/Makefile.am R include/osmocom/rua/rua_msg_factory.h M src/Makefile.am M src/context_map.c M src/hnbap_common.c M src/hnbgw.c M src/hnbgw_cn.c M src/hnbgw_hnbap.c M src/hnbgw_ranap.c M src/hnbgw_rua.c M src/hnbgw_vty.c M src/ranap_common_cn.c M src/rua_common.c M src/rua_msg_factory.c M src/tests/Makefile.am M src/tests/dummy_cn_sua.c M src/tests/hnb-test.c M src/tests/test-ranap.c M src/tests/test_common.c 27 files changed, 41 insertions(+), 37 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/87/787/3 diff --git a/include/osmocom/iuh/Makefile.am b/include/osmocom/iuh/Makefile.am index e2f7126..b2a667d 100644 --- a/include/osmocom/iuh/Makefile.am +++ b/include/osmocom/iuh/Makefile.am @@ -1,2 +1,4 @@ noinst_HEADERS = \ - vty.h + vty.h \ + context_map.h hnbgw.h hnbgw_cn.h \ + hnbgw_hnbap.h hnbgw_rua.h hnbgw_ranap.h diff --git a/src/context_map.h b/include/osmocom/iuh/context_map.h similarity index 100% rename from src/context_map.h rename to include/osmocom/iuh/context_map.h diff --git a/src/hnbgw.h b/include/osmocom/iuh/hnbgw.h similarity index 100% rename from src/hnbgw.h rename to include/osmocom/iuh/hnbgw.h diff --git a/src/hnbgw_cn.h b/include/osmocom/iuh/hnbgw_cn.h similarity index 78% rename from src/hnbgw_cn.h rename to include/osmocom/iuh/hnbgw_cn.h index 469b3d4..d5bec04 100644 --- a/src/hnbgw_cn.h +++ b/include/osmocom/iuh/hnbgw_cn.h @@ -1,5 +1,5 @@ #pragma once -#include "hnbgw.h" +#include struct hnbgw_cnlink *hnbgw_cnlink_init(struct hnb_gw *gw, const char *host, uint16_t port, int is_ps); diff --git a/src/hnbgw_hnbap.h b/include/osmocom/iuh/hnbgw_hnbap.h similarity index 77% rename from src/hnbgw_hnbap.h rename to include/osmocom/iuh/hnbgw_hnbap.h index 955e0aa..cca3550 100644 --- a/src/hnbgw_hnbap.h +++ b/include/osmocom/iuh/hnbgw_hnbap.h @@ -1,6 +1,6 @@ #pragma once -#include "hnbgw.h" +#include int hnbgw_hnbap_rx(struct hnb_context *hnb, struct msgb *msg); int hnbgw_hnbap_init(void); diff --git a/src/hnbgw_ranap.h b/include/osmocom/iuh/hnbgw_ranap.h similarity index 77% rename from src/hnbgw_ranap.h rename to include/osmocom/iuh/hnbgw_ranap.h index 85a2f98..2c55964 100644 --- a/src/hnbgw_ranap.h +++ b/include/osmocom/iuh/hnbgw_ranap.h @@ -1,6 +1,6 @@ #pragma once -#include "hnbgw.h" +#include int hnbgw_ranap_rx(struct msgb *msg, uint8_t *data, size_t len); int hnbgw_ranap_init(void); diff --git a/src/hnbgw_rua.h b/include/osmocom/iuh/hnbgw_rua.h similarity index 93% rename from src/hnbgw_rua.h rename to include/osmocom/iuh/hnbgw_rua.h index d170190..6a890b7 100644 --- a/src/hnbgw_rua.h +++ b/include/osmocom/iuh/hnbgw_rua.h @@ -1,6 +1,6 @@ #pragma once -#include "hnbgw.h" +#include #include int hnbgw_rua_rx(struct hnb_context *hnb, struct msgb *msg); diff --git a/src/iu_common.h b/include/osmocom/iuh/iu_common.h similarity index 100% rename from src/iu_common.h rename to include/osmocom/iuh/iu_common.h diff --git a/include/osmocom/rua/Makefile.am b/include/osmocom/rua/Makefile.am index 49e2150..307f123 100644 --- a/include/osmocom/rua/Makefile.am +++ b/include/osmocom/rua/Makefile.am @@ -1,5 +1,5 @@ noinst_HEADERS = \ - rua_common.h rua_ies_defs.h \ + rua_common.h rua_ies_defs.h rua_msg_factory.h \ RUA_Ansi-41-IDNNS.h \ RUA_Cause.h \ RUA_CauseMisc.h \ diff --git a/src/rua_msg_factory.h b/include/osmocom/rua/rua_msg_factory.h similarity index 100% rename from src/rua_msg_factory.h rename to include/osmocom/rua/rua_msg_factory.h diff --git a/src/Makefile.am b/src/Makefile.am index 2779315..bb1ebbd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -60,9 +60,6 @@ # bin_PROGRAMS = osmo-hnbgw -noinst_HEADERS = context_map.h hnbgw.h hnbgw_cn.h \ - hnbgw_hnbap.h hnbgw_rua.h hnbgw_ranap.h - osmo_hnbgw_SOURCES = hnbap_encoder.c hnbap_decoder.c hnbap_common.c \ rua_encoder.c rua_decoder.c rua_common.c \ rua_msg_factory.c \ diff --git a/src/context_map.c b/src/context_map.c index 22eb605..052133c 100644 --- a/src/context_map.c +++ b/src/context_map.c @@ -24,8 +24,8 @@ #include -#include "hnbgw.h" -#include "context_map.h" +#include +#include /* is a given SCCP USER SAP Connection ID in use for a given CN link? */ static int cn_id_in_use(struct hnbgw_cnlink *cn, uint32_t id) diff --git a/src/hnbap_common.c b/src/hnbap_common.c index 2cd6519..f8cfb13 100644 --- a/src/hnbap_common.c +++ b/src/hnbap_common.c @@ -25,7 +25,7 @@ #include #include -#include "hnbgw.h" +#include static const struct value_string hnbap_cause_radio_vals[] = { { CauseRadioNetwork_overload, "overload" }, diff --git a/src/hnbgw.c b/src/hnbgw.c index 4f23e8d..d50e622 100644 --- a/src/hnbgw.c +++ b/src/hnbgw.c @@ -51,11 +51,11 @@ #include #include -#include "hnbgw.h" -#include "hnbgw_hnbap.h" -#include "hnbgw_rua.h" -#include "hnbgw_cn.h" -#include "context_map.h" +#include +#include +#include +#include +#include static const char * const osmo_hnbgw_copyright = "OsmoHNBGW - Osmocom Home Node B Gateway implementation\r\n" diff --git a/src/hnbgw_cn.c b/src/hnbgw_cn.c index 09b2726..e41788d 100644 --- a/src/hnbgw_cn.c +++ b/src/hnbgw_cn.c @@ -29,11 +29,11 @@ #include #include -#include "hnbgw.h" -#include "hnbgw_rua.h" +#include +#include #include #include -#include "context_map.h" +#include /*********************************************************************** * Outbound RANAP RESET to CN diff --git a/src/hnbgw_hnbap.c b/src/hnbgw_hnbap.c index da82608..2595913 100644 --- a/src/hnbgw_hnbap.c +++ b/src/hnbgw_hnbap.c @@ -31,7 +31,7 @@ #include #include -#include "hnbgw.h" +#include #include #define IU_MSG_NUM_IES 32 diff --git a/src/hnbgw_ranap.c b/src/hnbgw_ranap.c index dde1183..7a505a5 100644 --- a/src/hnbgw_ranap.c +++ b/src/hnbgw_ranap.c @@ -29,8 +29,8 @@ #include "asn1helpers.h" -#include "hnbgw.h" -#include "hnbgw_rua.h" +#include +#include #include #include #include diff --git a/src/hnbgw_rua.c b/src/hnbgw_rua.c index fc22bfc..3f245b5 100644 --- a/src/hnbgw_rua.c +++ b/src/hnbgw_rua.c @@ -32,11 +32,11 @@ #include "asn1helpers.h" -#include "hnbgw.h" -#include "hnbgw_ranap.h" +#include +#include #include #include -#include "context_map.h" +#include static int hnbgw_rua_tx(struct hnb_context *ctx, struct msgb *msg) { diff --git a/src/hnbgw_vty.c b/src/hnbgw_vty.c index 1673c0c..2e3d1e9 100644 --- a/src/hnbgw_vty.c +++ b/src/hnbgw_vty.c @@ -22,8 +22,8 @@ #include -#include "hnbgw.h" -#include "context_map.h" +#include +#include static void *tall_hnb_ctx = NULL; static struct hnb_gw *g_hnb_gw = NULL; diff --git a/src/ranap_common_cn.c b/src/ranap_common_cn.c index 2c80dd0..3736dce 100644 --- a/src/ranap_common_cn.c +++ b/src/ranap_common_cn.c @@ -29,7 +29,7 @@ #include #include -#include "hnbgw.h" +#include static int cn_ranap_rx_initiating_msg_co(void *ctx, RANAP_InitiatingMessage_t *imsg, ranap_message *message) diff --git a/src/rua_common.c b/src/rua_common.c index a5ab044..3c9d773 100644 --- a/src/rua_common.c +++ b/src/rua_common.c @@ -24,7 +24,7 @@ #include #include -#include "hnbgw.h" +#include extern int asn1_xer_print; diff --git a/src/rua_msg_factory.c b/src/rua_msg_factory.c index 0bce326..268f6ac 100644 --- a/src/rua_msg_factory.c +++ b/src/rua_msg_factory.c @@ -3,9 +3,9 @@ #include #include -#include "rua_msg_factory.h" +#include #include "asn1helpers.h" -#include "hnbgw.h" +#include struct msgb *rua_new_udt(struct msgb *inmsg) diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index 2ba3e89..3a99681 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -1,9 +1,14 @@ -AM_CFLAGS = -g -I$(top_srcdir)/src -I$(top_srcdir)/include $(OSMOVTY_CFLAGS) $(OSMOCORE_CFLAGS) $(OSMOGSM_CFLAGS) $(OSMONETIF_CFLAGS) $(ASN1C_CFLAGS) $(OSMOSIGTRAN_CFLAGS) +AM_CFLAGS = -g -I$(top_srcdir)/src/tests \ + -I$(top_srcdir)/include -I$(top_builddir)/include \ + $(OSMOVTY_CFLAGS) $(OSMOCORE_CFLAGS) $(OSMOGSM_CFLAGS) \ + $(OSMONETIF_CFLAGS) $(ASN1C_CFLAGS) $(OSMOSIGTRAN_CFLAGS) COMMON_LIBS = $(OSMOVTY_LIBS) $(OSMOCORE_LIBS) $(OSMOGSM_LIBS) $(ASN1C_LIBS) $(OSMOSIGTRAN_LIBS) -lsctp check_PROGRAMS = test-ranap test-helpers test-hnbap hnb-test dummy-cn +noinst_HEADERS = test_common.h hnb-test.h hnb-test-layers.h + HNBAP_FILES = $(top_srcdir)/src/hnbap_common.c $(top_srcdir)/src/hnbap_decoder.c $(top_srcdir)/src/hnbap_encoder.c RUA_FILES = $(top_srcdir)/src/rua_common.c $(top_srcdir)/src/rua_decoder.c $(top_srcdir)/src/rua_encoder.c $(top_srcdir)/src/rua_msg_factory.c diff --git a/src/tests/dummy_cn_sua.c b/src/tests/dummy_cn_sua.c index c2fc712..f9b4244 100644 --- a/src/tests/dummy_cn_sua.c +++ b/src/tests/dummy_cn_sua.c @@ -24,7 +24,7 @@ #include #include #include -#include "hnbgw.h" +#include int asn1_xer_print = 1; const char *cmdline_bind_addr = "127.0.0.1"; diff --git a/src/tests/hnb-test.c b/src/tests/hnb-test.c index 2c41199..d338077 100644 --- a/src/tests/hnb-test.c +++ b/src/tests/hnb-test.c @@ -54,7 +54,7 @@ #include "hnb-test-layers.h" #include #include -#include "rua_msg_factory.h" +#include #include "asn1helpers.h" #include #include "test_common.h" diff --git a/src/tests/test-ranap.c b/src/tests/test-ranap.c index 7b1f3bf..812a863 100644 --- a/src/tests/test-ranap.c +++ b/src/tests/test-ranap.c @@ -32,7 +32,7 @@ #include "test_common.h" -#include "hnbgw.h" +#include int asn1_xer_print = 1; diff --git a/src/tests/test_common.c b/src/tests/test_common.c index a79d5f5..5a37e7e 100644 --- a/src/tests/test_common.c +++ b/src/tests/test_common.c @@ -37,7 +37,7 @@ #include #include -#include "hnbgw.h" +#include void *talloc_asn1_ctx; -- To view, visit https://gerrit.osmocom.org/787 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I5a82e029dcdc4df0a60a31271a4883393fe59234 Gerrit-PatchSet: 3 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Mon Aug 29 16:24:23 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 16:24:23 +0000 Subject: [PATCH] osmo-iuh[master]: build: parallel build: require ../libosmo-ranap.la from tests/ In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/788 to look at the new patch set (#3). build: parallel build: require ../libosmo-ranap.la from tests/ This rule is bad because it re-invokes $(MAKE), but it seems to fix the parallel build. It should probably be done differently. Change-Id: I8107e08e4c211f20d671f520bf6bab9356f3c90e --- M src/tests/Makefile.am 1 file changed, 3 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/88/788/3 diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index 3a99681..5b51262 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -27,6 +27,9 @@ dummy_cn_SOURCES = $(RANAP_FILES) test_common.c dummy_cn_sua.c dummy_cn_LDADD = $(COMMON_LIBS) $(top_builddir)/src/libosmo-ranap.la +$(top_builddir)/src/libosmo-ranap.la: + $(MAKE) -C $(top_builddir)/src libosmo-ranap.la + # The `:;' works around a Bash 3.2 bug when the output is not writeable. $(srcdir)/package.m4: $(top_srcdir)/configure.ac :;{ \ -- To view, visit https://gerrit.osmocom.org/788 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I8107e08e4c211f20d671f520bf6bab9356f3c90e Gerrit-PatchSet: 3 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 29 16:24:23 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 16:24:23 +0000 Subject: [PATCH] osmo-iuh[master]: jenkins.sh: enable make distcheck In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/789 to look at the new patch set (#3). jenkins.sh: enable make distcheck Change-Id: I967d4de9682cb2a45210f689ec076ef457841179 --- M contrib/jenkins.sh 1 file changed, 1 insertion(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/89/789/3 diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index 72efdbc..8021bbd 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -75,5 +75,4 @@ $MAKE $PARALLEL_MAKE LD_LIBRARY_PATH="$inst/lib" $MAKE check -# distcheck is broken -#LD_LIBRARY_PATH=$PWD/deps/install/lib $MAKE distcheck +LD_LIBRARY_PATH="$inst/lib" $MAKE distcheck -- To view, visit https://gerrit.osmocom.org/789 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I967d4de9682cb2a45210f689ec076ef457841179 Gerrit-PatchSet: 3 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 29 16:24:23 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 16:24:23 +0000 Subject: [PATCH] osmo-iuh[master]: build: fix ranap gen, use same for gen hnbap and rua gen In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/782 to look at the new patch set (#3). build: fix ranap gen, use same for gen hnbap and rua gen fix extraneous rebuild for each make invocation: touch the ranap.stamp file in src/ as the make target suggests. fix for 'make distcheck': ranap gen: move generated sources to builddir, not srcdir. Thus we also -I the builddir include to pick up those headers. hnbap and rua have the same situation as ranap (they generate numerous files from a single make rule). Use the same makefile semantics for those two (commit for ranap gen omitted the same changes for hnbap and rua). The generated headers are thus moved to include/osmocom/*/, so adjust #include statements accordingly (*_common.h, *_ies_defs.h). Also move hnbap_common.h to include/osmocom/hnbap and rua_common.h to include/osmocom/rua, since the *_ies_defs.h want to include them; and since *_ies_defs.h are now in include/osmocom/*, we want a '' include now. Also adjust gitignore. Change-Id: I32213666fcdfc144008fa7d46497c0938d093e86 --- M .gitignore M include/osmocom/hnbap/Makefile.am R include/osmocom/hnbap/hnbap_common.h M include/osmocom/ranap/Makefile.am M include/osmocom/rua/Makefile.am R include/osmocom/rua/rua_common.h M src/.gitignore M src/Makefile.am M src/hnbap_common.c M src/hnbgw_hnbap.c M src/hnbgw_rua.c M src/rua_common.c M src/rua_msg_factory.c M src/tests/hnb-test-rua.c M src/tests/hnb-test.c M src/tests/test-hnbap.c 16 files changed, 51 insertions(+), 27 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/82/782/3 diff --git a/.gitignore b/.gitignore index b2538a7..e1430f9 100644 --- a/.gitignore +++ b/.gitignore @@ -35,5 +35,9 @@ tags libosmo-ranap.pc m4 +gen_hnbap.stamp +gen_rua.stamp gen_ranap.stamp +include/osmocom/hnbap/hnbap_ies_defs.h +include/osmocom/rua/rua_ies_defs.h include/osmocom/ranap/ranap_ies_defs.h diff --git a/include/osmocom/hnbap/Makefile.am b/include/osmocom/hnbap/Makefile.am index 7ab5d7f..83654cb 100644 --- a/include/osmocom/hnbap/Makefile.am +++ b/include/osmocom/hnbap/Makefile.am @@ -1,4 +1,5 @@ noinst_HEADERS = \ + hnbap_common.h hnbap_ies_defs.h \ AccessResult.h \ Access-stratum-release-indicator.h \ AdditionalNeighbourInfoList.h \ diff --git a/src/hnbap_common.h b/include/osmocom/hnbap/hnbap_common.h similarity index 100% rename from src/hnbap_common.h rename to include/osmocom/hnbap/hnbap_common.h diff --git a/include/osmocom/ranap/Makefile.am b/include/osmocom/ranap/Makefile.am index 13f1e1c..4728ac8 100644 --- a/include/osmocom/ranap/Makefile.am +++ b/include/osmocom/ranap/Makefile.am @@ -3,8 +3,8 @@ # the build process wants this header file, it should first build # src/ranap_encoder.c and src/ranap_decoder.c. # This rule sucks: -ranap_ies_defs.h: $(top_builddir)/src/ranap_encoder.c - make -C $(top_builddir)/src/ ranap_encoder.c +ranap_ies_defs.h: + $(MAKE) -C $(top_builddir)/src/ gen_ranap.stamp ranap_HEADERS = \ ranap_ies_defs.h \ diff --git a/include/osmocom/rua/Makefile.am b/include/osmocom/rua/Makefile.am index 059dfb8..8e8896d 100644 --- a/include/osmocom/rua/Makefile.am +++ b/include/osmocom/rua/Makefile.am @@ -1,4 +1,5 @@ noinst_HEADERS = \ + rua_common.h rua_ies_defs.h \ RUA_Ansi-41-IDNNS.h \ RUA_Cause.h \ RUA_CauseMisc.h \ diff --git a/src/rua_common.h b/include/osmocom/rua/rua_common.h similarity index 100% rename from src/rua_common.h rename to include/osmocom/rua/rua_common.h diff --git a/src/.gitignore b/src/.gitignore index 9384c58..55bca01 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,13 +1,10 @@ hnbap_decoder.c hnbap_encoder.c -hnbap_ies_defs.h rua_decoder.c rua_encoder.c -rua_ies_defs.h ranap_decoder.c ranap_encoder.c -ranap_ies_defs.h hnbgw diff --git a/src/Makefile.am b/src/Makefile.am index 17e60e2..ffdfef8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,25 +3,48 @@ # Build {hnbap,rua,ranap}_{encoder,decoder}.c using asn1tostruct ASN1_ROOT = $(top_builddir)/asn1/ ASN1TOSTRUCT = $(ASN1_ROOT)/utils/asn1tostruct.py -BUILT_SOURCES = hnbap_decoder.c hnbap_encoder.c rua_decoder.c rua_encoder.c gen_ranap.stamp +BUILT_SOURCES = hnbap_decoder.c hnbap_encoder.c rua_decoder.c rua_encoder.c \ + gen_hnbap.stamp gen_rua.stamp gen_ranap.stamp -hnbap_encoder.c hnbap_decoder.c hnbap_ies_defs.h: $(ASN1_ROOT)/hnbap/HNBAP-PDU-Contents.asn $(ASN1TOSTRUCT) +gen_hnbap.stamp: $(ASN1_ROOT)/hnbap/HNBAP-PDU-Contents.asn $(ASN1TOSTRUCT) $(ASN1TOSTRUCT) -f $< +# We also need to replace the include in the newly generated .c files: + sed -i 's,^#include "hnbap_ies_defs.h",#include ,' hnbap_encoder.c hnbap_decoder.c + sed -i 's,^#include "hnbap_common.h",#include ,' hnbap_encoder.c hnbap_decoder.c hnbap_ies_defs.h + mv hnbap_ies_defs.h $(top_builddir)/include/osmocom/hnbap/ +# this is ugly ^. hnbap_ies_defs.h is generated from asn1tostruct.py here, but +# it should live in include/osmocom/hnbap/. + touch $(top_builddir)/src/$@ -rua_encoder.c rua_decoder.c rua_ies_defs.h: $(ASN1_ROOT)/rua/RUA-PDU-Contents.asn $(ASN1TOSTRUCT) +hnbap_decoder.c hnbap_encoder.c: gen_hnbap.stamp + +gen_rua.stamp: $(ASN1_ROOT)/rua/RUA-PDU-Contents.asn $(ASN1TOSTRUCT) $(ASN1TOSTRUCT) -p RUA_ -f $< +# We also need to replace the include in the newly generated .c files: + sed -i 's,^#include "rua_ies_defs.h",#include ,' rua_encoder.c rua_decoder.c + sed -i 's,^#include "rua_common.h",#include ,' rua_encoder.c rua_decoder.c rua_ies_defs.h + mv rua_ies_defs.h $(top_builddir)/include/osmocom/rua/ +# this is ugly ^. rua_ies_defs.h is generated from asn1tostruct.py here, but +# it should live in include/osmocom/rua/. + touch $(top_builddir)/src/$@ + +rua_decoder.c rua_encoder.c: gen_rua.stamp gen_ranap.stamp: $(ASN1_ROOT)/ranap/RANAP-PDU-Contents.asn $(ASN1TOSTRUCT) $(ASN1TOSTRUCT) -p RANAP_ -f $< # We also need to replace the include in the newly generated .c files: sed -i 's,^#include "ranap_ies_defs.h",#include ,' ranap_encoder.c ranap_decoder.c sed -i 's,^#include "ranap_common.h",#include ,' ranap_encoder.c ranap_decoder.c ranap_ies_defs.h - mv ranap_ies_defs.h $(top_srcdir)/include/osmocom/ranap/ + mv ranap_ies_defs.h $(top_builddir)/include/osmocom/ranap/ # this is ugly ^. ranap_ies_defs.h is generated from asn1tostruct.py here, but # it should live in include/osmocom/ranap/. - touch $(top_builddir)/$@ + touch $(top_builddir)/src/$@ -AM_CFLAGS = -I$(top_srcdir)/include $(OSMOCORE_CFLAGS) $(OSMOVTY_CFLAGS) $(OSMOGSM_CFLAGS) $(OSMONETIF_CFLAGS) $(ASN1C_CFLAGS) $(OSMOSIGTRAN_CFLAGS) +ranap_decoder.c ranap_encoder.c: gen_ranap.stamp + +AM_CFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include \ + $(OSMOCORE_CFLAGS) $(OSMOVTY_CFLAGS) $(OSMOGSM_CFLAGS) \ + $(OSMONETIF_CFLAGS) $(ASN1C_CFLAGS) $(OSMOSIGTRAN_CFLAGS) COMMON_LDADD = -lsctp # build the shared RANAP library @@ -37,9 +60,7 @@ # bin_PROGRAMS = osmo-hnbgw -noinst_HEADERS = hnbap_common.h hnbap_ies_defs.h \ - rua_common.h rua_ies_defs.h \ - context_map.h hnbgw.h hnbgw_cn.h \ +noinst_HEADERS = context_map.h hnbgw.h hnbgw_cn.h \ hnbgw_hnbap.h hnbgw_rua.h hnbgw_ranap.h osmo_hnbgw_SOURCES = hnbap_encoder.c hnbap_decoder.c hnbap_common.c \ diff --git a/src/hnbap_common.c b/src/hnbap_common.c index f321a1c..2cd6519 100644 --- a/src/hnbap_common.c +++ b/src/hnbap_common.c @@ -24,7 +24,7 @@ #include #include -#include "hnbap_common.h" +#include #include "hnbgw.h" static const struct value_string hnbap_cause_radio_vals[] = { diff --git a/src/hnbgw_hnbap.c b/src/hnbgw_hnbap.c index 8a0bc9b..da82608 100644 --- a/src/hnbgw_hnbap.c +++ b/src/hnbgw_hnbap.c @@ -28,11 +28,11 @@ #include #include "asn1helpers.h" +#include #include #include "hnbgw.h" -#include "hnbap_common.h" -#include "hnbap_ies_defs.h" +#include #define IU_MSG_NUM_IES 32 #define IU_MSG_NUM_EXT_IES 32 diff --git a/src/hnbgw_rua.c b/src/hnbgw_rua.c index a6f0100..fc22bfc 100644 --- a/src/hnbgw_rua.c +++ b/src/hnbgw_rua.c @@ -34,8 +34,8 @@ #include "hnbgw.h" #include "hnbgw_ranap.h" -#include "rua_common.h" -#include "rua_ies_defs.h" +#include +#include #include "context_map.h" static int hnbgw_rua_tx(struct hnb_context *ctx, struct msgb *msg) diff --git a/src/rua_common.c b/src/rua_common.c index fcb873e..a5ab044 100644 --- a/src/rua_common.c +++ b/src/rua_common.c @@ -23,7 +23,7 @@ #include -#include "rua_common.h" +#include #include "hnbgw.h" extern int asn1_xer_print; diff --git a/src/rua_msg_factory.c b/src/rua_msg_factory.c index b664509..0bce326 100644 --- a/src/rua_msg_factory.c +++ b/src/rua_msg_factory.c @@ -1,8 +1,8 @@ #include #include -#include "rua_common.h" -#include "rua_ies_defs.h" +#include +#include #include "rua_msg_factory.h" #include "asn1helpers.h" #include "hnbgw.h" diff --git a/src/tests/hnb-test-rua.c b/src/tests/hnb-test-rua.c index 69c41eb..a218852 100644 --- a/src/tests/hnb-test-rua.c +++ b/src/tests/hnb-test-rua.c @@ -1,6 +1,6 @@ #include -#include "../rua_ies_defs.h" +#include #include "hnb-test-layers.h" diff --git a/src/tests/hnb-test.c b/src/tests/hnb-test.c index af87376..2c41199 100644 --- a/src/tests/hnb-test.c +++ b/src/tests/hnb-test.c @@ -52,8 +52,8 @@ #include "hnb-test.h" #include "hnb-test-layers.h" -#include "hnbap_common.h" -#include "hnbap_ies_defs.h" +#include +#include #include "rua_msg_factory.h" #include "asn1helpers.h" #include diff --git a/src/tests/test-hnbap.c b/src/tests/test-hnbap.c index c6e7d94..ef46070 100644 --- a/src/tests/test-hnbap.c +++ b/src/tests/test-hnbap.c @@ -22,8 +22,8 @@ #include #include "asn1helpers.h" -#include "hnbap_common.h" -#include "hnbap_ies_defs.h" +#include +#include #include "test_common.h" #include -- To view, visit https://gerrit.osmocom.org/782 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I32213666fcdfc144008fa7d46497c0938d093e86 Gerrit-PatchSet: 3 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Mon Aug 29 16:29:39 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 16:29:39 +0000 Subject: osmo-bts[master]: heed VTY 'line vty'/'bind' command In-Reply-To: References: Message-ID: Patch Set 1: (1 comment) https://gerrit.osmocom.org/#/c/754/1/src/common/main.c File src/common/main.c: Line 308: rc = telnet_init_dynif(tall_bts_ctx, NULL, vty_get_bind_addr(), > it might be much better to log this inside libosmocore/libosmovty, so every Then I would place the LOGP and telnet_init_dynif() call in a new vty_telnet_init(void *ctx, void *priv) function. Is that what you have in mind? -- To view, visit https://gerrit.osmocom.org/754 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ic4ab32aee08d8a779adeb9943892de0c828c7b3d Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Mon Aug 29 16:38:14 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 16:38:14 +0000 Subject: openbsc[master]: sms: change rp err cause of smpp_try_deliver errors In-Reply-To: References: Message-ID: Patch Set 3: (1 comment) https://gerrit.osmocom.org/#/c/551/3/openbsc/src/libmsc/gsm_04_11.c File openbsc/src/libmsc/gsm_04_11.c: Line 298: LOGP(DLSMS, LOGL_ERROR, "While trying to deliver a SMS the error code %d received. Sending rp err cause 41 to ms\n", rc); how about "SMS delivery error: %d. Sending 41: 'Temporary failure' to MS." for brevity, and it would be good to log subscr_name(conn->subscr) at the start. -- To view, visit https://gerrit.osmocom.org/551 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia03e50ce2bd9a7d1054cc5a6000fd73bd3497c03 Gerrit-PatchSet: 3 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: lynxis lazus Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Mon Aug 29 16:43:06 2016 From: gerrit-no-reply at lists.osmocom.org (lynxis lazus) Date: Mon, 29 Aug 2016 16:43:06 +0000 Subject: [PATCH] openbsc[master]: fix mistypes, spaces and tabs Message-ID: Review at https://gerrit.osmocom.org/792 fix mistypes, spaces and tabs Change-Id: I651473f638365bbd333c4c80d223cdd023dd2c51 --- M openbsc/src/libbsc/chan_alloc.c M openbsc/src/libmsc/gsm_04_08.c M openbsc/src/libmsc/mncc_builtin.c 3 files changed, 17 insertions(+), 18 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/92/792/1 diff --git a/openbsc/src/libbsc/chan_alloc.c b/openbsc/src/libbsc/chan_alloc.c index 7b0c3e6..367139c 100644 --- a/openbsc/src/libbsc/chan_alloc.c +++ b/openbsc/src/libbsc/chan_alloc.c @@ -303,7 +303,7 @@ } break; case GSM_LCHAN_TCH_H: - lchan =_lc_find_bts(bts, GSM_PCHAN_TCH_H); + lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_H); /* If we don't have TCH/H available, fall-back to TCH/F */ if (!lchan) { lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_F); diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c index c4ecf1c..fc5cd67 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/src/libmsc/gsm_04_08.c @@ -464,7 +464,7 @@ LOGP(DMM, LOGL_ERROR, "Failed to create msg for LOCATION UPDATING REJECT.\n"); return -1; } - + msg->lchan = conn->lchan; LOGP(DMM, LOGL_INFO, "Subscriber %s: LOCATION UPDATING REJECT " @@ -482,7 +482,7 @@ struct gsm48_hdr *gh; struct gsm48_loc_area_id *lai; uint8_t *mid; - + msg->lchan = conn->lchan; gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); @@ -699,7 +699,7 @@ /* no sim card... FIXME: what to do ? */ DEBUGPC(DMM, "unimplemented mobile identity type\n"); break; - default: + default: DEBUGPC(DMM, "unknown mobile identity type\n"); break; } @@ -1081,7 +1081,7 @@ /* no sim card... FIXME: what to do ? */ DEBUGPC(DMM, ": unimplemented mobile identity type\n"); break; - default: + default: DEBUGPC(DMM, ": unknown mobile identity type\n"); break; } @@ -1256,7 +1256,7 @@ apdu_id_flags = gh->data[0]; apdu_len = gh->data[1]; apdu_data = gh->data+2; - + DEBUGP(DRR, "RX APPLICATION INFO id/flags=0x%02x apdu_len=%u apdu=%s", apdu_id_flags, apdu_len, osmo_hexdump(apdu_data, apdu_len)); @@ -1292,10 +1292,10 @@ struct gsm48_hdr *gh; msg->lchan = conn->lchan; - + DEBUGP(DRR, "TX APPLICATION INFO id=0x%02x, len=%u\n", apdu_id, apdu_len); - + gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 2 + apdu_len); gh->proto_discr = GSM48_PDISC_RR; gh->msg_type = GSM48_MT_RR_APP_INFO; @@ -1392,7 +1392,7 @@ "Sending '%s' to MNCC.\n", get_mncc_name(msg_type)); mncc->msg_type = msg_type; - + msg = msgb_alloc(sizeof(struct gsm_mncc), "MNCC"); if (!msg) return -ENOMEM; @@ -2034,7 +2034,7 @@ trans_free(trans); return rc; } - + /* Get free transaction_id */ trans_id = trans_assign_trans_id(trans->net, trans->subscr, GSM48_PDISC_CC, 0); @@ -2077,7 +2077,7 @@ /* signal */ if (setup->fields & MNCC_F_SIGNAL) gsm48_encode_signal(msg, setup->signal); - + new_cc_state(trans, GSM_CSTATE_CALL_PRESENT); rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MT_SETUP]); @@ -2165,7 +2165,7 @@ unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh); struct tlv_parsed tp; struct gsm_mncc alerting; - + gsm48_stop_cc_timer(trans); gsm48_start_cc_timer(trans, 0x301, GSM48_T301); @@ -2217,7 +2217,7 @@ gsm48_encode_useruser(msg, 0, &alerting->useruser); new_cc_state(trans, GSM_CSTATE_CALL_DELIVERED); - + return gsm48_conn_sendmsg(msg, trans->conn, trans); } @@ -2320,7 +2320,7 @@ new_cc_state(trans, GSM_CSTATE_ACTIVE); rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MO_CONNECT_ACK]); - + memset(&connect_ack, 0, sizeof(struct gsm_mncc)); connect_ack.callref = trans->callref; @@ -2584,7 +2584,7 @@ gh->msg_type = GSM48_MT_CC_RELEASE_COMPL; trans->callref = 0; - + gsm48_stop_cc_timer(trans); /* cause */ @@ -3667,7 +3667,7 @@ LOGP(DRLL, LOGL_DEBUG, "Dispatching 04.08 message, pdisc=%d\n", pdisc); if (silent_call_reroute(conn, msg)) return silent_call_rx(conn, msg); - + switch (pdisc) { case GSM48_PDISC_CC: release_anchor(conn); diff --git a/openbsc/src/libmsc/mncc_builtin.c b/openbsc/src/libmsc/mncc_builtin.c index ee98d2d..716cfe0 100644 --- a/openbsc/src/libmsc/mncc_builtin.c +++ b/openbsc/src/libmsc/mncc_builtin.c @@ -1,6 +1,5 @@ /* mncc_builtin.c - default, minimal built-in MNCC Application for - * standalone bsc_hack (netowrk-in-the-box mode) */ - + * standalone bsc_hack (network-in-the-box mode) */ /* (C) 2008-2010 by Harald Welte * (C) 2009 by Andreas Eversberg * All Rights Reserved -- To view, visit https://gerrit.osmocom.org/792 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I651473f638365bbd333c4c80d223cdd023dd2c51 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus From gerrit-no-reply at lists.osmocom.org Mon Aug 29 16:45:52 2016 From: gerrit-no-reply at lists.osmocom.org (lynxis lazus) Date: Mon, 29 Aug 2016 16:45:52 +0000 Subject: [PATCH] openbsc[master]: bts: extend bts_chan_load to allow counting tch only Message-ID: Review at https://gerrit.osmocom.org/793 bts: extend bts_chan_load to allow counting tch only Change-Id: I86f1d502649747b6b9aefcb39081b14110e8f494 --- M openbsc/include/openbsc/chan_alloc.h M openbsc/src/libbsc/bsc_ctrl_commands.c M openbsc/src/libbsc/bsc_vty.c M openbsc/src/libbsc/chan_alloc.c M openbsc/src/libbsc/paging.c 5 files changed, 30 insertions(+), 7 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/93/793/1 diff --git a/openbsc/include/openbsc/chan_alloc.h b/openbsc/include/openbsc/chan_alloc.h index 78242e5..d919b51 100644 --- a/openbsc/include/openbsc/chan_alloc.h +++ b/openbsc/include/openbsc/chan_alloc.h @@ -46,7 +46,7 @@ struct load_counter pchan[_GSM_PCHAN_MAX]; }; -void bts_chan_load(struct pchan_load *cl, const struct gsm_bts *bts); +void bts_chan_load(struct pchan_load *cl, const struct gsm_bts *bts, int only_count_tch); void network_chan_load(struct pchan_load *pl, struct gsm_network *net); int trx_is_usable(struct gsm_bts_trx *trx); diff --git a/openbsc/src/libbsc/bsc_ctrl_commands.c b/openbsc/src/libbsc/bsc_ctrl_commands.c index 7e84797..3f4fee2 100644 --- a/openbsc/src/libbsc/bsc_ctrl_commands.c +++ b/openbsc/src/libbsc/bsc_ctrl_commands.c @@ -239,7 +239,7 @@ bts = cmd->node; memset(&pl, 0, sizeof(pl)); - bts_chan_load(&pl, bts); + bts_chan_load(&pl, bts, 0); cmd->reply = talloc_strdup(cmd, ""); diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c index fbaf06b..bcbf1cf 100644 --- a/openbsc/src/libbsc/bsc_vty.c +++ b/openbsc/src/libbsc/bsc_vty.c @@ -329,7 +329,7 @@ /* FIXME: chan_desc */ memset(&pl, 0, sizeof(pl)); - bts_chan_load(&pl, bts); + bts_chan_load(&pl, bts, 0); vty_out(vty, " Current Channel Load:%s", VTY_NEWLINE); dump_pchan_load_vty(vty, " ", &pl); } diff --git a/openbsc/src/libbsc/chan_alloc.c b/openbsc/src/libbsc/chan_alloc.c index 7b0c3e6..03d44e0 100644 --- a/openbsc/src/libbsc/chan_alloc.c +++ b/openbsc/src/libbsc/chan_alloc.c @@ -514,7 +514,28 @@ return NULL; } -void bts_chan_load(struct pchan_load *cl, const struct gsm_bts *bts) +static int chan_is_tch(struct gsm_bts_trx_ts *ts) +{ + switch (ts->pchan) { + case GSM_PCHAN_TCH_F: + case GSM_PCHAN_TCH_H: + return 1; + case GSM_PCHAN_TCH_F_PDCH: + case GSM_PCHAN_TCH_F_TCH_H_PDCH: + if (ts->dyn.pchan_is == GSM_PCHAN_TCH_F || + ts->dyn.pchan_is == GSM_PCHAN_TCH_H) + return 1; + else + return 0; + default: + return 0; + } +} + + + +void bts_chan_load(struct pchan_load *cl, const struct gsm_bts *bts, + int only_count_tch) { struct gsm_bts_trx *trx; @@ -534,6 +555,9 @@ /* skip administratively deactivated timeslots */ if (!nm_is_running(&ts->mo.nm_state)) + continue; + + if (only_count_tch && !chan_is_tch(ts)) continue; subslots = ts_subslots(ts); @@ -561,6 +585,5 @@ memset(pl, 0, sizeof(*pl)); llist_for_each_entry(bts, &net->bts_list, list) - bts_chan_load(pl, bts); + bts_chan_load(pl, bts, 0); } - diff --git a/openbsc/src/libbsc/paging.c b/openbsc/src/libbsc/paging.c index 03c91fd..d6e07c0 100644 --- a/openbsc/src/libbsc/paging.c +++ b/openbsc/src/libbsc/paging.c @@ -119,7 +119,7 @@ int count; memset(&pl, 0, sizeof(pl)); - bts_chan_load(&pl, bts); + bts_chan_load(&pl, bts, 0); switch (rsl_type) { case RSL_CHANNEED_TCH_F: -- To view, visit https://gerrit.osmocom.org/793 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I86f1d502649747b6b9aefcb39081b14110e8f494 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus From gerrit-no-reply at lists.osmocom.org Mon Aug 29 17:05:30 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 17:05:30 +0000 Subject: [PATCH] openbsc[master]: libmsc/bsc: split rate counters into bsc and msc group In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/646 to look at the new patch set (#5). libmsc/bsc: split rate counters into bsc and msc group Tweaked-By: Neels Hofmeyr Change-Id: I7361033cd1eb919ec3c2ea2652f40ab8c75b2f99 --- M openbsc/include/openbsc/gsm_data.h M openbsc/src/libbsc/abis_rsl.c M openbsc/src/libbsc/bsc_init.c M openbsc/src/libbsc/bsc_vty.c M openbsc/src/libbsc/gsm_04_08_utils.c M openbsc/src/libbsc/handover_logic.c M openbsc/src/libbsc/net_init.c M openbsc/src/libbsc/paging.c M openbsc/src/libmsc/gsm_04_08.c M openbsc/src/libmsc/gsm_04_11.c M openbsc/src/libmsc/vty_interface_layer3.c 11 files changed, 110 insertions(+), 94 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/46/646/5 diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 6168a6b..daa5a4d 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -150,25 +150,49 @@ #include "gsm_data_shared.h" -/* Some statistics of our network */ enum { - MSC_CTR_CHREQ_TOTAL, - MSC_CTR_CHREQ_NO_CHANNEL, - MSC_CTR_HANDOVER_ATTEMPTED, - MSC_CTR_HANDOVER_NO_CHANNEL, - MSC_CTR_HANDOVER_TIMEOUT, - MSC_CTR_HANDOVER_COMPLETED, - MSC_CTR_HANDOVER_FAILED, + BSC_CTR_CHREQ_TOTAL, + BSC_CTR_CHREQ_NO_CHANNEL, + BSC_CTR_HANDOVER_ATTEMPTED, + BSC_CTR_HANDOVER_NO_CHANNEL, + BSC_CTR_HANDOVER_TIMEOUT, + BSC_CTR_HANDOVER_COMPLETED, + BSC_CTR_HANDOVER_FAILED, + BSC_CTR_PAGING_ATTEMPTED, + BSC_CTR_PAGING_DETACHED, + BSC_CTR_PAGING_COMPLETED, + BSC_CTR_PAGING_EXPIRED, + BSC_CTR_CHAN_RF_FAIL, + BSC_CTR_CHAN_RLL_ERR, + BSC_CTR_BTS_OML_FAIL, + BSC_CTR_BTS_RSL_FAIL, +}; + +static const struct rate_ctr_desc bsc_ctr_description[] = { + [BSC_CTR_CHREQ_TOTAL] = {"chreq.total", "Received channel requests."}, + [BSC_CTR_CHREQ_NO_CHANNEL] = {"chreq.no_channel", "Sent to MS no channel available."}, + [BSC_CTR_HANDOVER_ATTEMPTED] = {"handover.attempted", "Received handover attempts."}, + [BSC_CTR_HANDOVER_NO_CHANNEL] = {"handover.no_channel", "Sent no channel available responses."}, + [BSC_CTR_HANDOVER_TIMEOUT] = {"handover.timeout", "Count the amount of timeouts of timer T3103."}, + [BSC_CTR_HANDOVER_COMPLETED] = {"handover.completed", "Received handover completed."}, + [BSC_CTR_HANDOVER_FAILED] = {"handover.failed", "Receive HO FAIL messages."}, + [BSC_CTR_PAGING_ATTEMPTED] = {"paging.attempted", "Paging attempts for a MS."}, + [BSC_CTR_PAGING_DETACHED] = {"paging.detached", "Counts the amount of paging attempts which couldn't sent out any paging request because no responsible bts found."}, + [BSC_CTR_PAGING_COMPLETED] = {"paging.completed", "Paging successful completed."}, + [BSC_CTR_PAGING_EXPIRED] = {"paging.expired", "Paging Request expired because of timeout T3113."}, + [BSC_CTR_CHAN_RF_FAIL] = {"chan.rf_fail", "Received a RF failure indication from BTS."}, + [BSC_CTR_CHAN_RLL_ERR] = {"chan.rll_err", "Received a RLL failure with T200 cause from BTS."}, + [BSC_CTR_BTS_OML_FAIL] = {"bts.oml_fail", "Received a TEI down on a OML link."}, + [BSC_CTR_BTS_RSL_FAIL] = {"bts.rsl_fail", "Received a TEI down on a OML link."}, +}; + +enum { MSC_CTR_LOC_UPDATE_TYPE_ATTACH, MSC_CTR_LOC_UPDATE_TYPE_NORMAL, MSC_CTR_LOC_UPDATE_TYPE_PERIODIC, MSC_CTR_LOC_UPDATE_TYPE_DETACH, MSC_CTR_LOC_UPDATE_RESP_REJECT, MSC_CTR_LOC_UPDATE_RESP_ACCEPT, - MSC_CTR_PAGING_ATTEMPTED, - MSC_CTR_PAGING_DETACHED, - MSC_CTR_PAGING_COMPLETED, - MSC_CTR_PAGING_EXPIRED, MSC_CTR_SMS_SUBMITTED, MSC_CTR_SMS_NO_RECEIVER, MSC_CTR_SMS_DELIVERED, @@ -178,30 +202,15 @@ MSC_CTR_CALL_MO_CONNECT_ACK, MSC_CTR_CALL_MT_SETUP, MSC_CTR_CALL_MT_CONNECT, - MSC_CTR_CHAN_RF_FAIL, - MSC_CTR_CHAN_RLL_ERR, - MSC_CTR_BTS_OML_FAIL, - MSC_CTR_BTS_RSL_FAIL, }; static const struct rate_ctr_desc msc_ctr_description[] = { - [MSC_CTR_CHREQ_TOTAL] = {"chreq.total", "Received channel requests."}, - [MSC_CTR_CHREQ_NO_CHANNEL] = {"chreq.no_channel", "Sent to MS no channel available."}, - [MSC_CTR_HANDOVER_ATTEMPTED] = {"handover.attempted", "Received handover attempts."}, - [MSC_CTR_HANDOVER_NO_CHANNEL] = {"handover.no_channel", "Sent no channel available responses."}, - [MSC_CTR_HANDOVER_TIMEOUT] = {"handover.timeout", "Count the amount of timeouts of timer T3103."}, - [MSC_CTR_HANDOVER_COMPLETED] = {"handover.completed", "Received handover completed."}, - [MSC_CTR_HANDOVER_FAILED] = {"handover.failed", "Receive HO FAIL messages."}, [MSC_CTR_LOC_UPDATE_TYPE_ATTACH] = {"loc_update_type.attach", "Received location update imsi attach requests."}, [MSC_CTR_LOC_UPDATE_TYPE_NORMAL] = {"loc_update_type.normal", "Received location update normal requests."}, [MSC_CTR_LOC_UPDATE_TYPE_PERIODIC] = {"loc_update_type.periodic", "Received location update periodic requests."}, [MSC_CTR_LOC_UPDATE_TYPE_DETACH] = {"loc_update_type.detach", "Received location update detach indication."}, [MSC_CTR_LOC_UPDATE_RESP_REJECT] = {"loc_update_resp.reject", "Sent location update reject responses."}, [MSC_CTR_LOC_UPDATE_RESP_ACCEPT] = {"loc_update_resp.accept", "Sent location update accept responses."}, - [MSC_CTR_PAGING_ATTEMPTED] = {"paging.attempted", "Paging attempts for a MS."}, - [MSC_CTR_PAGING_DETACHED] = {"paging.detached", "Counts the amount of paging attempts which couldn't sent out any paging request because no responsible bts found."}, - [MSC_CTR_PAGING_COMPLETED] = {"paging.completed", "Paging successful completed."}, - [MSC_CTR_PAGING_EXPIRED] = {"paging.expired", "Paging Request expired because of timeout T3113."}, [MSC_CTR_SMS_SUBMITTED] = {"sms.submitted", "Received a RPDU from a MS (MO)."}, [MSC_CTR_SMS_NO_RECEIVER] = {"sms.no_receiver", "Counts SMS which couldn't routed because no receiver found."}, [MSC_CTR_SMS_DELIVERED] = {"sms.delivered", "Global SMS Deliver attempts."}, @@ -212,10 +221,15 @@ [MSC_CTR_CALL_MO_CONNECT_ACK] = {"call.mo_connect_ack", "Received a connect ack from MS of a MO call. Call is now succesful connected up."}, [MSC_CTR_CALL_MT_SETUP] = {"call.mt_setup", "Sent setup requests to the MS (MT)."}, [MSC_CTR_CALL_MT_CONNECT] = {"call.mt_connect", "Sent a connect to the MS (MT)."}, - [MSC_CTR_CHAN_RF_FAIL] = {"chan.rf_fail", "Received a RF failure indication from BTS."}, - [MSC_CTR_CHAN_RLL_ERR] = {"chan.rll_err", "Received a RLL failure with T200 cause from BTS."}, - [MSC_CTR_BTS_OML_FAIL] = {"bts.oml_fail", "Received a TEI down on a OML link."}, - [MSC_CTR_BTS_RSL_FAIL] = {"bts.rsl_fail", "Received a TEI down on a OML link."}, +}; + + +static const struct rate_ctr_group_desc bsc_ctrg_desc = { + "bsc", + "base station controller", + OSMO_STATS_CLASS_GLOBAL, + ARRAY_SIZE(bsc_ctr_description), + bsc_ctr_description, }; static const struct rate_ctr_group_desc msc_ctrg_desc = { @@ -268,7 +282,8 @@ unsigned int max_distance; /* TA values */ } handover; - struct rate_ctr_group *ratectrs; + struct rate_ctr_group *bsc_ctrs; + struct rate_ctr_group *msc_ctrs; /* layer 4 */ diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index 9af986a..4c8448e 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -1229,7 +1229,7 @@ TLVP_LEN(&tp, RSL_IE_CAUSE)); LOGPC(DRSL, LOGL_NOTICE, "\n"); - rate_ctr_inc(&msg->lchan->ts->trx->bts->network->ratectrs->ctr[MSC_CTR_CHAN_RF_FAIL]); + rate_ctr_inc(&msg->lchan->ts->trx->bts->network->bsc_ctrs->ctr[BSC_CTR_CHAN_RF_FAIL]); return rsl_rf_chan_release_err(msg->lchan); } @@ -1663,7 +1663,7 @@ lctype = get_ctype_by_chreq(bts->network, rqd_ref->ra); chreq_reason = get_reason_by_chreq(rqd_ref->ra, bts->network->neci); - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_CHREQ_TOTAL]); + rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_CHREQ_TOTAL]); /* * We want LOCATION UPDATES to succeed and will assign a TCH @@ -1676,7 +1676,7 @@ if (!lchan) { LOGP(DRSL, LOGL_NOTICE, "BTS %d CHAN RQD: no resources for %s 0x%x\n", msg->lchan->ts->trx->bts->nr, gsm_lchant_name(lctype), rqd_ref->ra); - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_CHREQ_NO_CHANNEL]); + rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_CHREQ_NO_CHANNEL]); /* FIXME gather multiple CHAN RQD and reject up to 4 at the same time */ if (bts->network->T3122) rsl_send_imm_ass_rej(bts, 1, rqd_ref, bts->network->T3122 & 0xff); @@ -1859,7 +1859,7 @@ rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_ERR_IND); if (rlm_cause == RLL_CAUSE_T200_EXPIRED) { - rate_ctr_inc(&msg->lchan->ts->trx->bts->network->ratectrs->ctr[MSC_CTR_CHAN_RLL_ERR]); + rate_ctr_inc(&msg->lchan->ts->trx->bts->network->bsc_ctrs->ctr[BSC_CTR_CHAN_RLL_ERR]); return rsl_rf_chan_release_err(msg->lchan); } diff --git a/openbsc/src/libbsc/bsc_init.c b/openbsc/src/libbsc/bsc_init.c index 5ea85d0..989fca8 100644 --- a/openbsc/src/libbsc/bsc_init.c +++ b/openbsc/src/libbsc/bsc_init.c @@ -340,9 +340,9 @@ LOGP(DLMI, LOGL_ERROR, "Lost some E1 TEI link: %d %p\n", isd->link_type, trx); if (isd->link_type == E1INP_SIGN_OML) - rate_ctr_inc(&trx->bts->network->ratectrs->ctr[MSC_CTR_BTS_OML_FAIL]); + rate_ctr_inc(&trx->bts->network->bsc_ctrs->ctr[BSC_CTR_BTS_OML_FAIL]); else if (isd->link_type == E1INP_SIGN_RSL) - rate_ctr_inc(&trx->bts->network->ratectrs->ctr[MSC_CTR_BTS_RSL_FAIL]); + rate_ctr_inc(&trx->bts->network->bsc_ctrs->ctr[BSC_CTR_BTS_RSL_FAIL]); /* * free all allocated channels. change the nm_state so the diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c index fbaf06b..8116af1 100644 --- a/openbsc/src/libbsc/bsc_vty.c +++ b/openbsc/src/libbsc/bsc_vty.c @@ -3784,21 +3784,21 @@ void openbsc_vty_print_statistics(struct vty *vty, struct gsm_network *net) { vty_out(vty, "Channel Requests : %lu total, %lu no channel%s", - net->ratectrs->ctr[MSC_CTR_CHREQ_TOTAL].current, - net->ratectrs->ctr[MSC_CTR_CHREQ_NO_CHANNEL].current, + net->bsc_ctrs->ctr[BSC_CTR_CHREQ_TOTAL].current, + net->bsc_ctrs->ctr[BSC_CTR_CHREQ_NO_CHANNEL].current, VTY_NEWLINE); vty_out(vty, "Channel Failures : %lu rf_failures, %lu rll failures%s", - net->ratectrs->ctr[MSC_CTR_CHAN_RF_FAIL].current, - net->ratectrs->ctr[MSC_CTR_CHAN_RLL_ERR].current, + net->bsc_ctrs->ctr[BSC_CTR_CHAN_RF_FAIL].current, + net->bsc_ctrs->ctr[BSC_CTR_CHAN_RLL_ERR].current, VTY_NEWLINE); vty_out(vty, "Paging : %lu attempted, %lu complete, %lu expired%s", - net->ratectrs->ctr[MSC_CTR_PAGING_ATTEMPTED].current, - net->ratectrs->ctr[MSC_CTR_PAGING_COMPLETED].current, - net->ratectrs->ctr[MSC_CTR_PAGING_EXPIRED].current, + net->bsc_ctrs->ctr[BSC_CTR_PAGING_ATTEMPTED].current, + net->bsc_ctrs->ctr[BSC_CTR_PAGING_COMPLETED].current, + net->bsc_ctrs->ctr[BSC_CTR_PAGING_EXPIRED].current, VTY_NEWLINE); vty_out(vty, "BTS failures : %lu OML, %lu RSL%s", - net->ratectrs->ctr[MSC_CTR_BTS_OML_FAIL].current, - net->ratectrs->ctr[MSC_CTR_BTS_RSL_FAIL].current, + net->bsc_ctrs->ctr[BSC_CTR_BTS_OML_FAIL].current, + net->bsc_ctrs->ctr[BSC_CTR_BTS_RSL_FAIL].current, VTY_NEWLINE); } diff --git a/openbsc/src/libbsc/gsm_04_08_utils.c b/openbsc/src/libbsc/gsm_04_08_utils.c index d4eca4a..46df108 100644 --- a/openbsc/src/libbsc/gsm_04_08_utils.c +++ b/openbsc/src/libbsc/gsm_04_08_utils.c @@ -304,7 +304,7 @@ subscr = conn->subscr; } - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_PAGING_COMPLETED]); + rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_PAGING_COMPLETED]); /* Stop paging on the bts we received the paging response */ paging_request_stop(conn->bts, subscr, conn, msg); diff --git a/openbsc/src/libbsc/handover_logic.c b/openbsc/src/libbsc/handover_logic.c index 5424e27..ffcca66 100644 --- a/openbsc/src/libbsc/handover_logic.c +++ b/openbsc/src/libbsc/handover_logic.c @@ -103,7 +103,7 @@ DEBUGP(DHO, "(old_lchan on BTS %u, new BTS %u)\n", old_lchan->ts->trx->bts->nr, bts->nr); - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_HANDOVER_ATTEMPTED]); + rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_HANDOVER_ATTEMPTED]); if (!old_lchan->conn) { LOGP(DHO, LOGL_ERROR, "Old lchan lacks connection data.\n"); @@ -113,7 +113,7 @@ new_lchan = lchan_alloc(bts, old_lchan->type, 0); if (!new_lchan) { LOGP(DHO, LOGL_NOTICE, "No free channel\n"); - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_HANDOVER_NO_CHANNEL]); + rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_HANDOVER_NO_CHANNEL]); return -ENOSPC; } @@ -188,7 +188,7 @@ struct gsm_network *net = ho->new_lchan->ts->trx->bts->network; DEBUGP(DHO, "HO T3103 expired\n"); - rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_HANDOVER_TIMEOUT]); + rate_ctr_inc(&net->bsc_ctrs->ctr[BSC_CTR_HANDOVER_TIMEOUT]); ho->new_lchan->conn->ho_lchan = NULL; ho->new_lchan->conn = NULL; @@ -265,7 +265,7 @@ ho->old_lchan->ts->trx->bts->nr, new_lchan->ts->trx->bts->nr, ho->old_lchan->ts->trx->arfcn, new_lchan->ts->trx->arfcn); - rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_HANDOVER_COMPLETED]); + rate_ctr_inc(&net->bsc_ctrs->ctr[BSC_CTR_HANDOVER_COMPLETED]); osmo_timer_del(&ho->T3103); @@ -303,7 +303,7 @@ return -ENODEV; } - rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_HANDOVER_FAILED]); + rate_ctr_inc(&net->bsc_ctrs->ctr[BSC_CTR_HANDOVER_FAILED]); new_lchan = ho->new_lchan; diff --git a/openbsc/src/libbsc/net_init.c b/openbsc/src/libbsc/net_init.c index b99f3d2..37ba3c0 100644 --- a/openbsc/src/libbsc/net_init.c +++ b/openbsc/src/libbsc/net_init.c @@ -81,7 +81,8 @@ INIT_LLIST_HEAD(&net->bts_list); /* init statistics */ - net->ratectrs = rate_ctr_group_alloc(net, &msc_ctrg_desc, 0); + net->bsc_ctrs = rate_ctr_group_alloc(net, &bsc_ctrg_desc, 0); + net->bsc_ctrs = rate_ctr_group_alloc(net, &msc_ctrg_desc, 0); net->mncc_recv = mncc_recv; net->ext_min = GSM_MIN_EXTEN; diff --git a/openbsc/src/libbsc/paging.c b/openbsc/src/libbsc/paging.c index 03c91fd..fcb4deb 100644 --- a/openbsc/src/libbsc/paging.c +++ b/openbsc/src/libbsc/paging.c @@ -260,7 +260,7 @@ req, req->subscr->imsi); /* must be destroyed before calling cbfn, to prevent double free */ - rate_ctr_inc(&req->bts->network->ratectrs->ctr[MSC_CTR_PAGING_EXPIRED]); + rate_ctr_inc(&req->bts->network->bsc_ctrs->ctr[BSC_CTR_PAGING_EXPIRED]); cbfn_param = req->cbfn_param; cbfn = req->cbfn; @@ -330,7 +330,7 @@ struct gsm_bts *bts = NULL; int num_pages = 0; - rate_ctr_inc(&network->ratectrs->ctr[MSC_CTR_PAGING_ATTEMPTED]); + rate_ctr_inc(&network->bsc_ctrs->ctr[BSC_CTR_PAGING_ATTEMPTED]); /* start paging subscriber on all BTS within Location Area */ do { @@ -349,7 +349,7 @@ } while (1); if (num_pages == 0) - rate_ctr_inc(&network->ratectrs->ctr[MSC_CTR_PAGING_DETACHED]); + rate_ctr_inc(&network->bsc_ctrs->ctr[BSC_CTR_PAGING_DETACHED]); return num_pages; } diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c index c4ecf1c..c30fbb0 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/src/libmsc/gsm_04_08.c @@ -457,7 +457,7 @@ struct gsm_bts *bts = conn->bts; struct msgb *msg; - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_REJECT]); + rate_ctr_inc(&bts->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_RESP_REJECT]); msg = gsm48_create_loc_upd_rej(cause); if (!msg) { @@ -506,7 +506,7 @@ DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n"); - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_ACCEPT]); + rate_ctr_inc(&bts->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_RESP_ACCEPT]); return gsm48_conn_sendmsg(msg, conn, NULL); } @@ -637,13 +637,13 @@ switch (lu->type) { case GSM48_LUPD_NORMAL: - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_NORMAL]); + rate_ctr_inc(&bts->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_NORMAL]); break; case GSM48_LUPD_IMSI_ATT: - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_ATTACH]); + rate_ctr_inc(&bts->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_ATTACH]); break; case GSM48_LUPD_PERIODIC: - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_PERIODIC]); + rate_ctr_inc(&bts->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_PERIODIC]); break; } @@ -1063,7 +1063,7 @@ DEBUGP(DMM, "IMSI DETACH INDICATION: MI(%s)=%s", gsm48_mi_type_name(mi_type), mi_string); - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_DETACH]); + rate_ctr_inc(&bts->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_DETACH]); switch (mi_type) { case GSM_MI_TYPE_TMSI: @@ -2002,7 +2002,7 @@ subscr_name(trans->subscr), trans->subscr->extension, setup.called.number); - rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MO_SETUP]); + rate_ctr_inc(&trans->net->msc_ctrs->ctr[MSC_CTR_CALL_MO_SETUP]); /* indicate setup to MNCC */ mncc_recvmsg(trans->net, trans, MNCC_SETUP_IND, &setup); @@ -2080,7 +2080,7 @@ new_cc_state(trans, GSM_CSTATE_CALL_PRESENT); - rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MT_SETUP]); + rate_ctr_inc(&trans->net->msc_ctrs->ctr[MSC_CTR_CALL_MT_SETUP]); return gsm48_conn_sendmsg(msg, trans->conn, trans); } @@ -2306,7 +2306,7 @@ } new_cc_state(trans, GSM_CSTATE_CONNECT_REQUEST); - rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MT_CONNECT]); + rate_ctr_inc(&trans->net->msc_ctrs->ctr[MSC_CTR_CALL_MT_CONNECT]); return mncc_recvmsg(trans->net, trans, MNCC_SETUP_CNF, &connect); } @@ -2319,7 +2319,7 @@ gsm48_stop_cc_timer(trans); new_cc_state(trans, GSM_CSTATE_ACTIVE); - rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MO_CONNECT_ACK]); + rate_ctr_inc(&trans->net->msc_ctrs->ctr[MSC_CTR_CALL_MO_CONNECT_ACK]); memset(&connect_ack, 0, sizeof(struct gsm_mncc)); connect_ack.callref = trans->callref; diff --git a/openbsc/src/libmsc/gsm_04_11.c b/openbsc/src/libmsc/gsm_04_11.c index 840d4d4..6d3f41b 100644 --- a/openbsc/src/libmsc/gsm_04_11.c +++ b/openbsc/src/libmsc/gsm_04_11.c @@ -310,21 +310,21 @@ #ifdef BUILD_SMPP /* Avoid a second look-up */ if (smpp_first) { - rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); + rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); return 1; /* cause 1: unknown subscriber */ } rc = smpp_try_deliver(gsms, conn); if (rc == 1) { rc = 1; /* cause 1: unknown subscriber */ - rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); + rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); } else if (rc < 0) { rc = 21; /* cause 21: short message transfer rejected */ /* FIXME: handle the error somehow? */ } #else rc = 1; /* cause 1: unknown subscriber */ - rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); + rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); #endif return rc; } @@ -365,7 +365,7 @@ uint8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */ int rc = 0; - rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_SUBMITTED]); + rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_SUBMITTED]); gsms = sms_alloc(); if (!gsms) @@ -635,10 +635,10 @@ * to store this in our database and wait for a SMMA message */ /* FIXME */ send_signal(S_SMS_MEM_EXCEEDED, trans, sms, 0); - rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_MEM]); + rate_ctr_inc(&net->msc_ctrs->ctr[MSC_CTR_SMS_RP_ERR_MEM]); } else { send_signal(S_SMS_UNKNOWN_ERROR, trans, sms, 0); - rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_OTHER]); + rate_ctr_inc(&net->msc_ctrs->ctr[MSC_CTR_SMS_RP_ERR_OTHER]); } sms_free(sms); @@ -934,7 +934,7 @@ DEBUGP(DLSMS, "TX: SMS DELIVER\n"); - rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_DELIVERED]); + rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_DELIVERED]); db_sms_inc_deliver_attempts(trans->sms.sms); return gsm411_rp_sendmsg(&trans->sms.smr_inst, msg, diff --git a/openbsc/src/libmsc/vty_interface_layer3.c b/openbsc/src/libmsc/vty_interface_layer3.c index d1041b3..e7ff0a9 100644 --- a/openbsc/src/libmsc/vty_interface_layer3.c +++ b/openbsc/src/libmsc/vty_interface_layer3.c @@ -795,41 +795,41 @@ openbsc_vty_print_statistics(vty, net); vty_out(vty, "Location Update : %lu attach, %lu normal, %lu periodic%s", - net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_ATTACH].current, - net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_NORMAL].current, - net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_PERIODIC].current, + net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_ATTACH].current, + net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_NORMAL].current, + net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_PERIODIC].current, VTY_NEWLINE); vty_out(vty, "IMSI Detach Indications : %lu%s", - net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_DETACH].current, + net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_DETACH].current, VTY_NEWLINE); vty_out(vty, "Location Update Response: %lu accept, %lu reject%s", - net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_ACCEPT].current, - net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_REJECT].current, + net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_RESP_ACCEPT].current, + net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_RESP_REJECT].current, VTY_NEWLINE); vty_out(vty, "Handover : %lu attempted, %lu no_channel, %lu timeout, " "%lu completed, %lu failed%s", - net->ratectrs->ctr[MSC_CTR_HANDOVER_ATTEMPTED].current, - net->ratectrs->ctr[MSC_CTR_HANDOVER_NO_CHANNEL].current, - net->ratectrs->ctr[MSC_CTR_HANDOVER_TIMEOUT].current, - net->ratectrs->ctr[MSC_CTR_HANDOVER_COMPLETED].current, - net->ratectrs->ctr[MSC_CTR_HANDOVER_FAILED].current, + net->msc_ctrs->ctr[BSC_CTR_HANDOVER_ATTEMPTED].current, + net->msc_ctrs->ctr[BSC_CTR_HANDOVER_NO_CHANNEL].current, + net->msc_ctrs->ctr[BSC_CTR_HANDOVER_TIMEOUT].current, + net->msc_ctrs->ctr[BSC_CTR_HANDOVER_COMPLETED].current, + net->msc_ctrs->ctr[BSC_CTR_HANDOVER_FAILED].current, VTY_NEWLINE); vty_out(vty, "SMS MO : %lu submitted, %lu no receiver%s", - net->ratectrs->ctr[MSC_CTR_SMS_SUBMITTED].current, - net->ratectrs->ctr[MSC_CTR_SMS_NO_RECEIVER].current, + net->msc_ctrs->ctr[MSC_CTR_SMS_SUBMITTED].current, + net->msc_ctrs->ctr[MSC_CTR_SMS_NO_RECEIVER].current, VTY_NEWLINE); vty_out(vty, "SMS MT : %lu delivered, %lu no memory, %lu other error%s", - net->ratectrs->ctr[MSC_CTR_SMS_DELIVERED].current, - net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_MEM].current, - net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_OTHER].current, + net->msc_ctrs->ctr[MSC_CTR_SMS_DELIVERED].current, + net->msc_ctrs->ctr[MSC_CTR_SMS_RP_ERR_MEM].current, + net->msc_ctrs->ctr[MSC_CTR_SMS_RP_ERR_OTHER].current, VTY_NEWLINE); vty_out(vty, "MO Calls : %lu setup, %lu connect ack%s", - net->ratectrs->ctr[MSC_CTR_CALL_MO_SETUP].current, - net->ratectrs->ctr[MSC_CTR_CALL_MO_CONNECT_ACK].current, + net->msc_ctrs->ctr[MSC_CTR_CALL_MO_SETUP].current, + net->msc_ctrs->ctr[MSC_CTR_CALL_MO_CONNECT_ACK].current, VTY_NEWLINE); vty_out(vty, "MT Calls : %lu setup, %lu connect%s", - net->ratectrs->ctr[MSC_CTR_CALL_MT_SETUP].current, - net->ratectrs->ctr[MSC_CTR_CALL_MT_CONNECT].current, + net->msc_ctrs->ctr[MSC_CTR_CALL_MT_SETUP].current, + net->msc_ctrs->ctr[MSC_CTR_CALL_MT_CONNECT].current, VTY_NEWLINE); return CMD_SUCCESS; } -- To view, visit https://gerrit.osmocom.org/646 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I7361033cd1eb919ec3c2ea2652f40ab8c75b2f99 Gerrit-PatchSet: 5 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Mon Aug 29 17:05:30 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 17:05:30 +0000 Subject: [PATCH] openbsc[master]: sms: change rp err cause of smpp_try_deliver errors In-Reply-To: References: Message-ID: Hello Jenkins Builder, Holger Freyther, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/551 to look at the new patch set (#4). sms: change rp err cause of smpp_try_deliver errors smpp_try_deliver could fail with rc < 0. In such cases don't send the MS the rp error sms rejected (cause 21). A rejected message should not be sent again. The spec 04 11 recommends sending cause 41 Temporary failure in unknown cases. Add also a log message and rate counter for such cases. Tweaked-By: Neels Hofmeyr Change-Id: Ia03e50ce2bd9a7d1054cc5a6000fd73bd3497c03 --- M openbsc/include/openbsc/gsm_data.h M openbsc/src/libmsc/gsm_04_11.c 2 files changed, 15 insertions(+), 4 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/51/551/4 diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index daa5a4d..bfb7a60 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -198,6 +198,7 @@ MSC_CTR_SMS_DELIVERED, MSC_CTR_SMS_RP_ERR_MEM, MSC_CTR_SMS_RP_ERR_OTHER, + MSC_CTR_SMS_DELIVER_UNKNOWN_ERROR, MSC_CTR_CALL_MO_SETUP, MSC_CTR_CALL_MO_CONNECT_ACK, MSC_CTR_CALL_MT_SETUP, @@ -216,6 +217,7 @@ [MSC_CTR_SMS_DELIVERED] = {"sms.delivered", "Global SMS Deliver attempts."}, [MSC_CTR_SMS_RP_ERR_MEM] = {"sms.rp_err_mem", "CAUSE_MT_MEM_EXCEEDED errors of MS responses on a sms deliver attempt."}, [MSC_CTR_SMS_RP_ERR_OTHER] = {"sms.rp_err_other", "Other error of MS responses on a sms delive attempt."}, + [MSC_CTR_SMS_DELIVER_UNKNOWN_ERROR] = {"sms.deliver_unknown_error", "While trying to deliver an unknown error attempted."}, /* FIXME: count also sms delivered */ [MSC_CTR_CALL_MO_SETUP] = {"call.mo_setup", "Received setup requests from a MS to init a MO call."}, [MSC_CTR_CALL_MO_CONNECT_ACK] = {"call.mo_connect_ack", "Received a connect ack from MS of a MO call. Call is now succesful connected up."}, diff --git a/openbsc/src/libmsc/gsm_04_11.c b/openbsc/src/libmsc/gsm_04_11.c index 6d3f41b..d1fdfb9 100644 --- a/openbsc/src/libmsc/gsm_04_11.c +++ b/openbsc/src/libmsc/gsm_04_11.c @@ -40,6 +40,7 @@ #include #include +#include #include #include @@ -294,8 +295,12 @@ if (rc == 1) goto try_local; if (rc < 0) { - rc = 21; /* cause 21: short message transfer rejected */ - /* FIXME: handle the error somehow? */ + LOGP(DLSMS, LOGL_ERROR, "%s: SMS delivery error: %d.", + subscr_name(conn->subscr), rc); + rc = GSM411_RP_CAUSE_MO_TEMP_FAIL; + /* rc will be logged by gsm411_send_rp_error() */ + rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[ + MSC_CTR_SMS_DELIVER_UNKNOWN_ERROR]); } return rc; } @@ -319,8 +324,12 @@ rc = 1; /* cause 1: unknown subscriber */ rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); } else if (rc < 0) { - rc = 21; /* cause 21: short message transfer rejected */ - /* FIXME: handle the error somehow? */ + LOGP(DLSMS, LOGL_ERROR, "%s: SMS delivery error: %d.", + subscr_name(conn->subscr), rc); + rc = GSM411_RP_CAUSE_MO_TEMP_FAIL; + /* rc will be logged by gsm411_send_rp_error() */ + rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[ + MSC_CTR_SMS_DELIVER_UNKNOWN_ERROR]); } #else rc = 1; /* cause 1: unknown subscriber */ -- To view, visit https://gerrit.osmocom.org/551 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia03e50ce2bd9a7d1054cc5a6000fd73bd3497c03 Gerrit-PatchSet: 4 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: lynxis lazus From gerrit-no-reply at lists.osmocom.org Mon Aug 29 17:06:11 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 17:06:11 +0000 Subject: openbsc[master]: libmsc/bsc: split rate counters into bsc and msc group In-Reply-To: References: Message-ID: Patch Set 5: I changed the order of the commits, so that I can merge the split of counter groups without depending on the SMS error related commit. -- To view, visit https://gerrit.osmocom.org/646 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I7361033cd1eb919ec3c2ea2652f40ab8c75b2f99 Gerrit-PatchSet: 5 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 29 17:06:26 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 17:06:26 +0000 Subject: openbsc[master]: libmsc/bsc: split rate counters into bsc and msc group In-Reply-To: References: Message-ID: Patch Set 5: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/646 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I7361033cd1eb919ec3c2ea2652f40ab8c75b2f99 Gerrit-PatchSet: 5 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 29 17:20:00 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 17:20:00 +0000 Subject: openbsc[master]: IuPS: add VTY config for asn_debug In-Reply-To: References: Message-ID: Patch Set 1: > http://jenkins.osmocom.org/jenkins/job/OpenBSC-gerrit/813/ : > FAILURE due to timeout in testBSCreload in vty_test_runner.py. Build retriggered. -- To view, visit https://gerrit.osmocom.org/790 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: If4e7d0ab3fc2ed0cdf4fb0a3fa077a9e34890918 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 29 18:51:58 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Mon, 29 Aug 2016 18:51:58 +0000 Subject: openbsc[master]: IuPS: add VTY config for asn_debug In-Reply-To: References: Message-ID: Patch Set 1: Code-Review-1 (1 comment) https://gerrit.osmocom.org/#/c/790/1//COMMIT_MSG Commit Message: Line 13: logging asn1-debug (on|off) it would be the first time that we use on|off rather than either 0|1 or the usual 'no' construct. Let's try to not create more confiusion to the user. Also, I'm not sure if it should be a 'log' node, which is easily confused with the exisiting 'logging' node[s]... -- To view, visit https://gerrit.osmocom.org/790 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: If4e7d0ab3fc2ed0cdf4fb0a3fa077a9e34890918 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Mon Aug 29 19:28:49 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 19:28:49 +0000 Subject: openbsc[master]: IuPS: add VTY config for asn_debug In-Reply-To: References: Message-ID: Patch Set 1: re (0|1): ack It actually is a 'logging' item; each 'logging' command is a child of the 'log' node, apparently. -- To view, visit https://gerrit.osmocom.org/790 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: If4e7d0ab3fc2ed0cdf4fb0a3fa077a9e34890918 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 29 19:35:27 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 19:35:27 +0000 Subject: openbsc[master]: IuPS: add VTY config for asn_debug In-Reply-To: References: Message-ID: Patch Set 1: I guess 'logging asn-debug' and 'no logging asn-debug' is a bit odd. So going for the 'logging asn-debug (0|1)'. -- To view, visit https://gerrit.osmocom.org/790 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: If4e7d0ab3fc2ed0cdf4fb0a3fa077a9e34890918 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 29 19:39:59 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 19:39:59 +0000 Subject: openbsc[master]: IuPS: add VTY config for asn_debug In-Reply-To: References: Message-ID: Patch Set 1: hmm, but what about config 'write', I'm not printing the 'logging asn-debug' nor would it be beautiful code to do so... -- To view, visit https://gerrit.osmocom.org/790 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: If4e7d0ab3fc2ed0cdf4fb0a3fa077a9e34890918 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Mon Aug 29 19:42:09 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Mon, 29 Aug 2016 19:42:09 +0000 Subject: [PATCH] openbsc[master]: IuPS: add VTY config for asn_debug In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/790 to look at the new patch set (#2). IuPS: add VTY config for asn_debug Add file iu_vty.c in libiu, and iu_vty_init() to initialize the new VTY command: log logging asn1-debug (on|off) Change-Id: If4e7d0ab3fc2ed0cdf4fb0a3fa077a9e34890918 --- M openbsc/include/openbsc/iu.h M openbsc/src/libiu/Makefile.am A openbsc/src/libiu/iu_vty.c 3 files changed, 53 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/90/790/2 diff --git a/openbsc/include/openbsc/iu.h b/openbsc/include/openbsc/iu.h index d0ab540..f973ac1 100644 --- a/openbsc/include/openbsc/iu.h +++ b/openbsc/include/openbsc/iu.h @@ -58,3 +58,5 @@ int iu_rab_deact(struct ue_conn_ctx *ue_ctx, uint8_t rab_id); int iu_tx_sec_mode_cmd(struct ue_conn_ctx *uectx, struct gsm_auth_tuple *tp, int send_ck, int new_key); + +void iu_vty_init(int *asn_debug_p); diff --git a/openbsc/src/libiu/Makefile.am b/openbsc/src/libiu/Makefile.am index 7b1ba4d..1968d3e 100644 --- a/openbsc/src/libiu/Makefile.am +++ b/openbsc/src/libiu/Makefile.am @@ -6,5 +6,5 @@ noinst_LIBRARIES = libiu.a -libiu_a_SOURCES = iu.c +libiu_a_SOURCES = iu.c iu_vty.c diff --git a/openbsc/src/libiu/iu_vty.c b/openbsc/src/libiu/iu_vty.c new file mode 100644 index 0000000..91eed96 --- /dev/null +++ b/openbsc/src/libiu/iu_vty.c @@ -0,0 +1,50 @@ +/* OpenBSC Iu related interface to quagga VTY */ +/* (C) 2016 by sysmocom s.m.f.c. GmbH + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include + +#include +#include + +/* Pointer to the actual asn_debug value as passed from main scopes. */ +static int *g_asn_debug_p = NULL; + +DEFUN(logging_asn_debug, + logging_asn_debug_cmd, + "logging asn1-debug (1|0)", + LOGGING_STR + "Log human readable representations of all ASN.1 messages to stderr\n" + "Log decoded ASN.1 messages to stderr\n" + "Do not log decoded ASN.1 messages to stderr\n") +{ + if (!g_asn_debug_p) { + vty_out(vty, "%%ASN.1 debugging not available%s", VTY_NEWLINE); + return CMD_WARNING; + } + + *g_asn_debug_p = atoi(argv[0]); + return CMD_SUCCESS; +} + +void iu_vty_init(int *asn_debug_p) +{ + g_asn_debug_p = asn_debug_p; + + install_element(CFG_LOG_NODE, &logging_asn_debug_cmd); +} -- To view, visit https://gerrit.osmocom.org/790 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: If4e7d0ab3fc2ed0cdf4fb0a3fa077a9e34890918 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Tue Aug 30 07:34:36 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Tue, 30 Aug 2016 07:34:36 +0000 Subject: osmo-bts[master]: dyn TS: measurement: use correct nr of subslots, rm code dup In-Reply-To: References: Message-ID: Patch Set 3: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/675 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I9d9df470c49487bffd56dde42c7bec0da2f50642 Gerrit-PatchSet: 3 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 30 07:35:49 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Tue, 30 Aug 2016 07:35:49 +0000 Subject: [MERGED] osmo-bts[master]: dyn TS: measurement: use correct nr of subslots, rm code dup In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: dyn TS: measurement: use correct nr of subslots, rm code dup ...................................................................... dyn TS: measurement: use correct nr of subslots, rm code dup In measurement.c, fix the number of sublots for TCH/F_TCH/H_PDCH, by using ts_subslots() from gsm_data_shared.c. The local dup of subslots_per_pchan[] is no longer needed. (depends on recent commit to openbsc.git for ts_sublots()) Change-Id: I9d9df470c49487bffd56dde42c7bec0da2f50642 --- M src/common/measurement.c 1 file changed, 1 insertion(+), 15 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/src/common/measurement.c b/src/common/measurement.c index d0b84d5..be1d4f6 100644 --- a/src/common/measurement.c +++ b/src/common/measurement.c @@ -200,24 +200,10 @@ return 1; } -/* Copied from OpenBSC and enlarged to _GSM_PCHAN_MAX */ -static const uint8_t subslots_per_pchan[_GSM_PCHAN_MAX] = { - [GSM_PCHAN_NONE] = 0, - [GSM_PCHAN_CCCH] = 0, - [GSM_PCHAN_CCCH_SDCCH4] = 4, - [GSM_PCHAN_CCCH_SDCCH4_CBCH] = 4, - [GSM_PCHAN_TCH_F] = 1, - [GSM_PCHAN_TCH_H] = 2, - [GSM_PCHAN_SDCCH8_SACCH8C] = 8, - [GSM_PCHAN_SDCCH8_SACCH8C_CBCH] = 8, - [GSM_PCHAN_TCH_F_PDCH] = 1, - /* dynamic pchan are handled outside of this array */ -}; - static int ts_meas_check_compute(struct gsm_bts_trx_ts *ts, uint32_t fn) { int i; - const int num_subslots = subslots_per_pchan[ts->pchan]; + const int num_subslots = ts_subslots(ts); for (i = 0; i < num_subslots; ++i) { struct gsm_lchan *lchan = &ts->lchan[i]; -- To view, visit https://gerrit.osmocom.org/675 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I9d9df470c49487bffd56dde42c7bec0da2f50642 Gerrit-PatchSet: 4 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Tue Aug 30 07:35:50 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Tue, 30 Aug 2016 07:35:50 +0000 Subject: [MERGED] osmo-bts[master]: dyn TS: sysmo, lc15: ph_data_req: fix PDCH mode detection In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: dyn TS: sysmo,lc15: ph_data_req: fix PDCH mode detection ...................................................................... dyn TS: sysmo,lc15: ph_data_req: fix PDCH mode detection Though this patch theoretically makes a lot of sense, it is not entirely clear why dyn TS are working without it. Committing due to common sense, not to fix any actual breakage. Change-Id: I6136cb42a4d627ebefc963eb5321fadfe63cca4b --- M src/osmo-bts-litecell15/l1_if.c M src/osmo-bts-sysmo/l1_if.c 2 files changed, 2 insertions(+), 2 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/src/osmo-bts-litecell15/l1_if.c b/src/osmo-bts-litecell15/l1_if.c index dcd25ee..3672b8f 100644 --- a/src/osmo-bts-litecell15/l1_if.c +++ b/src/osmo-bts-litecell15/l1_if.c @@ -363,7 +363,7 @@ if (!L1SAP_IS_CHAN_TCHF(chan_nr)) subCh = l1sap_chan2ss(chan_nr); } else if (L1SAP_IS_CHAN_TCHF(chan_nr)) { - if (trx->ts[u8Tn].pchan == GSM_PCHAN_PDCH) { + if (ts_is_pdch(&trx->ts[u8Tn])) { if (L1SAP_IS_PTCCH(u32Fn)) { sapi = GsmL1_Sapi_Ptcch; u8BlockNbr = L1SAP_FN2PTCCHBLOCK(u32Fn); diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index fcd3a3e..0880ee9 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -358,7 +358,7 @@ if (!L1SAP_IS_CHAN_TCHF(chan_nr)) subCh = l1sap_chan2ss(chan_nr); } else if (L1SAP_IS_CHAN_TCHF(chan_nr)) { - if (trx->ts[u8Tn].pchan == GSM_PCHAN_PDCH) { + if (ts_is_pdch(&trx->ts[u8Tn])) { if (L1SAP_IS_PTCCH(u32Fn)) { sapi = GsmL1_Sapi_Ptcch; u8BlockNbr = L1SAP_FN2PTCCHBLOCK(u32Fn); -- To view, visit https://gerrit.osmocom.org/677 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I6136cb42a4d627ebefc963eb5321fadfe63cca4b Gerrit-PatchSet: 4 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Tue Aug 30 07:35:50 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Tue, 30 Aug 2016 07:35:50 +0000 Subject: [MERGED] osmo-bts[master]: cosmetic: common ts_is_pdch() In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: cosmetic: common ts_is_pdch() ...................................................................... cosmetic: common ts_is_pdch() Have one common ts_is_pdch(), placed in lchan.c, since this file is pretty empty and pretty close to ts. Publish in gsm_data.h. Remove the if-style implementation from l1sap.c, and instead implement in a switch statement. This prepares for upcoming ts_is_pdch() usage in ph_data_req() for sysmo and lc15. Change-Id: Ib78d663fdbac5a1d7053f1b9d543649b66da00e2 --- M include/osmo-bts/gsm_data.h M src/common/l1sap.c M src/common/lchan.c 3 files changed, 17 insertions(+), 11 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/include/osmo-bts/gsm_data.h b/include/osmo-bts/gsm_data.h index c75f828..f1c9601 100644 --- a/include/osmo-bts/gsm_data.h +++ b/include/osmo-bts/gsm_data.h @@ -135,5 +135,6 @@ int bts_supports_cipher(struct gsm_bts_role_bts *bts, int rsl_cipher); +bool ts_is_pdch(const struct gsm_bts_trx_ts *ts); #endif /* _GSM_DATA_H */ diff --git a/src/common/l1sap.c b/src/common/l1sap.c index f7df218..7c30c9b 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -294,17 +294,6 @@ return 0; } -static bool ts_is_pdch(const struct gsm_bts_trx_ts *ts) -{ - return ts->pchan == GSM_PCHAN_PDCH - || (ts->pchan == GSM_PCHAN_TCH_F_PDCH - && (ts->flags & TS_F_PDCH_ACTIVE) - && !(ts->flags & TS_F_PDCH_PENDING_MASK)) - || (ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH - && ts->dyn.pchan_want == ts->dyn.pchan_is - && ts->dyn.pchan_is == GSM_PCHAN_PDCH); -} - static int to_gsmtap(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) { uint8_t *data; diff --git a/src/common/lchan.c b/src/common/lchan.c index fbc2636..9e98166 100644 --- a/src/common/lchan.c +++ b/src/common/lchan.c @@ -31,3 +31,19 @@ gsm_lchans_name(state)); lchan->state = state; } + +bool ts_is_pdch(const struct gsm_bts_trx_ts *ts) +{ + switch (ts->pchan) { + case GSM_PCHAN_PDCH: + return true; + case GSM_PCHAN_TCH_F_PDCH: + return (ts->flags & TS_F_PDCH_ACTIVE) + && !(ts->flags & TS_F_PDCH_PENDING_MASK); + case GSM_PCHAN_TCH_F_TCH_H_PDCH: + return ts->dyn.pchan_is == GSM_PCHAN_PDCH + && ts->dyn.pchan_want == ts->dyn.pchan_is; + default: + return false; + } +} -- To view, visit https://gerrit.osmocom.org/676 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ib78d663fdbac5a1d7053f1b9d543649b66da00e2 Gerrit-PatchSet: 4 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Tue Aug 30 07:38:31 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Tue, 30 Aug 2016 07:38:31 +0000 Subject: osmo-bts[master]: heed VTY 'line vty'/'bind' command In-Reply-To: References: Message-ID: Patch Set 1: > (1 comment) Why not put the LOGP in the existing telnet_init_dynif() ? -- To view, visit https://gerrit.osmocom.org/754 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ic4ab32aee08d8a779adeb9943892de0c828c7b3d Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 30 07:38:49 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Tue, 30 Aug 2016 07:38:49 +0000 Subject: openbsc[master]: sms: change rp err cause of smpp_try_deliver errors In-Reply-To: References: Message-ID: Patch Set 4: Code-Review+1 -- To view, visit https://gerrit.osmocom.org/551 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia03e50ce2bd9a7d1054cc5a6000fd73bd3497c03 Gerrit-PatchSet: 4 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: lynxis lazus Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 30 07:38:59 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 30 Aug 2016 07:38:59 +0000 Subject: [PATCH] osmo-pcu[master]: GPRS: PUAN encoding: add test case to show wrong BSNs status In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/770 to look at the new patch set (#2). GPRS: PUAN encoding: add test case to show wrong BSNs status This patch adds a test case which expects a current bug with GPRS PUAN encoding. The test's expectation is corrected along with the bug fix in a subsequent commit Related: OS#1806 Change-Id: Ied0f1dd3037d8fac6a772f4e097defb72634f955 --- M tests/types/TypesTest.cpp 1 file changed, 18 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/70/770/2 diff --git a/tests/types/TypesTest.cpp b/tests/types/TypesTest.cpp index c56b125..c5654f6 100644 --- a/tests/types/TypesTest.cpp +++ b/tests/types/TypesTest.cpp @@ -322,6 +322,24 @@ ul_win.receive_bsn(4); count = ul_win.raise_v_q(); OSMO_ASSERT(count == 0); + + /* + * SSN wrap around case + * TODO: Should not expect any BSN as nacked. + * should be fixed in subsequent patch + */ + rbb = "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIRR"; + for (int i = 0; i < 128; ++i) { + ul_win.receive_bsn(i); + ul_win.raise_v_q(); + } + ul_win.receive_bsn(0); + ul_win.raise_v_q(); + ul_win.receive_bsn(1); + ul_win.raise_v_q(); + ul_win.update_rbb(win_rbb); + OSMO_ASSERT_STR_EQ(win_rbb, rbb); + OSMO_ASSERT(ul_win.ssn() == 2); } { -- To view, visit https://gerrit.osmocom.org/770 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ied0f1dd3037d8fac6a772f4e097defb72634f955 Gerrit-PatchSet: 2 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Tue Aug 30 07:38:59 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 30 Aug 2016 07:38:59 +0000 Subject: [PATCH] osmo-pcu[master]: Fix GPRS PUAN encoding: wrong BSN status In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/771 to look at the new patch set (#2). Fix GPRS PUAN encoding: wrong BSN status Earlier there was an incorrect encoding of BSN status in GPRS PUAN message. This was a bottle neck for GPRS performance testing for UL. Which has been fixed in this patch. Related: OS#1806 Change-Id: I98e586aa5cb9200cf03e092556304211d4d459aa --- M src/rlc.cpp M tests/types/TypesTest.cpp 2 files changed, 3 insertions(+), 4 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/71/771/2 diff --git a/src/rlc.cpp b/src/rlc.cpp index e69d1fc..ee2635a 100644 --- a/src/rlc.cpp +++ b/src/rlc.cpp @@ -227,7 +227,7 @@ { int i; for (i=0; i < ws(); i++) { - if (m_v_n.is_received(ssn()-1-i)) + if (m_v_n.is_received((ssn()-1-i) & mod_sns())) rbb[ws()-1-i] = 'R'; else rbb[ws()-1-i] = 'I'; diff --git a/tests/types/TypesTest.cpp b/tests/types/TypesTest.cpp index c5654f6..8b3cfd1 100644 --- a/tests/types/TypesTest.cpp +++ b/tests/types/TypesTest.cpp @@ -325,10 +325,9 @@ /* * SSN wrap around case - * TODO: Should not expect any BSN as nacked. - * should be fixed in subsequent patch + * Should not expect any BSN as nacked. */ - rbb = "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIRR"; + rbb = "RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"; for (int i = 0; i < 128; ++i) { ul_win.receive_bsn(i); ul_win.raise_v_q(); -- To view, visit https://gerrit.osmocom.org/771 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I98e586aa5cb9200cf03e092556304211d4d459aa Gerrit-PatchSet: 2 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Tue Aug 30 07:44:30 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 30 Aug 2016 07:44:30 +0000 Subject: osmo-pcu[master]: GPRS: PUAN encoding: add test case to show wrong BSNs status In-Reply-To: References: Message-ID: Patch Set 2: Hi Holger, I have modified the patch as per your suggestion. please have a look. Thanks, Aravind Sirsikar -- To view, visit https://gerrit.osmocom.org/770 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ied0f1dd3037d8fac6a772f4e097defb72634f955 Gerrit-PatchSet: 2 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 30 07:55:28 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 30 Aug 2016 07:55:28 +0000 Subject: [PATCH] osmo-pcu[master]: Fix EGPRS EPDAN decoding: no ack nack dissector length In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/766 to look at the new patch set (#6). Fix EGPRS EPDAN decoding: no ack nack dissector length Earlier there was an incorrect decoding of URBB fields when EPDAN is received withot ack/Nack dissector length.This was a bottle neck for performance testing. Which has been fixed in this patch. Related: OS#1805 unit test assertion in the previous commit is fixed in this patch. Change-Id: Ieddf96aca82b0b0e917cfcc70aeb978799fb4e95 --- M src/csn1.cpp M tests/rlcmac/RLCMACTest.cpp 2 files changed, 3 insertions(+), 6 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/66/766/6 diff --git a/src/csn1.cpp b/src/csn1.cpp index d51fe83..da5fe3b 100644 --- a/src/csn1.cpp +++ b/src/csn1.cpp @@ -1111,6 +1111,7 @@ { /* extract bits */ guint8* pui8 = pui8DATA(data, pDescr->offset); gint16 nB1 = no_of_bits & 0x07;/* no_of_bits Mod 8 */ + no_of_bits -= nB1; while (no_of_bits > 0) { diff --git a/tests/rlcmac/RLCMACTest.cpp b/tests/rlcmac/RLCMACTest.cpp index 4f74ea4..091fc5a 100644 --- a/tests/rlcmac/RLCMACTest.cpp +++ b/tests/rlcmac/RLCMACTest.cpp @@ -223,12 +223,8 @@ EGPRS_AckNack_Desc_t *urbb = &data.u.Egprs_Packet_Downlink_Ack_Nack.EGPRS_AckNack.Desc; - /* - * TODO: URBB len is decoded as 102. so there is total 12 bytes and - * 6 bits in the 13th byte. in 13th byte we expect value - * as 0x00. But we see some incorrect value - */ - OSMO_ASSERT(strcmp(osmo_hexdump(urbb->URBB, 13), + + OSMO_ASSERT(!strcmp(osmo_hexdump(urbb->URBB, 13), "7f ff ff ee 00 00 00 00 00 00 00 00 00 " )); } -- To view, visit https://gerrit.osmocom.org/766 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ieddf96aca82b0b0e917cfcc70aeb978799fb4e95 Gerrit-PatchSet: 6 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Tue Aug 30 07:59:59 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 30 Aug 2016 07:59:59 +0000 Subject: osmo-pcu[master]: EGPRS: EPDAN decoding: add test case to show no ack_nack len... In-Reply-To: References: Message-ID: Patch Set 6: Hi Neeels, I have incorporated the comments you have raised. Please have a look. Thanks, Aravind Sirsikar -- To view, visit https://gerrit.osmocom.org/765 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I8da84794748f2e81722c3eca69b46ccc3a21552e Gerrit-PatchSet: 6 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 30 09:41:41 2016 From: gerrit-no-reply at lists.osmocom.org (lynxis lazus) Date: Tue, 30 Aug 2016 09:41:41 +0000 Subject: [PATCH] openbsc[master]: bsc: count the usage of codec by setting the lchan active Message-ID: Review at https://gerrit.osmocom.org/794 bsc: count the usage of codec by setting the lchan active we count the codec when the channel was successful setted up Change-Id: Ifc8a406a11dce16b9e7f3310841e470545550a2c --- M openbsc/include/openbsc/gsm_data.h M openbsc/src/libbsc/abis_rsl.c 2 files changed, 23 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/94/794/1 diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index bfb7a60..2f09af1 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -166,6 +166,9 @@ BSC_CTR_CHAN_RLL_ERR, BSC_CTR_BTS_OML_FAIL, BSC_CTR_BTS_RSL_FAIL, + BSC_CTR_CODEC_AMR, + BSC_CTR_CODEC_EFR, + BSC_CTR_CODEC_V1, }; static const struct rate_ctr_desc bsc_ctr_description[] = { @@ -184,6 +187,9 @@ [BSC_CTR_CHAN_RLL_ERR] = {"chan.rll_err", "Received a RLL failure with T200 cause from BTS."}, [BSC_CTR_BTS_OML_FAIL] = {"bts.oml_fail", "Received a TEI down on a OML link."}, [BSC_CTR_BTS_RSL_FAIL] = {"bts.rsl_fail", "Received a TEI down on a OML link."}, + [BSC_CTR_CODEC_AMR] = {"bts.codec_amr", "Count the usage of amr codec by channel mode requested."}, + [BSC_CTR_CODEC_EFR] = {"bts.codec_efr", "Count the usage of efr codec by channel mode requested."}, + [BSC_CTR_CODEC_V1] = {"bts.codec_hfr", "Count the usage of hr or fr codec by channel mode requested."}, }; enum { diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index 4c8448e..71a15aa 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -82,6 +82,21 @@ lchan_free(lchan); } +static void count_codecs(struct gsm_bts *bts, int chan_mode) +{ + switch (chan_mode) { + case GSM48_CMODE_SPEECH_AMR: + rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_CODEC_AMR]); + break; + case GSM48_CMODE_SPEECH_EFR: + rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_CODEC_EFR]); + break; + case GSM48_CMODE_SPEECH_V1: + rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_CODEC_V1]); + break; + } +} + static uint8_t mdisc_by_msgtype(uint8_t msg_type) { /* mask off the transparent bit ? */ @@ -1164,6 +1179,7 @@ lchan->rqd_ta = 0; } + count_codecs(msg->trx->bts, lchan->tch_mode); send_lchan_signal(S_LCHAN_ACTIVATE_ACK, lchan, NULL); return 0; @@ -1472,6 +1488,7 @@ rc = rsl_rx_rf_chan_rel_ack(msg->lchan); break; case RSL_MT_MODE_MODIFY_ACK: + count_codecs(msg->trx->bts, msg->lchan->tch_mode); DEBUGP(DRSL, "%s CHANNEL MODE MODIFY ACK\n", ts_name); break; case RSL_MT_MODE_MODIFY_NACK: -- To view, visit https://gerrit.osmocom.org/794 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ifc8a406a11dce16b9e7f3310841e470545550a2c Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus From gerrit-no-reply at lists.osmocom.org Tue Aug 30 09:41:42 2016 From: gerrit-no-reply at lists.osmocom.org (lynxis lazus) Date: Tue, 30 Aug 2016 09:41:42 +0000 Subject: [PATCH] openbsc[master]: msc: add counters to track call attempts/active/success/failed Message-ID: Review at https://gerrit.osmocom.org/795 msc: add counters to track call attempts/active/success/failed active_calls describe all calls in active state. call.complete Call got terminated by disconnect requested either by MS or MSC. call.incomplete Call got terminated by any other reason. call.active Calls reached active state. Change-Id: I49b93af2e6a0ba16c2fb00b7b83974e8a6a16df3 --- M openbsc/include/openbsc/gsm_data.h M openbsc/src/libbsc/net_init.c M openbsc/src/libmsc/gsm_04_08.c 3 files changed, 42 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/95/795/1 diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 2f09af1..7879ea6 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -209,6 +209,9 @@ MSC_CTR_CALL_MO_CONNECT_ACK, MSC_CTR_CALL_MT_SETUP, MSC_CTR_CALL_MT_CONNECT, + MSC_CTR_CALL_ACTIVE, + MSC_CTR_CALL_COMPLETE, + MSC_CTR_CALL_INCOMPLETE, }; static const struct rate_ctr_desc msc_ctr_description[] = { @@ -229,6 +232,9 @@ [MSC_CTR_CALL_MO_CONNECT_ACK] = {"call.mo_connect_ack", "Received a connect ack from MS of a MO call. Call is now succesful connected up."}, [MSC_CTR_CALL_MT_SETUP] = {"call.mt_setup", "Sent setup requests to the MS (MT)."}, [MSC_CTR_CALL_MT_CONNECT] = {"call.mt_connect", "Sent a connect to the MS (MT)."}, + [MSC_CTR_CALL_ACTIVE] = {"call.active", "Count amount of calls reached state active."}, + [MSC_CTR_CALL_COMPLETE] = {"call.complete", "Count amount of calls which got terminated by disconnect req or ind after reaching active state."}, + [MSC_CTR_CALL_INCOMPLETE] = {"call.incomplete", "Call got terminated by any other reason."}, }; @@ -292,7 +298,7 @@ struct rate_ctr_group *bsc_ctrs; struct rate_ctr_group *msc_ctrs; - + struct osmo_counter *active_calls; /* layer 4 */ struct mncc_sock_state *mncc_state; diff --git a/openbsc/src/libbsc/net_init.c b/openbsc/src/libbsc/net_init.c index 37ba3c0..59a3e2c 100644 --- a/openbsc/src/libbsc/net_init.c +++ b/openbsc/src/libbsc/net_init.c @@ -83,6 +83,7 @@ /* init statistics */ net->bsc_ctrs = rate_ctr_group_alloc(net, &bsc_ctrg_desc, 0); net->bsc_ctrs = rate_ctr_group_alloc(net, &msc_ctrg_desc, 0); + net->active_calls = osmo_counter_alloc("msc.active_calls"); net->mncc_recv = mncc_recv; net->ext_min = GSM_MIN_EXTEN; diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c index c30fbb0..a1d9cf3 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/src/libmsc/gsm_04_08.c @@ -1306,6 +1306,39 @@ return gsm48_conn_sendmsg(msg, conn, NULL); } +/* FIXME: this count_statistics is a state machine behaviour. we should convert + * the complete call control into a state machine. Afterwards we can move this + * code into state transitions. + */ +static void count_statistics(struct gsm_trans *trans, int new_state) +{ + int old_state = trans->cc.state; + struct rate_ctr_group *msc = trans->net->msc_ctrs; + + if (old_state == new_state) + return; + + /* state incoming */ + switch (new_state) { + case GSM_CSTATE_ACTIVE: + osmo_counter_inc(trans->net->active_calls); + rate_ctr_inc(&msc->ctr[MSC_CTR_CALL_ACTIVE]); + break; + } + + /* state outgoing */ + switch (old_state) { + case GSM_CSTATE_ACTIVE: + osmo_counter_dec(trans->net->active_calls); + if (new_state == GSM_CSTATE_DISCONNECT_REQ || + new_state == GSM_CSTATE_DISCONNECT_IND) + rate_ctr_inc(&msc->ctr[MSC_CTR_CALL_COMPLETE]); + else + rate_ctr_inc(&msc->ctr[MSC_CTR_CALL_INCOMPLETE]); + break; + } +} + /* Call Control */ /* The entire call control code is written in accordance with Figure 7.10c @@ -1322,6 +1355,7 @@ gsm48_cc_state_name(trans->cc.state), gsm48_cc_state_name(state)); + count_statistics(trans, state); trans->cc.state = state; } -- To view, visit https://gerrit.osmocom.org/795 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I49b93af2e6a0ba16c2fb00b7b83974e8a6a16df3 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus From gerrit-no-reply at lists.osmocom.org Tue Aug 30 10:03:12 2016 From: gerrit-no-reply at lists.osmocom.org (lynxis lazus) Date: Tue, 30 Aug 2016 10:03:12 +0000 Subject: [PATCH] libosmocore[master]: core/counter: add osmo_counter_dec() Message-ID: Review at https://gerrit.osmocom.org/796 core/counter: add osmo_counter_dec() Change-Id: I030140a45afa295c3ebc4d3ccaffd437b984f515 --- M include/osmocom/core/statistics.h 1 file changed, 6 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/96/796/1 diff --git a/include/osmocom/core/statistics.h b/include/osmocom/core/statistics.h index 1e472ff..41716cc 100644 --- a/include/osmocom/core/statistics.h +++ b/include/osmocom/core/statistics.h @@ -12,6 +12,12 @@ unsigned long previous; /*!< \brief previous value */ }; +/*! \brief Decrement counter */ +static inline void osmo_counter_dec(struct osmo_counter *ctr) +{ + ctr->value--; +} + /*! \brief Increment counter */ static inline void osmo_counter_inc(struct osmo_counter *ctr) { -- To view, visit https://gerrit.osmocom.org/796 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I030140a45afa295c3ebc4d3ccaffd437b984f515 Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: lynxis lazus From gerrit-no-reply at lists.osmocom.org Tue Aug 30 10:05:08 2016 From: gerrit-no-reply at lists.osmocom.org (lynxis lazus) Date: Tue, 30 Aug 2016 10:05:08 +0000 Subject: openbsc[master]: msc: add counters to track call attempts/active/success/failed In-Reply-To: References: Message-ID: Patch Set 1: it's missing https://gerrit.osmocom.org/#/c/796/ in libosmocore -- To view, visit https://gerrit.osmocom.org/795 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I49b93af2e6a0ba16c2fb00b7b83974e8a6a16df3 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: lynxis lazus Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 30 10:05:50 2016 From: gerrit-no-reply at lists.osmocom.org (lynxis lazus) Date: Tue, 30 Aug 2016 10:05:50 +0000 Subject: openbsc[master]: fix mistypes, spaces and tabs In-Reply-To: References: Message-ID: Patch Set 1: Code-Review-1 please merge first the other patches in line of msc_stats which conflicting with this patch -- To view, visit https://gerrit.osmocom.org/792 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I651473f638365bbd333c4c80d223cdd023dd2c51 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: lynxis lazus Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 30 10:13:43 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 30 Aug 2016 10:13:43 +0000 Subject: libosmocore[master]: core/counter: add osmo_counter_dec() In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+1 I'm not sure whether it is a concious design decision to omit the dec(), but can't think of any reason why, especially when the counter struct isn't opaque and we could set any value we want anyway. -- To view, visit https://gerrit.osmocom.org/796 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I030140a45afa295c3ebc4d3ccaffd437b984f515 Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 30 10:15:23 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 30 Aug 2016 10:15:23 +0000 Subject: [PATCH] osmo-pcu[master]: DL: add test case to show wrong window size Message-ID: Review at https://gerrit.osmocom.org/797 DL: add test case to show wrong window size This patch adds a test case test_tbf_update_ws. Which expects a current bug with DL window size calculation. The test's expectation is corrected along with the bug fix in a subsequent commit Related: OS#1808 Change-Id: I4659494c6f93ae89e4cc4ac79fff5fcaf2d23699 --- M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err M tests/tbf/TbfTest.ok 3 files changed, 111 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/97/797/1 diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index a4de6c9..ca5a3c8 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -1774,6 +1774,65 @@ gprs_bssgp_destroy(); } +static void test_tbf_update_ws(void) +{ + BTS the_bts; + gprs_rlcmac_bts *bts; + uint8_t ts_no = 4; + uint8_t ms_class = 11; + gprs_rlcmac_dl_tbf *dl_tbf; + + printf("=== start %s ===\n", __func__); + + bts = the_bts.bts_data(); + setup_bts(&the_bts, ts_no); + + bts->ws_base = 128; + bts->ws_pdch = 64; + bts->alloc_algorithm = alloc_algorithm_b; + bts->trx[0].pdch[2].enable(); + bts->trx[0].pdch[3].enable(); + bts->trx[0].pdch[4].enable(); + bts->trx[0].pdch[5].enable(); + + gprs_bssgp_create_and_connect(bts, 33001, 0, 33001, + 1234, 1234, 1234, 1, 1, 0, 0, 0); + + /* EGPRS-only */ + bts->egprs_enabled = 1; + + /* Does support EGPRS */ + dl_tbf = tbf_alloc_dl_tbf(bts, NULL, 0, ms_class, ms_class, 1); + + OSMO_ASSERT(dl_tbf != NULL); + fprintf(stderr, "DL TBF slots: 0x%02x, N: %d, WS: %d\n", + dl_tbf->dl_slots(), + pcu_bitcount(dl_tbf->dl_slots()), + dl_tbf->window()->ws()); + OSMO_ASSERT(pcu_bitcount(dl_tbf->dl_slots()) == 1); + OSMO_ASSERT(dl_tbf->window()->ws() == 128 + 1 * 64); + + dl_tbf->update(); + + /* + * TODO: Should not expect window size as 192. + * should be fixed in subsequent patch + */ + OSMO_ASSERT(dl_tbf != NULL); + fprintf(stderr, "DL TBF slots: 0x%02x, N: %d, WS: %d\n", + dl_tbf->dl_slots(), + pcu_bitcount(dl_tbf->dl_slots()), + dl_tbf->window()->ws()); + OSMO_ASSERT(pcu_bitcount(dl_tbf->dl_slots()) == 4); + OSMO_ASSERT(dl_tbf->window()->ws() == 128 + 1 * 64); + + tbf_free(dl_tbf); + + printf("=== end %s ===\n", __func__); + + gprs_bssgp_destroy(); +} + static void test_tbf_puan_urbb_len(void) { BTS the_bts; @@ -2485,6 +2544,7 @@ test_tbf_egprs_retx_dl(); test_tbf_egprs_spb_dl(); test_tbf_puan_urbb_len(); + test_tbf_update_ws(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 452f1c1..67aade9 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -6335,3 +6335,52 @@ TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=NULL EGPRS) changes state from NULL to ASSIGN TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) starting timer 0. TBF(TFI=0 TLLI=0xf1223344 DIR=DL STATE=ASSIGN EGPRS) append +********** TBF starts here ********** +Allocating DL TBF: MS_CLASS=11/11 +Creating MS object, TLLI = 0x00000000 +Modifying MS object, TLLI = 0x00000000, MS class 0 -> 11 +Modifying MS object, TLLI = 0x00000000, EGPRS MS class 0 -> 11 +Enabled EGPRS for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), mode EGPRS +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +Slot Allocation (Algorithm B) for class 11 +- Rx=4 Tx=3 Sum Rx+Tx=5 Tta=3 Ttb=1 Tra=2 Trb=1 Type=1 +- Skipping TS 0, because not enabled +- Skipping TS 1, because not enabled +- Skipping TS 6, because not enabled +- Skipping TS 7, because not enabled +- Possible DL/UL slots: (TS=0)"..CCCC.."(TS=7) +- Selected DL slots: (TS=0)"..ddDd.."(TS=7), single +Using single slot at TS 4 for DL +- Reserved DL/UL slots: (TS=0)"....C..."(TS=7) +- Assigning DL TS 4 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Setting Control TS 4 +Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) +Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): trx = 0, ul_slots = 10, dl_slots = 10 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting EGPRS window size to 192 +DL TBF slots: 0x10, N: 1, WS: 192 +********** TBF update ********** +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Searching for first unallocated TFI: TRX=0 + Found TFI=0. +- Selected DL slots: (TS=0)"..DDDD.."(TS=7) +Using 4 slots for DL +- Assigning DL TS 2 +PDCH(TS 2, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Assigning DL TS 3 +PDCH(TS 3, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Assigning DL TS 4 +PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +- Assigning DL TS 5 +PDCH(TS 5, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. +DL TBF slots: 0x3c, N: 4, WS: 192 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to RELEASING +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=RELEASING EGPRS) free +PDCH(TS 2, TRX 0): Detaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +PDCH(TS 3, TRX 0): Detaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +PDCH(TS 5, TRX 0): Detaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. +Detaching TBF from MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=RELEASING EGPRS) +Destroying MS object, TLLI = 0x00000000 +********** TBF ends here ********** diff --git a/tests/tbf/TbfTest.ok b/tests/tbf/TbfTest.ok index dda72ef..13ad362 100644 --- a/tests/tbf/TbfTest.ok +++ b/tests/tbf/TbfTest.ok @@ -62,3 +62,5 @@ === end test_tbf_egprs_spb_dl === === start test_tbf_puan_urbb_len === === end test_tbf_puan_urbb_len === +=== start test_tbf_update_ws === +=== end test_tbf_update_ws === -- To view, visit https://gerrit.osmocom.org/797 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I4659494c6f93ae89e4cc4ac79fff5fcaf2d23699 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Tue Aug 30 10:15:23 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 30 Aug 2016 10:15:23 +0000 Subject: [PATCH] osmo-pcu[master]: Fix DL window calculation during tbf update Message-ID: Review at https://gerrit.osmocom.org/798 Fix DL window calculation during tbf update Earlier there was no handling for recalculation of DL window size during tbf update. Which has been fixed in this patch. Related: OS#1808 Change-Id: I41aa807068520460fd665a55e3529e60f6bbb630 --- M src/tbf.cpp M tests/tbf/TbfTest.cpp M tests/tbf/TbfTest.err 3 files changed, 22 insertions(+), 6 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/98/798/1 diff --git a/src/tbf.cpp b/src/tbf.cpp index 1fc1aef..871708e 100644 --- a/src/tbf.cpp +++ b/src/tbf.cpp @@ -375,6 +375,23 @@ return -rc; } + unsigned int num_pdch = pcu_bitcount(dl_slots()); + unsigned int ws = bts->bts_data()->ws_base + + num_pdch * bts->bts_data()->ws_pdch; + ws = (ws / 32) * 32; + ws = OSMO_MAX(64, ws); + + if (num_pdch == 1) + ws = OSMO_MIN(192, ws); + else + ws = OSMO_MIN(128 * num_pdch, ws); + LOGP(DRLCMAC, LOGL_INFO, "%s: Setting DL window size to %d\n" + "num_pdch(%d) ws_base(%d) ws_pdch(%d)\n", + name(), ws, num_pdch, bts->bts_data()->ws_base, + bts->bts_data()->ws_pdch); + + window()->set_ws(ws); + return 0; } diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index ca5a3c8..e74c676 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -1814,17 +1814,14 @@ dl_tbf->update(); - /* - * TODO: Should not expect window size as 192. - * should be fixed in subsequent patch - */ + /* window size should be 384 */ OSMO_ASSERT(dl_tbf != NULL); fprintf(stderr, "DL TBF slots: 0x%02x, N: %d, WS: %d\n", dl_tbf->dl_slots(), pcu_bitcount(dl_tbf->dl_slots()), dl_tbf->window()->ws()); OSMO_ASSERT(pcu_bitcount(dl_tbf->dl_slots()) == 4); - OSMO_ASSERT(dl_tbf->window()->ws() == 128 + 1 * 64); + OSMO_ASSERT(dl_tbf->window()->ws() == 128 + 4 * 64); tbf_free(dl_tbf); diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err index 67aade9..1e40906 100644 --- a/tests/tbf/TbfTest.err +++ b/tests/tbf/TbfTest.err @@ -6374,7 +6374,9 @@ PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. - Assigning DL TS 5 PDCH(TS 5, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS), 1 TBFs, USFs = 00, TFIs = 00000001. -DL TBF slots: 0x3c, N: 4, WS: 192 +TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS): Setting DL window size to 384 +num_pdch(4) ws_base(128) ws_pdch(64) +DL TBF slots: 0x3c, N: 4, WS: 384 TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL EGPRS) changes state from NULL to RELEASING TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=RELEASING EGPRS) free PDCH(TS 2, TRX 0): Detaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000. -- To view, visit https://gerrit.osmocom.org/798 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I41aa807068520460fd665a55e3529e60f6bbb630 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Tue Aug 30 10:20:57 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 30 Aug 2016 10:20:57 +0000 Subject: osmo-bts[master]: heed VTY 'line vty'/'bind' command In-Reply-To: References: Message-ID: Patch Set 1: I wouldn't log "VTY" in the more general telnet init function, but I'd like to say "VTY" in the log message. For example, the SGSN also logs its CTRL interface port like this: <000f> sgsn_main.c:364 VTY at 127.0.0.1 4245 <000f> sgsn_main.c:373 CTRL at 127.0.0.1 4251 Ok, we could say "telnet at 127.0.0.1 4245" ... -- To view, visit https://gerrit.osmocom.org/754 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ic4ab32aee08d8a779adeb9943892de0c828c7b3d Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 30 10:56:25 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 30 Aug 2016 10:56:25 +0000 Subject: [MERGED] openbsc[master]: libmsc/bsc: split rate counters into bsc and msc group In-Reply-To: References: Message-ID: Neels Hofmeyr has submitted this change and it was merged. Change subject: libmsc/bsc: split rate counters into bsc and msc group ...................................................................... libmsc/bsc: split rate counters into bsc and msc group Tweaked-By: Neels Hofmeyr Change-Id: I7361033cd1eb919ec3c2ea2652f40ab8c75b2f99 --- M openbsc/include/openbsc/gsm_data.h M openbsc/src/libbsc/abis_rsl.c M openbsc/src/libbsc/bsc_init.c M openbsc/src/libbsc/bsc_vty.c M openbsc/src/libbsc/gsm_04_08_utils.c M openbsc/src/libbsc/handover_logic.c M openbsc/src/libbsc/net_init.c M openbsc/src/libbsc/paging.c M openbsc/src/libmsc/gsm_04_08.c M openbsc/src/libmsc/gsm_04_11.c M openbsc/src/libmsc/vty_interface_layer3.c 11 files changed, 110 insertions(+), 94 deletions(-) Approvals: Neels Hofmeyr: Looks good to me, approved Jenkins Builder: Verified diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 6168a6b..daa5a4d 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -150,25 +150,49 @@ #include "gsm_data_shared.h" -/* Some statistics of our network */ enum { - MSC_CTR_CHREQ_TOTAL, - MSC_CTR_CHREQ_NO_CHANNEL, - MSC_CTR_HANDOVER_ATTEMPTED, - MSC_CTR_HANDOVER_NO_CHANNEL, - MSC_CTR_HANDOVER_TIMEOUT, - MSC_CTR_HANDOVER_COMPLETED, - MSC_CTR_HANDOVER_FAILED, + BSC_CTR_CHREQ_TOTAL, + BSC_CTR_CHREQ_NO_CHANNEL, + BSC_CTR_HANDOVER_ATTEMPTED, + BSC_CTR_HANDOVER_NO_CHANNEL, + BSC_CTR_HANDOVER_TIMEOUT, + BSC_CTR_HANDOVER_COMPLETED, + BSC_CTR_HANDOVER_FAILED, + BSC_CTR_PAGING_ATTEMPTED, + BSC_CTR_PAGING_DETACHED, + BSC_CTR_PAGING_COMPLETED, + BSC_CTR_PAGING_EXPIRED, + BSC_CTR_CHAN_RF_FAIL, + BSC_CTR_CHAN_RLL_ERR, + BSC_CTR_BTS_OML_FAIL, + BSC_CTR_BTS_RSL_FAIL, +}; + +static const struct rate_ctr_desc bsc_ctr_description[] = { + [BSC_CTR_CHREQ_TOTAL] = {"chreq.total", "Received channel requests."}, + [BSC_CTR_CHREQ_NO_CHANNEL] = {"chreq.no_channel", "Sent to MS no channel available."}, + [BSC_CTR_HANDOVER_ATTEMPTED] = {"handover.attempted", "Received handover attempts."}, + [BSC_CTR_HANDOVER_NO_CHANNEL] = {"handover.no_channel", "Sent no channel available responses."}, + [BSC_CTR_HANDOVER_TIMEOUT] = {"handover.timeout", "Count the amount of timeouts of timer T3103."}, + [BSC_CTR_HANDOVER_COMPLETED] = {"handover.completed", "Received handover completed."}, + [BSC_CTR_HANDOVER_FAILED] = {"handover.failed", "Receive HO FAIL messages."}, + [BSC_CTR_PAGING_ATTEMPTED] = {"paging.attempted", "Paging attempts for a MS."}, + [BSC_CTR_PAGING_DETACHED] = {"paging.detached", "Counts the amount of paging attempts which couldn't sent out any paging request because no responsible bts found."}, + [BSC_CTR_PAGING_COMPLETED] = {"paging.completed", "Paging successful completed."}, + [BSC_CTR_PAGING_EXPIRED] = {"paging.expired", "Paging Request expired because of timeout T3113."}, + [BSC_CTR_CHAN_RF_FAIL] = {"chan.rf_fail", "Received a RF failure indication from BTS."}, + [BSC_CTR_CHAN_RLL_ERR] = {"chan.rll_err", "Received a RLL failure with T200 cause from BTS."}, + [BSC_CTR_BTS_OML_FAIL] = {"bts.oml_fail", "Received a TEI down on a OML link."}, + [BSC_CTR_BTS_RSL_FAIL] = {"bts.rsl_fail", "Received a TEI down on a OML link."}, +}; + +enum { MSC_CTR_LOC_UPDATE_TYPE_ATTACH, MSC_CTR_LOC_UPDATE_TYPE_NORMAL, MSC_CTR_LOC_UPDATE_TYPE_PERIODIC, MSC_CTR_LOC_UPDATE_TYPE_DETACH, MSC_CTR_LOC_UPDATE_RESP_REJECT, MSC_CTR_LOC_UPDATE_RESP_ACCEPT, - MSC_CTR_PAGING_ATTEMPTED, - MSC_CTR_PAGING_DETACHED, - MSC_CTR_PAGING_COMPLETED, - MSC_CTR_PAGING_EXPIRED, MSC_CTR_SMS_SUBMITTED, MSC_CTR_SMS_NO_RECEIVER, MSC_CTR_SMS_DELIVERED, @@ -178,30 +202,15 @@ MSC_CTR_CALL_MO_CONNECT_ACK, MSC_CTR_CALL_MT_SETUP, MSC_CTR_CALL_MT_CONNECT, - MSC_CTR_CHAN_RF_FAIL, - MSC_CTR_CHAN_RLL_ERR, - MSC_CTR_BTS_OML_FAIL, - MSC_CTR_BTS_RSL_FAIL, }; static const struct rate_ctr_desc msc_ctr_description[] = { - [MSC_CTR_CHREQ_TOTAL] = {"chreq.total", "Received channel requests."}, - [MSC_CTR_CHREQ_NO_CHANNEL] = {"chreq.no_channel", "Sent to MS no channel available."}, - [MSC_CTR_HANDOVER_ATTEMPTED] = {"handover.attempted", "Received handover attempts."}, - [MSC_CTR_HANDOVER_NO_CHANNEL] = {"handover.no_channel", "Sent no channel available responses."}, - [MSC_CTR_HANDOVER_TIMEOUT] = {"handover.timeout", "Count the amount of timeouts of timer T3103."}, - [MSC_CTR_HANDOVER_COMPLETED] = {"handover.completed", "Received handover completed."}, - [MSC_CTR_HANDOVER_FAILED] = {"handover.failed", "Receive HO FAIL messages."}, [MSC_CTR_LOC_UPDATE_TYPE_ATTACH] = {"loc_update_type.attach", "Received location update imsi attach requests."}, [MSC_CTR_LOC_UPDATE_TYPE_NORMAL] = {"loc_update_type.normal", "Received location update normal requests."}, [MSC_CTR_LOC_UPDATE_TYPE_PERIODIC] = {"loc_update_type.periodic", "Received location update periodic requests."}, [MSC_CTR_LOC_UPDATE_TYPE_DETACH] = {"loc_update_type.detach", "Received location update detach indication."}, [MSC_CTR_LOC_UPDATE_RESP_REJECT] = {"loc_update_resp.reject", "Sent location update reject responses."}, [MSC_CTR_LOC_UPDATE_RESP_ACCEPT] = {"loc_update_resp.accept", "Sent location update accept responses."}, - [MSC_CTR_PAGING_ATTEMPTED] = {"paging.attempted", "Paging attempts for a MS."}, - [MSC_CTR_PAGING_DETACHED] = {"paging.detached", "Counts the amount of paging attempts which couldn't sent out any paging request because no responsible bts found."}, - [MSC_CTR_PAGING_COMPLETED] = {"paging.completed", "Paging successful completed."}, - [MSC_CTR_PAGING_EXPIRED] = {"paging.expired", "Paging Request expired because of timeout T3113."}, [MSC_CTR_SMS_SUBMITTED] = {"sms.submitted", "Received a RPDU from a MS (MO)."}, [MSC_CTR_SMS_NO_RECEIVER] = {"sms.no_receiver", "Counts SMS which couldn't routed because no receiver found."}, [MSC_CTR_SMS_DELIVERED] = {"sms.delivered", "Global SMS Deliver attempts."}, @@ -212,10 +221,15 @@ [MSC_CTR_CALL_MO_CONNECT_ACK] = {"call.mo_connect_ack", "Received a connect ack from MS of a MO call. Call is now succesful connected up."}, [MSC_CTR_CALL_MT_SETUP] = {"call.mt_setup", "Sent setup requests to the MS (MT)."}, [MSC_CTR_CALL_MT_CONNECT] = {"call.mt_connect", "Sent a connect to the MS (MT)."}, - [MSC_CTR_CHAN_RF_FAIL] = {"chan.rf_fail", "Received a RF failure indication from BTS."}, - [MSC_CTR_CHAN_RLL_ERR] = {"chan.rll_err", "Received a RLL failure with T200 cause from BTS."}, - [MSC_CTR_BTS_OML_FAIL] = {"bts.oml_fail", "Received a TEI down on a OML link."}, - [MSC_CTR_BTS_RSL_FAIL] = {"bts.rsl_fail", "Received a TEI down on a OML link."}, +}; + + +static const struct rate_ctr_group_desc bsc_ctrg_desc = { + "bsc", + "base station controller", + OSMO_STATS_CLASS_GLOBAL, + ARRAY_SIZE(bsc_ctr_description), + bsc_ctr_description, }; static const struct rate_ctr_group_desc msc_ctrg_desc = { @@ -268,7 +282,8 @@ unsigned int max_distance; /* TA values */ } handover; - struct rate_ctr_group *ratectrs; + struct rate_ctr_group *bsc_ctrs; + struct rate_ctr_group *msc_ctrs; /* layer 4 */ diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index 9af986a..4c8448e 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -1229,7 +1229,7 @@ TLVP_LEN(&tp, RSL_IE_CAUSE)); LOGPC(DRSL, LOGL_NOTICE, "\n"); - rate_ctr_inc(&msg->lchan->ts->trx->bts->network->ratectrs->ctr[MSC_CTR_CHAN_RF_FAIL]); + rate_ctr_inc(&msg->lchan->ts->trx->bts->network->bsc_ctrs->ctr[BSC_CTR_CHAN_RF_FAIL]); return rsl_rf_chan_release_err(msg->lchan); } @@ -1663,7 +1663,7 @@ lctype = get_ctype_by_chreq(bts->network, rqd_ref->ra); chreq_reason = get_reason_by_chreq(rqd_ref->ra, bts->network->neci); - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_CHREQ_TOTAL]); + rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_CHREQ_TOTAL]); /* * We want LOCATION UPDATES to succeed and will assign a TCH @@ -1676,7 +1676,7 @@ if (!lchan) { LOGP(DRSL, LOGL_NOTICE, "BTS %d CHAN RQD: no resources for %s 0x%x\n", msg->lchan->ts->trx->bts->nr, gsm_lchant_name(lctype), rqd_ref->ra); - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_CHREQ_NO_CHANNEL]); + rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_CHREQ_NO_CHANNEL]); /* FIXME gather multiple CHAN RQD and reject up to 4 at the same time */ if (bts->network->T3122) rsl_send_imm_ass_rej(bts, 1, rqd_ref, bts->network->T3122 & 0xff); @@ -1859,7 +1859,7 @@ rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_ERR_IND); if (rlm_cause == RLL_CAUSE_T200_EXPIRED) { - rate_ctr_inc(&msg->lchan->ts->trx->bts->network->ratectrs->ctr[MSC_CTR_CHAN_RLL_ERR]); + rate_ctr_inc(&msg->lchan->ts->trx->bts->network->bsc_ctrs->ctr[BSC_CTR_CHAN_RLL_ERR]); return rsl_rf_chan_release_err(msg->lchan); } diff --git a/openbsc/src/libbsc/bsc_init.c b/openbsc/src/libbsc/bsc_init.c index 5ea85d0..989fca8 100644 --- a/openbsc/src/libbsc/bsc_init.c +++ b/openbsc/src/libbsc/bsc_init.c @@ -340,9 +340,9 @@ LOGP(DLMI, LOGL_ERROR, "Lost some E1 TEI link: %d %p\n", isd->link_type, trx); if (isd->link_type == E1INP_SIGN_OML) - rate_ctr_inc(&trx->bts->network->ratectrs->ctr[MSC_CTR_BTS_OML_FAIL]); + rate_ctr_inc(&trx->bts->network->bsc_ctrs->ctr[BSC_CTR_BTS_OML_FAIL]); else if (isd->link_type == E1INP_SIGN_RSL) - rate_ctr_inc(&trx->bts->network->ratectrs->ctr[MSC_CTR_BTS_RSL_FAIL]); + rate_ctr_inc(&trx->bts->network->bsc_ctrs->ctr[BSC_CTR_BTS_RSL_FAIL]); /* * free all allocated channels. change the nm_state so the diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c index fbaf06b..8116af1 100644 --- a/openbsc/src/libbsc/bsc_vty.c +++ b/openbsc/src/libbsc/bsc_vty.c @@ -3784,21 +3784,21 @@ void openbsc_vty_print_statistics(struct vty *vty, struct gsm_network *net) { vty_out(vty, "Channel Requests : %lu total, %lu no channel%s", - net->ratectrs->ctr[MSC_CTR_CHREQ_TOTAL].current, - net->ratectrs->ctr[MSC_CTR_CHREQ_NO_CHANNEL].current, + net->bsc_ctrs->ctr[BSC_CTR_CHREQ_TOTAL].current, + net->bsc_ctrs->ctr[BSC_CTR_CHREQ_NO_CHANNEL].current, VTY_NEWLINE); vty_out(vty, "Channel Failures : %lu rf_failures, %lu rll failures%s", - net->ratectrs->ctr[MSC_CTR_CHAN_RF_FAIL].current, - net->ratectrs->ctr[MSC_CTR_CHAN_RLL_ERR].current, + net->bsc_ctrs->ctr[BSC_CTR_CHAN_RF_FAIL].current, + net->bsc_ctrs->ctr[BSC_CTR_CHAN_RLL_ERR].current, VTY_NEWLINE); vty_out(vty, "Paging : %lu attempted, %lu complete, %lu expired%s", - net->ratectrs->ctr[MSC_CTR_PAGING_ATTEMPTED].current, - net->ratectrs->ctr[MSC_CTR_PAGING_COMPLETED].current, - net->ratectrs->ctr[MSC_CTR_PAGING_EXPIRED].current, + net->bsc_ctrs->ctr[BSC_CTR_PAGING_ATTEMPTED].current, + net->bsc_ctrs->ctr[BSC_CTR_PAGING_COMPLETED].current, + net->bsc_ctrs->ctr[BSC_CTR_PAGING_EXPIRED].current, VTY_NEWLINE); vty_out(vty, "BTS failures : %lu OML, %lu RSL%s", - net->ratectrs->ctr[MSC_CTR_BTS_OML_FAIL].current, - net->ratectrs->ctr[MSC_CTR_BTS_RSL_FAIL].current, + net->bsc_ctrs->ctr[BSC_CTR_BTS_OML_FAIL].current, + net->bsc_ctrs->ctr[BSC_CTR_BTS_RSL_FAIL].current, VTY_NEWLINE); } diff --git a/openbsc/src/libbsc/gsm_04_08_utils.c b/openbsc/src/libbsc/gsm_04_08_utils.c index d4eca4a..46df108 100644 --- a/openbsc/src/libbsc/gsm_04_08_utils.c +++ b/openbsc/src/libbsc/gsm_04_08_utils.c @@ -304,7 +304,7 @@ subscr = conn->subscr; } - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_PAGING_COMPLETED]); + rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_PAGING_COMPLETED]); /* Stop paging on the bts we received the paging response */ paging_request_stop(conn->bts, subscr, conn, msg); diff --git a/openbsc/src/libbsc/handover_logic.c b/openbsc/src/libbsc/handover_logic.c index 5424e27..ffcca66 100644 --- a/openbsc/src/libbsc/handover_logic.c +++ b/openbsc/src/libbsc/handover_logic.c @@ -103,7 +103,7 @@ DEBUGP(DHO, "(old_lchan on BTS %u, new BTS %u)\n", old_lchan->ts->trx->bts->nr, bts->nr); - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_HANDOVER_ATTEMPTED]); + rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_HANDOVER_ATTEMPTED]); if (!old_lchan->conn) { LOGP(DHO, LOGL_ERROR, "Old lchan lacks connection data.\n"); @@ -113,7 +113,7 @@ new_lchan = lchan_alloc(bts, old_lchan->type, 0); if (!new_lchan) { LOGP(DHO, LOGL_NOTICE, "No free channel\n"); - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_HANDOVER_NO_CHANNEL]); + rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_HANDOVER_NO_CHANNEL]); return -ENOSPC; } @@ -188,7 +188,7 @@ struct gsm_network *net = ho->new_lchan->ts->trx->bts->network; DEBUGP(DHO, "HO T3103 expired\n"); - rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_HANDOVER_TIMEOUT]); + rate_ctr_inc(&net->bsc_ctrs->ctr[BSC_CTR_HANDOVER_TIMEOUT]); ho->new_lchan->conn->ho_lchan = NULL; ho->new_lchan->conn = NULL; @@ -265,7 +265,7 @@ ho->old_lchan->ts->trx->bts->nr, new_lchan->ts->trx->bts->nr, ho->old_lchan->ts->trx->arfcn, new_lchan->ts->trx->arfcn); - rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_HANDOVER_COMPLETED]); + rate_ctr_inc(&net->bsc_ctrs->ctr[BSC_CTR_HANDOVER_COMPLETED]); osmo_timer_del(&ho->T3103); @@ -303,7 +303,7 @@ return -ENODEV; } - rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_HANDOVER_FAILED]); + rate_ctr_inc(&net->bsc_ctrs->ctr[BSC_CTR_HANDOVER_FAILED]); new_lchan = ho->new_lchan; diff --git a/openbsc/src/libbsc/net_init.c b/openbsc/src/libbsc/net_init.c index b99f3d2..37ba3c0 100644 --- a/openbsc/src/libbsc/net_init.c +++ b/openbsc/src/libbsc/net_init.c @@ -81,7 +81,8 @@ INIT_LLIST_HEAD(&net->bts_list); /* init statistics */ - net->ratectrs = rate_ctr_group_alloc(net, &msc_ctrg_desc, 0); + net->bsc_ctrs = rate_ctr_group_alloc(net, &bsc_ctrg_desc, 0); + net->bsc_ctrs = rate_ctr_group_alloc(net, &msc_ctrg_desc, 0); net->mncc_recv = mncc_recv; net->ext_min = GSM_MIN_EXTEN; diff --git a/openbsc/src/libbsc/paging.c b/openbsc/src/libbsc/paging.c index 03c91fd..fcb4deb 100644 --- a/openbsc/src/libbsc/paging.c +++ b/openbsc/src/libbsc/paging.c @@ -260,7 +260,7 @@ req, req->subscr->imsi); /* must be destroyed before calling cbfn, to prevent double free */ - rate_ctr_inc(&req->bts->network->ratectrs->ctr[MSC_CTR_PAGING_EXPIRED]); + rate_ctr_inc(&req->bts->network->bsc_ctrs->ctr[BSC_CTR_PAGING_EXPIRED]); cbfn_param = req->cbfn_param; cbfn = req->cbfn; @@ -330,7 +330,7 @@ struct gsm_bts *bts = NULL; int num_pages = 0; - rate_ctr_inc(&network->ratectrs->ctr[MSC_CTR_PAGING_ATTEMPTED]); + rate_ctr_inc(&network->bsc_ctrs->ctr[BSC_CTR_PAGING_ATTEMPTED]); /* start paging subscriber on all BTS within Location Area */ do { @@ -349,7 +349,7 @@ } while (1); if (num_pages == 0) - rate_ctr_inc(&network->ratectrs->ctr[MSC_CTR_PAGING_DETACHED]); + rate_ctr_inc(&network->bsc_ctrs->ctr[BSC_CTR_PAGING_DETACHED]); return num_pages; } diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c index c4ecf1c..c30fbb0 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/src/libmsc/gsm_04_08.c @@ -457,7 +457,7 @@ struct gsm_bts *bts = conn->bts; struct msgb *msg; - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_REJECT]); + rate_ctr_inc(&bts->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_RESP_REJECT]); msg = gsm48_create_loc_upd_rej(cause); if (!msg) { @@ -506,7 +506,7 @@ DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n"); - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_ACCEPT]); + rate_ctr_inc(&bts->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_RESP_ACCEPT]); return gsm48_conn_sendmsg(msg, conn, NULL); } @@ -637,13 +637,13 @@ switch (lu->type) { case GSM48_LUPD_NORMAL: - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_NORMAL]); + rate_ctr_inc(&bts->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_NORMAL]); break; case GSM48_LUPD_IMSI_ATT: - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_ATTACH]); + rate_ctr_inc(&bts->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_ATTACH]); break; case GSM48_LUPD_PERIODIC: - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_PERIODIC]); + rate_ctr_inc(&bts->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_PERIODIC]); break; } @@ -1063,7 +1063,7 @@ DEBUGP(DMM, "IMSI DETACH INDICATION: MI(%s)=%s", gsm48_mi_type_name(mi_type), mi_string); - rate_ctr_inc(&bts->network->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_DETACH]); + rate_ctr_inc(&bts->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_DETACH]); switch (mi_type) { case GSM_MI_TYPE_TMSI: @@ -2002,7 +2002,7 @@ subscr_name(trans->subscr), trans->subscr->extension, setup.called.number); - rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MO_SETUP]); + rate_ctr_inc(&trans->net->msc_ctrs->ctr[MSC_CTR_CALL_MO_SETUP]); /* indicate setup to MNCC */ mncc_recvmsg(trans->net, trans, MNCC_SETUP_IND, &setup); @@ -2080,7 +2080,7 @@ new_cc_state(trans, GSM_CSTATE_CALL_PRESENT); - rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MT_SETUP]); + rate_ctr_inc(&trans->net->msc_ctrs->ctr[MSC_CTR_CALL_MT_SETUP]); return gsm48_conn_sendmsg(msg, trans->conn, trans); } @@ -2306,7 +2306,7 @@ } new_cc_state(trans, GSM_CSTATE_CONNECT_REQUEST); - rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MT_CONNECT]); + rate_ctr_inc(&trans->net->msc_ctrs->ctr[MSC_CTR_CALL_MT_CONNECT]); return mncc_recvmsg(trans->net, trans, MNCC_SETUP_CNF, &connect); } @@ -2319,7 +2319,7 @@ gsm48_stop_cc_timer(trans); new_cc_state(trans, GSM_CSTATE_ACTIVE); - rate_ctr_inc(&trans->net->ratectrs->ctr[MSC_CTR_CALL_MO_CONNECT_ACK]); + rate_ctr_inc(&trans->net->msc_ctrs->ctr[MSC_CTR_CALL_MO_CONNECT_ACK]); memset(&connect_ack, 0, sizeof(struct gsm_mncc)); connect_ack.callref = trans->callref; diff --git a/openbsc/src/libmsc/gsm_04_11.c b/openbsc/src/libmsc/gsm_04_11.c index 840d4d4..6d3f41b 100644 --- a/openbsc/src/libmsc/gsm_04_11.c +++ b/openbsc/src/libmsc/gsm_04_11.c @@ -310,21 +310,21 @@ #ifdef BUILD_SMPP /* Avoid a second look-up */ if (smpp_first) { - rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); + rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); return 1; /* cause 1: unknown subscriber */ } rc = smpp_try_deliver(gsms, conn); if (rc == 1) { rc = 1; /* cause 1: unknown subscriber */ - rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); + rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); } else if (rc < 0) { rc = 21; /* cause 21: short message transfer rejected */ /* FIXME: handle the error somehow? */ } #else rc = 1; /* cause 1: unknown subscriber */ - rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); + rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); #endif return rc; } @@ -365,7 +365,7 @@ uint8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */ int rc = 0; - rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_SUBMITTED]); + rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_SUBMITTED]); gsms = sms_alloc(); if (!gsms) @@ -635,10 +635,10 @@ * to store this in our database and wait for a SMMA message */ /* FIXME */ send_signal(S_SMS_MEM_EXCEEDED, trans, sms, 0); - rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_MEM]); + rate_ctr_inc(&net->msc_ctrs->ctr[MSC_CTR_SMS_RP_ERR_MEM]); } else { send_signal(S_SMS_UNKNOWN_ERROR, trans, sms, 0); - rate_ctr_inc(&net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_OTHER]); + rate_ctr_inc(&net->msc_ctrs->ctr[MSC_CTR_SMS_RP_ERR_OTHER]); } sms_free(sms); @@ -934,7 +934,7 @@ DEBUGP(DLSMS, "TX: SMS DELIVER\n"); - rate_ctr_inc(&conn->bts->network->ratectrs->ctr[MSC_CTR_SMS_DELIVERED]); + rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_DELIVERED]); db_sms_inc_deliver_attempts(trans->sms.sms); return gsm411_rp_sendmsg(&trans->sms.smr_inst, msg, diff --git a/openbsc/src/libmsc/vty_interface_layer3.c b/openbsc/src/libmsc/vty_interface_layer3.c index d1041b3..e7ff0a9 100644 --- a/openbsc/src/libmsc/vty_interface_layer3.c +++ b/openbsc/src/libmsc/vty_interface_layer3.c @@ -795,41 +795,41 @@ openbsc_vty_print_statistics(vty, net); vty_out(vty, "Location Update : %lu attach, %lu normal, %lu periodic%s", - net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_ATTACH].current, - net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_NORMAL].current, - net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_PERIODIC].current, + net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_ATTACH].current, + net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_NORMAL].current, + net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_PERIODIC].current, VTY_NEWLINE); vty_out(vty, "IMSI Detach Indications : %lu%s", - net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_DETACH].current, + net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_DETACH].current, VTY_NEWLINE); vty_out(vty, "Location Update Response: %lu accept, %lu reject%s", - net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_ACCEPT].current, - net->ratectrs->ctr[MSC_CTR_LOC_UPDATE_RESP_REJECT].current, + net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_RESP_ACCEPT].current, + net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_RESP_REJECT].current, VTY_NEWLINE); vty_out(vty, "Handover : %lu attempted, %lu no_channel, %lu timeout, " "%lu completed, %lu failed%s", - net->ratectrs->ctr[MSC_CTR_HANDOVER_ATTEMPTED].current, - net->ratectrs->ctr[MSC_CTR_HANDOVER_NO_CHANNEL].current, - net->ratectrs->ctr[MSC_CTR_HANDOVER_TIMEOUT].current, - net->ratectrs->ctr[MSC_CTR_HANDOVER_COMPLETED].current, - net->ratectrs->ctr[MSC_CTR_HANDOVER_FAILED].current, + net->msc_ctrs->ctr[BSC_CTR_HANDOVER_ATTEMPTED].current, + net->msc_ctrs->ctr[BSC_CTR_HANDOVER_NO_CHANNEL].current, + net->msc_ctrs->ctr[BSC_CTR_HANDOVER_TIMEOUT].current, + net->msc_ctrs->ctr[BSC_CTR_HANDOVER_COMPLETED].current, + net->msc_ctrs->ctr[BSC_CTR_HANDOVER_FAILED].current, VTY_NEWLINE); vty_out(vty, "SMS MO : %lu submitted, %lu no receiver%s", - net->ratectrs->ctr[MSC_CTR_SMS_SUBMITTED].current, - net->ratectrs->ctr[MSC_CTR_SMS_NO_RECEIVER].current, + net->msc_ctrs->ctr[MSC_CTR_SMS_SUBMITTED].current, + net->msc_ctrs->ctr[MSC_CTR_SMS_NO_RECEIVER].current, VTY_NEWLINE); vty_out(vty, "SMS MT : %lu delivered, %lu no memory, %lu other error%s", - net->ratectrs->ctr[MSC_CTR_SMS_DELIVERED].current, - net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_MEM].current, - net->ratectrs->ctr[MSC_CTR_SMS_RP_ERR_OTHER].current, + net->msc_ctrs->ctr[MSC_CTR_SMS_DELIVERED].current, + net->msc_ctrs->ctr[MSC_CTR_SMS_RP_ERR_MEM].current, + net->msc_ctrs->ctr[MSC_CTR_SMS_RP_ERR_OTHER].current, VTY_NEWLINE); vty_out(vty, "MO Calls : %lu setup, %lu connect ack%s", - net->ratectrs->ctr[MSC_CTR_CALL_MO_SETUP].current, - net->ratectrs->ctr[MSC_CTR_CALL_MO_CONNECT_ACK].current, + net->msc_ctrs->ctr[MSC_CTR_CALL_MO_SETUP].current, + net->msc_ctrs->ctr[MSC_CTR_CALL_MO_CONNECT_ACK].current, VTY_NEWLINE); vty_out(vty, "MT Calls : %lu setup, %lu connect%s", - net->ratectrs->ctr[MSC_CTR_CALL_MT_SETUP].current, - net->ratectrs->ctr[MSC_CTR_CALL_MT_CONNECT].current, + net->msc_ctrs->ctr[MSC_CTR_CALL_MT_SETUP].current, + net->msc_ctrs->ctr[MSC_CTR_CALL_MT_CONNECT].current, VTY_NEWLINE); return CMD_SUCCESS; } -- To view, visit https://gerrit.osmocom.org/646 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I7361033cd1eb919ec3c2ea2652f40ab8c75b2f99 Gerrit-PatchSet: 5 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Tue Aug 30 11:11:23 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 30 Aug 2016 11:11:23 +0000 Subject: osmo-iuh[master]: UE Register with TMSI: reply with a Register Reject In-Reply-To: References: Message-ID: Patch Set 1: BTW, this is from when we were testing with the ipa nano3G at the OsmoDevCon. The nano3G hack that follows up on this actually accepts all UE Register identities; this patch only fixes the missing reject for "normal" Iuh operation. -- To view, visit https://gerrit.osmocom.org/723 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia47e398e50e316842cd260dc0d9a4e2d8a1c627c Gerrit-PatchSet: 1 Gerrit-Project: osmo-iuh Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 30 11:16:14 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 30 Aug 2016 11:16:14 +0000 Subject: osmo-pcu[master]: EGPRS: EPDAN decoding: add test case to show no ack_nack len... In-Reply-To: References: Message-ID: Patch Set 6: (1 comment) https://gerrit.osmocom.org/#/c/765/6/tests/rlcmac/RLCMACTest.cpp File tests/rlcmac/RLCMACTest.cpp: Line 231: OSMO_ASSERT(strcmp(osmo_hexdump(urbb->URBB, 13), I'd prefer to have !strcmp() instead of strcmp(): that way we can see exactly how the fix affects the byte sequence, in your next commit. -- To view, visit https://gerrit.osmocom.org/765 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I8da84794748f2e81722c3eca69b46ccc3a21552e Gerrit-PatchSet: 6 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 30 11:18:09 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 30 Aug 2016 11:18:09 +0000 Subject: osmo-pcu[master]: EGPRS: EPDAN decoding: add test case to show no ack_nack len... In-Reply-To: References: Message-ID: Patch Set 6: (1 comment) https://gerrit.osmocom.org/#/c/765/6/tests/rlcmac/RLCMACTest.cpp File tests/rlcmac/RLCMACTest.cpp: Line 231: OSMO_ASSERT(strcmp(osmo_hexdump(urbb->URBB, 13), > I'd prefer to have !strcmp() instead of On the other hand, if the remaining bytes are undefined random, then this here is better of course. Are they random? -- To view, visit https://gerrit.osmocom.org/765 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I8da84794748f2e81722c3eca69b46ccc3a21552e Gerrit-PatchSet: 6 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 30 11:31:00 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 30 Aug 2016 11:31:00 +0000 Subject: osmo-pcu[master]: Fix DL window calculation during tbf update In-Reply-To: References: Message-ID: Patch Set 1: (1 comment) https://gerrit.osmocom.org/#/c/798/1/src/tbf.cpp File src/tbf.cpp: Line 387: ws = OSMO_MIN(128 * num_pdch, ws); This calculation is a code duplication from a part of tbf_alloc_dl_tbf() below. Rather have a static function to calculate, and call in both places. Combine as much common code as possible, i.e. pass dl_slots() and bts as argument, having pcu_bitcount() and ws in the function. I am uncertain ... here you use bts->bts_data()->ws_base and ->ws_pdch, while tbf_alloc_dl_tbf() uses bts->ws_base and ->ws_pdch. Could you please explain this difference if it is valid? -- To view, visit https://gerrit.osmocom.org/798 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I41aa807068520460fd665a55e3529e60f6bbb630 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 30 11:36:23 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 30 Aug 2016 11:36:23 +0000 Subject: osmo-pcu[master]: GPRS: PUAN encoding: add test case to show wrong BSNs status In-Reply-To: References: Message-ID: Patch Set 1: (1 comment) https://gerrit.osmocom.org/#/c/770/1/tests/tbf/TbfTest.cpp File tests/tbf/TbfTest.cpp: Line 1578: ms_class); just asking ... why split the test in two functions? Above test could just be in here, right? -- To view, visit https://gerrit.osmocom.org/770 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ied0f1dd3037d8fac6a772f4e097defb72634f955 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 30 11:37:08 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 30 Aug 2016 11:37:08 +0000 Subject: osmo-pcu[master]: EGPRS: EPDAN decoding: add test case to show no ack_nack len... In-Reply-To: References: Message-ID: Patch Set 6: (1 comment) https://gerrit.osmocom.org/#/c/765/6/tests/rlcmac/RLCMACTest.cpp File tests/rlcmac/RLCMACTest.cpp: Line 231: OSMO_ASSERT(strcmp(osmo_hexdump(urbb->URBB, 13), > On the other hand, if the remaining bytes are undefined random, Hi Neels, These are random values so I have kept this way. Thanks, Aravind sirsikar -- To view, visit https://gerrit.osmocom.org/765 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I8da84794748f2e81722c3eca69b46ccc3a21552e Gerrit-PatchSet: 6 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 30 11:39:35 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 30 Aug 2016 11:39:35 +0000 Subject: osmo-pcu[master]: GPRS: PUAN encoding: add test case to show wrong BSNs status In-Reply-To: References: Message-ID: Patch Set 2: (1 comment) https://gerrit.osmocom.org/#/c/770/1/tests/tbf/TbfTest.cpp File tests/tbf/TbfTest.cpp: Line 1578: OSMO_ASSERT(ms1 != ms); > just asking ... why split the test in two functions? The fixes moved to TypeTest.cpp and this file modifications are reverted. Please refer latest set. -- To view, visit https://gerrit.osmocom.org/770 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ied0f1dd3037d8fac6a772f4e097defb72634f955 Gerrit-PatchSet: 2 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 30 11:44:25 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 30 Aug 2016 11:44:25 +0000 Subject: osmo-pcu[master]: Update the function immediate assignment for EGPRS In-Reply-To: References: Message-ID: Patch Set 6: (2 comments) https://gerrit.osmocom.org/#/c/431/6/src/encoding.cpp File src/encoding.cpp: Line 256: bitvec_write_field(dest, wp, ra, 8); /* RACH value */ might be a stupid question ... if ra is now 16bit aka 11bit, isn't a len == 8 too small? Maybe this deserves a comment? https://gerrit.osmocom.org/#/c/431/6/tests/edge/EdgeTest.cpp File tests/edge/EdgeTest.cpp: Line 39: #include why? -- To view, visit https://gerrit.osmocom.org/431 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ie5e309156e5dbbb6add74a1b4d257c4ee2332e52 Gerrit-PatchSet: 6 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-Reviewer: bhargava_abhyankar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 30 11:50:44 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 30 Aug 2016 11:50:44 +0000 Subject: osmo-pcu[master]: Fix DL window calculation during tbf update In-Reply-To: References: Message-ID: Patch Set 1: (1 comment) https://gerrit.osmocom.org/#/c/798/1/src/tbf.cpp File src/tbf.cpp: Line 387: ws = OSMO_MIN(128 * num_pdch, ws); > This calculation is a code duplication from a part of tbf_alloc_dl_tbf() be in this functions bts is of type BTS*(member variable). in another function what you mentioned bts is of type gprs_rlcmac_bts *bts_data. we need a content inside gprs_rlcmac_bts for this purpose. In any case I will write separate function. -- To view, visit https://gerrit.osmocom.org/798 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I41aa807068520460fd665a55e3529e60f6bbb630 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 30 11:52:04 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 30 Aug 2016 11:52:04 +0000 Subject: osmo-pcu[master]: Handle EGPRS 11 bit RACH in osmo-pcu In-Reply-To: References: Message-ID: Patch Set 5: (6 comments) https://gerrit.osmocom.org/#/c/430/5/src/bts.cpp File src/bts.cpp: Line 520: /* class yet */ /* multi * line * comment */ Line 576: if ((is_11bit == 0) && (burst_type == GSM_L1_BURST_TYPE_ACCESS_0)) { is_11bit is boolean, right? It should be only 0 or 1? If so, just do 'if (!is_11bit && ...'; If not, change the name. Line 584: "phase access,but we force two phase access\n"); (space after comma) Line 588: } else if ((is_11bit == 1) && if (is_11bit && ... Line 603: *priority = ((ra & 0x18) >> 3); (unnecessary outer braces) Line 612: } else if ((is_11bit == 1) && boolean -- To view, visit https://gerrit.osmocom.org/430 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I61d74a32f7764644ed86f7fdf97fa3c2f61503f7 Gerrit-PatchSet: 5 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-Reviewer: bhargava_abhyankar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 30 12:16:46 2016 From: gerrit-no-reply at lists.osmocom.org (Holger Freyther) Date: Tue, 30 Aug 2016 12:16:46 +0000 Subject: osmo-pcu[master]: Fix DL window calculation during tbf update In-Reply-To: References: Message-ID: Patch Set 1: Code-Review-2 Please don't duplicate that calculation. For latency and against buffer bloat we had decided to have the window smaller than it theoretucally could be. As such it is "business" logic and should not be duplicated in two different places. -- To view, visit https://gerrit.osmocom.org/798 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I41aa807068520460fd665a55e3529e60f6bbb630 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 30 12:38:03 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 30 Aug 2016 12:38:03 +0000 Subject: osmo-bts[master]: Fix ip.access style dyn PDCH, broken in 37af36e85eca54659508... In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 Since this fixes a regression, taking the liberty to submit it on my sole responsibility. -- To view, visit https://gerrit.osmocom.org/751 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I376b92a06f4cbe943c1c913dea7487fac53a7d08 Gerrit-PatchSet: 1 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 30 12:38:04 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 30 Aug 2016 12:38:04 +0000 Subject: [MERGED] osmo-bts[master]: Fix ip.access style dyn PDCH, broken in 37af36e85eca54659508... In-Reply-To: References: Message-ID: Neels Hofmeyr has submitted this change and it was merged. Change subject: Fix ip.access style dyn PDCH, broken in 37af36e85eca546595081246aec010fa7f6fd0be ...................................................................... Fix ip.access style dyn PDCH, broken in 37af36e85eca546595081246aec010fa7f6fd0be Commit "sysmo,lc15: ts_connect_as(): log error also for pchan_as == TCH/F_PDCH" introduced a check for TCH/F_PDCH intended only for TCH/F_TCH/H_PDCH. It looked correct, but TCH/F_PDCH startup was designed differently: For TCH/F_PDCH, the idea was to look it up in pchan_to_logChComb[] and obtain the TCH/F channel combination, so that TCH/F_PDCH first initialize as TCH/F. So pchan was in fact intended to be passed as TCH/F_PDCH. For Osmocom TCH/F_TCH/H_PDCH, we've in the meantime added a ts_opstart() function that makes this decision explicitly. So, instead of reverting the erratic commit, add TCH/F_PDCH to ts_opstart(), for both sysmo and lc15. In ts_opstart(), move to a switch statement to resolve the actual pchan to use for ts_connect_as(). Drop TCH/F_PDCH and TCH/F_TCH/H_PDCH from pchan_to_logChComb[] and comment. Change-Id: I376b92a06f4cbe943c1c913dea7487fac53a7d08 --- M src/osmo-bts-litecell15/oml.c M src/osmo-bts-sysmo/oml.c 2 files changed, 38 insertions(+), 16 deletions(-) Approvals: Neels Hofmeyr: Looks good to me, approved; Verified Jenkins Builder: Verified diff --git a/src/osmo-bts-litecell15/oml.c b/src/osmo-bts-litecell15/oml.c index 5ce510a..a175af4 100644 --- a/src/osmo-bts-litecell15/oml.c +++ b/src/osmo-bts-litecell15/oml.c @@ -89,11 +89,12 @@ [GSM_PCHAN_SDCCH8_SACCH8C] = GsmL1_LogChComb_VII, [GSM_PCHAN_SDCCH8_SACCH8C_CBCH] = GsmL1_LogChComb_VII, [GSM_PCHAN_PDCH] = GsmL1_LogChComb_XIII, - [GSM_PCHAN_TCH_F_PDCH] = GsmL1_LogChComb_I, /*< first init - like TCH/F, until PDCH ACT */ - [GSM_PCHAN_TCH_F_TCH_H_PDCH] = GsmL1_LogChComb_0, /*< first unused, - until first RSL CHAN ACT */ [GSM_PCHAN_UNKNOWN] = GsmL1_LogChComb_0, + /* + * GSM_PCHAN_TCH_F_PDCH and GSM_PCHAN_TCH_F_TCH_H_PDCH should not be + * part of this, only "real" pchan values will be looked up here. + * See the callers of ts_connect_as(). + */ }; static int trx_rf_lock(struct gsm_bts_trx *trx, int locked, l1if_compl_cb *cb); @@ -507,12 +508,22 @@ static int ts_opstart(struct gsm_bts_trx_ts *ts) { - if (ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) { - /* First connect as NONE, until first RSL CHAN ACT. */ + enum gsm_phys_chan_config pchan = ts->pchan; + switch (pchan) { + case GSM_PCHAN_TCH_F_TCH_H_PDCH: ts->dyn.pchan_is = ts->dyn.pchan_want = GSM_PCHAN_NONE; - return ts_connect_as(ts, GSM_PCHAN_NONE, opstart_compl_cb, NULL); + /* First connect as NONE, until first RSL CHAN ACT. */ + pchan = GSM_PCHAN_NONE; + break; + case GSM_PCHAN_TCH_F_PDCH: + /* First connect as TCH/F, expecting PDCH ACT. */ + pchan = GSM_PCHAN_TCH_F; + break; + default: + /* simply use ts->pchan */ + break; } - return ts_connect_as(ts, ts->pchan, opstart_compl_cb, NULL); + return ts_connect_as(ts, pchan, opstart_compl_cb, NULL); } GsmL1_Sapi_t lchan_to_GsmL1_Sapi_t(const struct gsm_lchan *lchan) diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c index 6f0629d..dea1c5e 100644 --- a/src/osmo-bts-sysmo/oml.c +++ b/src/osmo-bts-sysmo/oml.c @@ -86,11 +86,12 @@ [GSM_PCHAN_SDCCH8_SACCH8C] = GsmL1_LogChComb_VII, [GSM_PCHAN_SDCCH8_SACCH8C_CBCH] = GsmL1_LogChComb_VII, [GSM_PCHAN_PDCH] = GsmL1_LogChComb_XIII, - [GSM_PCHAN_TCH_F_PDCH] = GsmL1_LogChComb_I, /*< first init - like TCH/F, until PDCH ACT */ - [GSM_PCHAN_TCH_F_TCH_H_PDCH] = GsmL1_LogChComb_0, /*< first unused, - until first RSL CHAN ACT */ [GSM_PCHAN_UNKNOWN] = GsmL1_LogChComb_0, + /* + * GSM_PCHAN_TCH_F_PDCH and GSM_PCHAN_TCH_F_TCH_H_PDCH should not be + * part of this, only "real" pchan values will be looked up here. + * See the callers of ts_connect_as(). + */ }; static int trx_rf_lock(struct gsm_bts_trx *trx, int locked, l1if_compl_cb *cb); @@ -515,12 +516,22 @@ static int ts_opstart(struct gsm_bts_trx_ts *ts) { - if (ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) { - /* First connect as NONE, until first RSL CHAN ACT. */ + enum gsm_phys_chan_config pchan = ts->pchan; + switch (pchan) { + case GSM_PCHAN_TCH_F_TCH_H_PDCH: ts->dyn.pchan_is = ts->dyn.pchan_want = GSM_PCHAN_NONE; - return ts_connect_as(ts, GSM_PCHAN_NONE, opstart_compl_cb, NULL); + /* First connect as NONE, until first RSL CHAN ACT. */ + pchan = GSM_PCHAN_NONE; + break; + case GSM_PCHAN_TCH_F_PDCH: + /* First connect as TCH/F, expecting PDCH ACT. */ + pchan = GSM_PCHAN_TCH_F; + break; + default: + /* simply use ts->pchan */ + break; } - return ts_connect_as(ts, ts->pchan, opstart_compl_cb, NULL); + return ts_connect_as(ts, pchan, opstart_compl_cb, NULL); } GsmL1_Sapi_t lchan_to_GsmL1_Sapi_t(const struct gsm_lchan *lchan) -- To view, visit https://gerrit.osmocom.org/751 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I376b92a06f4cbe943c1c913dea7487fac53a7d08 Gerrit-PatchSet: 2 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: neels_test_account From gerrit-no-reply at lists.osmocom.org Tue Aug 30 12:39:53 2016 From: gerrit-no-reply at lists.osmocom.org (lynxis lazus) Date: Tue, 30 Aug 2016 12:39:53 +0000 Subject: [PATCH] openbsc[master]: bsc/netinit: correct mistyped rate counter Message-ID: Review at https://gerrit.osmocom.org/799 bsc/netinit: correct mistyped rate counter Introduced by b847a21fa48158b17c4f84c1ceeb3d143cffed8c Change-Id: I57c41f98e3826951a5071b005cb640c23d466477 --- M openbsc/src/libbsc/net_init.c 1 file changed, 1 insertion(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/99/799/1 diff --git a/openbsc/src/libbsc/net_init.c b/openbsc/src/libbsc/net_init.c index 37ba3c0..65419ae 100644 --- a/openbsc/src/libbsc/net_init.c +++ b/openbsc/src/libbsc/net_init.c @@ -82,7 +82,7 @@ /* init statistics */ net->bsc_ctrs = rate_ctr_group_alloc(net, &bsc_ctrg_desc, 0); - net->bsc_ctrs = rate_ctr_group_alloc(net, &msc_ctrg_desc, 0); + net->msc_ctrs = rate_ctr_group_alloc(net, &msc_ctrg_desc, 0); net->mncc_recv = mncc_recv; net->ext_min = GSM_MIN_EXTEN; -- To view, visit https://gerrit.osmocom.org/799 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I57c41f98e3826951a5071b005cb640c23d466477 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus From gerrit-no-reply at lists.osmocom.org Tue Aug 30 12:54:35 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 30 Aug 2016 12:54:35 +0000 Subject: openbsc[master]: libmsc/bsc: split rate counters into bsc and msc group In-Reply-To: References: Message-ID: Patch Set 5: (1 comment) https://gerrit.osmocom.org/#/c/646/5/openbsc/src/libbsc/net_init.c File openbsc/src/libbsc/net_init.c: Line 85: net->bsc_ctrs = rate_ctr_group_alloc(net, &msc_ctrg_desc, 0); Whoa, missed this bug when accepting the patch: Assigning twice to net->bsc_ctrs! So you didn't test this?? -- To view, visit https://gerrit.osmocom.org/646 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I7361033cd1eb919ec3c2ea2652f40ab8c75b2f99 Gerrit-PatchSet: 5 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 30 12:57:23 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 30 Aug 2016 12:57:23 +0000 Subject: openbsc[master]: bsc/netinit: correct mistyped rate counter In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/799 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I57c41f98e3826951a5071b005cb640c23d466477 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 30 12:57:24 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 30 Aug 2016 12:57:24 +0000 Subject: [MERGED] openbsc[master]: bsc/netinit: correct mistyped rate counter In-Reply-To: References: Message-ID: Neels Hofmeyr has submitted this change and it was merged. Change subject: bsc/netinit: correct mistyped rate counter ...................................................................... bsc/netinit: correct mistyped rate counter Introduced by b847a21fa48158b17c4f84c1ceeb3d143cffed8c Change-Id: I57c41f98e3826951a5071b005cb640c23d466477 --- M openbsc/src/libbsc/net_init.c 1 file changed, 1 insertion(+), 1 deletion(-) Approvals: Neels Hofmeyr: Looks good to me, approved Jenkins Builder: Verified diff --git a/openbsc/src/libbsc/net_init.c b/openbsc/src/libbsc/net_init.c index 37ba3c0..65419ae 100644 --- a/openbsc/src/libbsc/net_init.c +++ b/openbsc/src/libbsc/net_init.c @@ -82,7 +82,7 @@ /* init statistics */ net->bsc_ctrs = rate_ctr_group_alloc(net, &bsc_ctrg_desc, 0); - net->bsc_ctrs = rate_ctr_group_alloc(net, &msc_ctrg_desc, 0); + net->msc_ctrs = rate_ctr_group_alloc(net, &msc_ctrg_desc, 0); net->mncc_recv = mncc_recv; net->ext_min = GSM_MIN_EXTEN; -- To view, visit https://gerrit.osmocom.org/799 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I57c41f98e3826951a5071b005cb640c23d466477 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Tue Aug 30 13:00:32 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 30 Aug 2016 13:00:32 +0000 Subject: openbsc[master]: libmsc/bsc: split rate counters into bsc and msc group In-Reply-To: References: Message-ID: Patch Set 5: for the record: fixed by https://gerrit.osmocom.org/799 -- To view, visit https://gerrit.osmocom.org/646 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I7361033cd1eb919ec3c2ea2652f40ab8c75b2f99 Gerrit-PatchSet: 5 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 30 13:27:59 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 30 Aug 2016 13:27:59 +0000 Subject: osmo-pcu[master]: Fix DL window calculation during tbf update In-Reply-To: References: Message-ID: Patch Set 1: Hi Holger, The issue is related to the fact that if 4 TS is configured in DL and "window-size 64 104" used in osmo-pcu.cfg, We see window size allocation is inconsistent when we create DL TBF through PCH(64) compared to DL TBF allocation through PACCH(480). and update function is used only for the PCH case. Let me know your opinion. Thanks, Aravind Sirsikar -- To view, visit https://gerrit.osmocom.org/798 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I41aa807068520460fd665a55e3529e60f6bbb630 Gerrit-PatchSet: 1 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 30 14:06:13 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Tue, 30 Aug 2016 14:06:13 +0000 Subject: osmo-pcu[master]: EGPRS: EPDAN decoding: add test case to show no ack_nack len... In-Reply-To: References: Message-ID: Patch Set 6: (1 comment) https://gerrit.osmocom.org/#/c/765/6/tests/rlcmac/RLCMACTest.cpp File tests/rlcmac/RLCMACTest.cpp: Line 231: OSMO_ASSERT(strcmp(osmo_hexdump(urbb->URBB, 13), > Hi Neels, Hmm, thinking again, if the random bits happen to be all zero by random, then this test would fail; or could randomly succeed, after we fixed it and when we've introduced a regression some time in the future. We should initialize the unwritten bytes to known values so that the result is deterministic: do a memset(urbb->URBB, -1, sizeof(urbb->URBB)); before calling decode_gsm_rlcmac_uplink()? Please try that. -- To view, visit https://gerrit.osmocom.org/765 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I8da84794748f2e81722c3eca69b46ccc3a21552e Gerrit-PatchSet: 6 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 30 14:19:15 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 30 Aug 2016 14:19:15 +0000 Subject: [PATCH] osmo-pcu[master]: EGPRS: EPDAN decoding: add test case to show no ack_nack len... In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/765 to look at the new patch set (#7). EGPRS: EPDAN decoding: add test case to show no ack_nack len issue This patch adds a test case itest_epdan_noack_nack_len_issue which expects a current bug with EGPRS EPDAN decoding Ack/Nack dissector length is not received. The test's expectation is corrected along with the bug fix in a subsequent commit Related: OS#1805 Change-Id: I8da84794748f2e81722c3eca69b46ccc3a21552e --- M tests/rlcmac/RLCMACTest.cpp 1 file changed, 24 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/65/765/7 diff --git a/tests/rlcmac/RLCMACTest.cpp b/tests/rlcmac/RLCMACTest.cpp index 466b89e..8db1c15 100644 --- a/tests/rlcmac/RLCMACTest.cpp +++ b/tests/rlcmac/RLCMACTest.cpp @@ -30,6 +30,7 @@ #include "pcu_vty.h" #include #include +#include #include } using namespace std; @@ -211,6 +212,28 @@ bitvec_free(resultVector); } +void test_epdan_no_ack_nack_len() +{ + bitvec *vector = bitvec_alloc(23); + + bitvec_unhex(vector, "40200bffd161003e0e519ffffffb800000000000000000"); + RlcMacUplink_t data; + + EGPRS_AckNack_Desc_t *urbb = + &data.u.Egprs_Packet_Downlink_Ack_Nack.EGPRS_AckNack.Desc; + memset(urbb->URBB, -1, sizeof(urbb->URBB)); + + decode_gsm_rlcmac_uplink(vector, &data); + /* + * TODO: URBB len is decoded as 102. so there is total 12 bytes and + * 6 bits in the 13th byte. in 13th byte we expect value + * as 0x00. But we see some incorrect value + */ + OSMO_ASSERT(strcmp(osmo_hexdump(urbb->URBB, 13), + "7f ff ff ee 00 00 00 00 00 00 00 00 00 " + )); +} + int main(int argc, char *argv[]) { osmo_init_logging(&gprs_log_info); @@ -218,5 +241,5 @@ //printSizeofRLCMAC(); testRlcMacDownlink(); testRlcMacUplink(); - + test_epdan_no_ack_nack_len(); } -- To view, visit https://gerrit.osmocom.org/765 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I8da84794748f2e81722c3eca69b46ccc3a21552e Gerrit-PatchSet: 7 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Tue Aug 30 14:19:58 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 30 Aug 2016 14:19:58 +0000 Subject: osmo-pcu[master]: EGPRS: EPDAN decoding: add test case to show no ack_nack len... In-Reply-To: References: Message-ID: Patch Set 7: (1 comment) https://gerrit.osmocom.org/#/c/765/7/tests/rlcmac/RLCMACTest.cpp File tests/rlcmac/RLCMACTest.cpp: Line 225: fix here -- To view, visit https://gerrit.osmocom.org/765 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I8da84794748f2e81722c3eca69b46ccc3a21552e Gerrit-PatchSet: 7 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Tue Aug 30 14:20:35 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 30 Aug 2016 14:20:35 +0000 Subject: [PATCH] osmo-pcu[master]: EGPRS: EPDAN decoding: add test case to show no ack_nack len... In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/765 to look at the new patch set (#8). EGPRS: EPDAN decoding: add test case to show no ack_nack len issue This patch adds a test case itest_epdan_noack_nack_len_issue which expects a current bug with EGPRS EPDAN decoding Ack/Nack dissector length is not received. The test's expectation is corrected along with the bug fix in a subsequent commit Related: OS#1805 Change-Id: I8da84794748f2e81722c3eca69b46ccc3a21552e --- M tests/rlcmac/RLCMACTest.cpp 1 file changed, 24 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/65/765/8 diff --git a/tests/rlcmac/RLCMACTest.cpp b/tests/rlcmac/RLCMACTest.cpp index 466b89e..79c3472 100644 --- a/tests/rlcmac/RLCMACTest.cpp +++ b/tests/rlcmac/RLCMACTest.cpp @@ -30,6 +30,7 @@ #include "pcu_vty.h" #include #include +#include #include } using namespace std; @@ -211,6 +212,28 @@ bitvec_free(resultVector); } +void test_epdan_no_ack_nack_len() +{ + bitvec *vector = bitvec_alloc(23); + + bitvec_unhex(vector, "40200bffd161003e0e519ffffffb800000000000000000"); + RlcMacUplink_t data; + + EGPRS_AckNack_Desc_t *urbb = + &data.u.Egprs_Packet_Downlink_Ack_Nack.EGPRS_AckNack.Desc; + memset(urbb->URBB, -1, sizeof(urbb->URBB)); + decode_gsm_rlcmac_uplink(vector, &data); + + /* + * TODO: URBB len is decoded as 102. so there is total 12 bytes and + * 6 bits in the 13th byte. in 13th byte we expect value + * as 0x00. But we see some incorrect value + */ + OSMO_ASSERT(strcmp(osmo_hexdump(urbb->URBB, 13), + "7f ff ff ee 00 00 00 00 00 00 00 00 00 " + )); +} + int main(int argc, char *argv[]) { osmo_init_logging(&gprs_log_info); @@ -218,5 +241,5 @@ //printSizeofRLCMAC(); testRlcMacDownlink(); testRlcMacUplink(); - + test_epdan_no_ack_nack_len(); } -- To view, visit https://gerrit.osmocom.org/765 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I8da84794748f2e81722c3eca69b46ccc3a21552e Gerrit-PatchSet: 8 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar From gerrit-no-reply at lists.osmocom.org Tue Aug 30 14:24:28 2016 From: gerrit-no-reply at lists.osmocom.org (arvind.sirsikar) Date: Tue, 30 Aug 2016 14:24:28 +0000 Subject: osmo-pcu[master]: EGPRS: EPDAN decoding: add test case to show no ack_nack len... In-Reply-To: References: Message-ID: Patch Set 8: Hi Neels, I have modified the patch. Please have a look. Thanks, Aravind Sirsikar -- To view, visit https://gerrit.osmocom.org/765 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I8da84794748f2e81722c3eca69b46ccc3a21552e Gerrit-PatchSet: 8 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Tue Aug 30 16:54:49 2016 From: gerrit-no-reply at lists.osmocom.org (lynxis lazus) Date: Tue, 30 Aug 2016 16:54:49 +0000 Subject: [PATCH] openbsc[master]: gprs/gsm0408_gprs_force_reattach_oldmsg: check llme before use Message-ID: Review at https://gerrit.osmocom.org/800 gprs/gsm0408_gprs_force_reattach_oldmsg: check llme before use Change-Id: I9385655872c4dcf46aa1d18bcc47b84aba2f34f7 --- M openbsc/src/gprs/gprs_gmm.c 1 file changed, 2 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/00/800/1 diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index 1efada9..a0b52ab 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -2171,7 +2171,8 @@ struct gprs_llc_llme *llme) { int rc; - gprs_llgmm_reset_oldmsg(msg, GPRS_SAPI_GMM, llme); + if (llme) + gprs_llgmm_reset_oldmsg(msg, GPRS_SAPI_GMM, llme); rc = gsm48_tx_gmm_detach_req_oldmsg( msg, GPRS_DET_T_MT_REATT_REQ, GMM_CAUSE_IMPL_DETACHED); -- To view, visit https://gerrit.osmocom.org/800 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I9385655872c4dcf46aa1d18bcc47b84aba2f34f7 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus From gerrit-no-reply at lists.osmocom.org Tue Aug 30 16:54:50 2016 From: gerrit-no-reply at lists.osmocom.org (lynxis lazus) Date: Tue, 30 Aug 2016 16:54:50 +0000 Subject: [PATCH] openbsc[master]: gprs/gprs_llc: fix null pointer deref in gprs_llc_rcvmsg Message-ID: Review at https://gerrit.osmocom.org/801 gprs/gprs_llc: fix null pointer deref in gprs_llc_rcvmsg Change-Id: I1f7e1d524042134c93a4f3de599c54d442447512 --- M openbsc/src/gprs/gprs_llc.c 1 file changed, 1 insertion(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/01/801/1 diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c index 32920da..a2ffa51 100644 --- a/openbsc/src/gprs/gprs_llc.c +++ b/openbsc/src/gprs/gprs_llc.c @@ -859,8 +859,7 @@ case GPRS_SAPI_SNDCP9: case GPRS_SAPI_SNDCP11: /* Ask an upper layer for help. */ - return gsm0408_gprs_force_reattach_oldmsg(msg, - lle->llme); + return gsm0408_gprs_force_reattach_oldmsg(msg, NULL); default: break; } -- To view, visit https://gerrit.osmocom.org/801 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I1f7e1d524042134c93a4f3de599c54d442447512 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus From gerrit-no-reply at lists.osmocom.org Tue Aug 30 17:48:19 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Tue, 30 Aug 2016 17:48:19 +0000 Subject: [PATCH] openbsc[master]: Adding SNDCP-XID encoder / decoder and unit test In-Reply-To: References: Message-ID: Hello Neels Hofmeyr, Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/641 to look at the new patch set (#14). Adding SNDCP-XID encoder / decoder and unit test The SNDCP-XID (or layer-3 xid) is used to exchange layer-3 parameters such as compression. The encoder encodes a bytestream that is then sent as regular XID field from LLC. We will need the SNDCP-XID to negotiate the parameters for our upcomming GPRS data and header compression features Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e --- M openbsc/.gitignore M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_sndcp_xid.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_sndcp_xid.c M openbsc/tests/Makefile.am M openbsc/tests/sgsn/Makefile.am A openbsc/tests/sndcp_xid/Makefile.am A openbsc/tests/sndcp_xid/sndcp_xid_test.c A openbsc/tests/sndcp_xid/sndcp_xid_test.ok M openbsc/tests/testsuite.at 12 files changed, 2,347 insertions(+), 5 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/41/641/14 diff --git a/openbsc/.gitignore b/openbsc/.gitignore index 518a960..8ce3b70 100644 --- a/openbsc/.gitignore +++ b/openbsc/.gitignore @@ -82,6 +82,7 @@ tests/gtphub/gtphub_test tests/mm_auth/mm_auth_test tests/xid/xid_test +tests/sndcp_xid/sndcp_xid_test tests/atconfig tests/atlocal diff --git a/openbsc/configure.ac b/openbsc/configure.ac index f63d61f..9dc2f8d 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -231,6 +231,7 @@ tests/gtphub/Makefile tests/mm_auth/Makefile tests/xid/Makefile + tests/sndcp_xid/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 90aa364..a5ba3ef 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,7 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_llc_xid.h gprs_sndcp.h \ + gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ iu.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h diff --git a/openbsc/include/openbsc/gprs_sndcp_xid.h b/openbsc/include/openbsc/gprs_sndcp_xid.h new file mode 100644 index 0000000..02904a7 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_xid.h @@ -0,0 +1,216 @@ +/* GPRS SNDCP XID field encoding/decoding as per 3GPP TS 44.065 */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include + +#define CURRENT_SNDCP_VERSION 0 /* See 3GPP TS 44.065, clause 8 */ +#define MAX_ENTITIES 32 /* 3GPP TS 44.065 reserves 5 bit + * for compression enitity number */ + +#define MAX_COMP 16 /* Maximum number of possible pcomp/dcomp values */ +#define MAX_NSAPI 11 /* Maximum number usable NSAPIs */ +#define MAX_ROHC 16 /* Maximum number of ROHC compression profiles */ + +/* According to: 3GPP TS 44.065, 6.5.1.1 Format of the protocol control + * information compression field (Figure 7) and 3GPP TS 44.065, + * 6.6.1.1 Format of the data compression field (Figure 9) */ +struct gprs_sndcp_comp_field { + struct llist_head list; + + /* Propose bit (P), see also: 6.5.1.1.2 and 6.6.1.1.2 */ + unsigned int p; + + /* Entity number, see also: 6.5.1.1.3 and 6.6.1.1.3 */ + unsigned int entity; + + /* Algorithm identifier, see also: 6.5.1.1.4 and 6.6.1.1.4 */ + int algo; + + /* Number of contained PCOMP / DCOMP values */ + uint8_t comp_len; + + /* PCOMP / DCOMP values, see also: 6.5.1.1.5 and 6.6.1.1.5 */ + uint8_t comp[MAX_COMP]; + + /* Note: Only one of the following struct pointers may, + be used. Unused pointers must be set to NULL! */ + struct gprs_sndcp_pcomp_rfc1144_params *rfc1144_params; + struct gprs_sndcp_pcomp_rfc2507_params *rfc2507_params; + struct gprs_sndcp_pcomp_rohc_params *rohc_params; + struct gprs_sndcp_dcomp_v42bis_params *v42bis_params; + struct gprs_sndcp_dcomp_v44_params *v44_params; +}; + +/* According to: 3GPP TS 44.065, 6.5.1.1.4 Algorithm identifier */ +enum gprs_sndcp_hdr_comp_algo { + RFC_1144, /* TCP/IP header compression, see also 6.5.2 */ + RFC_2507, /* TCP/UDP/IP header compression, see also: 6.5.3 */ + ROHC /* Robust Header Compression, see also 6.5.4 */ +}; + +/* According to: 3GPP TS 44.065, 6.5.1.1.4 Algorithm identifier */ +enum gprs_sndcp_data_comp_algo { + V42BIS, /* V.42bis data compression, see also 6.6.2 */ + V44 /* V44 data compression, see also: 6.6.3 */ +}; + +/* According to: 3GPP TS 44.065, 8 SNDCP XID parameters */ +enum gprs_sndcp_xid_param_types { + SNDCP_XID_VERSION_NUMBER, + SNDCP_XID_DATA_COMPRESSION, /* See also: subclause 6.6.1 */ + SNDCP_XID_PROTOCOL_COMPRESSION, /* See also: subclause 6.5.1 */ +}; + +/* According to: 3GPP TS 44.065, 6.5.2.1 Parameters (Table 5) */ +struct gprs_sndcp_pcomp_rfc1144_params { + uint8_t nsapi_len; /* Number of applicable NSAPIs + * (default 0) */ + uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */ + int s01; /* (default 15) */ +}; + +/* According to: 3GPP TS 44.065, 6.5.2.2 Assignment of PCOMP values */ +enum gprs_sndcp_pcomp_rfc1144_pcomp { + RFC1144_PCOMP1, /* Uncompressed TCP */ + RFC1144_PCOMP2, /* Compressed TCP */ + RFC1144_PCOMP_NUM /* Number of pcomp values */ +}; + +/* According to: 3GPP TS 44.065, 6.5.3.1 Parameters (Table 6) */ +struct gprs_sndcp_pcomp_rfc2507_params { + uint8_t nsapi_len; /* Number of applicable NSAPIs + * (default 0) */ + uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */ + int f_max_period; /* (default 256) */ + int f_max_time; /* (default 5) */ + int max_header; /* (default 168) */ + int tcp_space; /* (default 15) */ + int non_tcp_space; /* (default 15) */ +}; + +/* According to: 3GPP TS 44.065, 6.5.3.2 Assignment of PCOMP values for RFC2507 */ +enum gprs_sndcp_pcomp_rfc2507_pcomp { + RFC2507_PCOMP1, /* Full Header */ + RFC2507_PCOMP2, /* Compressed TCP */ + RFC2507_PCOMP3, /* Compressed TCP non delta */ + RFC2507_PCOMP4, /* Compressed non TCP */ + RFC2507_PCOMP5, /* Context state */ + RFC2507_PCOMP_NUM /* Number of pcomp values */ +}; + +/* According to: 3GPP TS 44.065, 6.5.4.1 Parameter (Table 10) */ +struct gprs_sndcp_pcomp_rohc_params { + uint8_t nsapi_len; /* Number of applicable NSAPIs + * (default 0) */ + uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */ + int max_cid; /* (default 15) */ + int max_header; /* (default 168) */ + uint8_t profile_len; /* (default 1) */ + uint16_t profile[MAX_ROHC]; /* (default 0, ROHC uncompressed) */ +}; + +/* According to: 3GPP TS 44.065, 6.5.4.2 Assignment of PCOMP values for ROHC */ +enum gprs_sndcp_pcomp_rohc_pcomp { + ROHC_PCOMP1, /* ROHC small CIDs */ + ROHC_PCOMP2, /* ROHC large CIDs */ + ROHC_PCOMP_NUM /* Number of pcomp values */ +}; + +/* ROHC compression profiles, see also: + http://www.iana.org/assignments/rohc-pro-ids/rohc-pro-ids.xhtml */ +enum gprs_sndcp_xid_rohc_profiles { + ROHC_UNCOMPRESSED = 0x0000, /* ROHC uncompressed [RFC5795] */ + ROHC_RTP = 0x0001, /* ROHC RTP [RFC3095] */ + ROHCV2_RTP = 0x0101, /* ROHCv2 RTP [RFC5225] */ + ROHC_UDP = 0x0002, /* ROHC UDP [RFC3095] */ + ROHCv2_UDP = 0x0102, /* ROHCv2 UDP [RFC5225] */ + ROHC_ESP = 0x0003, /* ROHC ESP [RFC3095] */ + ROHCV2_ESP = 0x0103, /* ROHCv2 ESP [RFC5225] */ + ROHC_IP = 0x0004, /* ROHC IP [RFC3843] */ + ROHCV2_IP = 0x0104, /* ROHCv2 IP [RFC5225] */ + ROHC_LLA = 0x0005, /* ROHC LLA [RFC4362] */ + ROHC_LLA_WITH_R_MODE = 0x0105, /* ROHC LLA with R-mode [RFC3408] */ + ROHC_TCP = 0x0006, /* ROHC TCP [RFC6846] */ + ROHC_RTP_UDP_LITE = 0x0007, /* ROHC RTP/UDP-Lite [RFC4019] */ + ROHCV2_RTP_UDP_LITE = 0x0107, /* ROHCv2 RTP/UDP-Lite [RFC5225] */ + ROHC_UDP_LITE = 0x0008, /* ROHC UDP-Lite [RFC4019] */ + ROHCV2_UDP_LITE = 0x0108, /* ROHCv2 UDP-Lite [RFC5225] */ +}; + +/* According to: 3GPP TS 44.065, 6.6.2.1 Parameters (Table 7a) */ +struct gprs_sndcp_dcomp_v42bis_params { + uint8_t nsapi_len; /* Number of applicable NSAPIs + * (default 0) */ + uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */ + int p0; /* (default 3) */ + int p1; /* (default 2048) */ + int p2; /* (default 20) */ + +}; + +/* According to: 3GPP TS 44.065, 6.6.2.2 Assignment of DCOMP values */ +enum gprs_sndcp_dcomp_v42bis_dcomp { + V42BIS_DCOMP1, /* V.42bis enabled */ + V42BIS_DCOMP_NUM /* Number of dcomp values */ +}; + +/* According to: 3GPP TS 44.065, 6.6.3.1 Parameters (Table 7c) */ +struct gprs_sndcp_dcomp_v44_params { + uint8_t nsapi_len; /* Number of applicable NSAPIs + * (default 0) */ + uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */ + int c0; /* (default 10000000) */ + int p0; /* (default 3) */ + int p1t; /* Refer to subclause 6.6.3.1.4 */ + int p1r; /* Refer to subclause 6.6.3.1.5 */ + int p3t; /* (default 3 x p1t) */ + int p3r; /* (default 3 x p1r) */ +}; + +/* According to: 3GPP TS 44.065, 6.6.3.2 Assignment of DCOMP values */ +enum gprs_sndcp_dcomp_v44_dcomp { + V44_DCOMP1, /* Packet method compressed */ + V44_DCOMP2, /* Multi packet method compressed */ + V44_DCOMP_NUM /* Number of dcomp values */ +}; + +/* Transform a list with compression fields into an SNDCP-XID message (dst) */ +int gprs_sndcp_compile_xid(uint8_t *dst, unsigned int dst_maxlen, + const struct llist_head *comp_fields); + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +struct llist_head *gprs_sndcp_parse_xid(const void *ctx, + const uint8_t * src, + unsigned int src_len, + const struct llist_head *comp_fields_req); + +/* Find out to which compression class the specified comp-field belongs + * (header compression or data compression?) */ +int gprs_sndcp_get_compression_class( + const struct gprs_sndcp_comp_field *comp_field); + +/* Dump a list with SNDCP-XID fields (Debug) */ +void gprs_sndcp_dump_comp_fields(const struct llist_head *comp_fields, + unsigned int logl); + diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 1b6de46..fa4a3dd 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -26,11 +26,11 @@ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ - oap.c oap_messages.c gprs_llc_xid.c + oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ - $(LIBCRYPTO_LIBS) -lrt + $(LIBCRYPTO_LIBS) -lrt -lm osmo_gtphub_SOURCES = gtphub_main.c gtphub.c gtphub_sock.c gtphub_ares.c \ gtphub_vty.c sgsn_ares.c gprs_utils.c diff --git a/openbsc/src/gprs/gprs_sndcp_xid.c b/openbsc/src/gprs/gprs_sndcp_xid.c new file mode 100644 index 0000000..270bdee --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_xid.c @@ -0,0 +1,1803 @@ +/* GPRS SNDCP XID field encoding/decoding as per 3GPP TS 44.065 */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* When the propose bit in an SNDCP-XID compression field is set to zero, + * the algorithm identifier is stripped. The algoritm parameters are specific + * for each algorithms. The following struct is used to pass the information + * about the referenced algorithm to the parser. */ +struct entity_algo_table { + unsigned int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + unsigned int algo; /* see also: 6.5.1.1.4 and 6.6.1.1.4 */ + unsigned int compclass; /* Can be either SNDCP_XID_DATA_COMPRESSION or + SNDCP_XID_PROTOCOL_COMPRESSION */ +}; + +/* FUNCTIONS RELATED TO SNDCP-XID ENCODING */ + +/* Encode applicable sapis (works the same in all three compression schemes) */ +static int encode_pcomp_applicable_sapis(uint8_t *dst, + const uint8_t *nsapis, + uint8_t nsapis_len) +{ + /* NOTE: Buffer *dst needs offer at 2 bytes + * of space to store the generation results */ + + uint16_t blob; + uint8_t nsapi; + int i; + + /* Bail if number of possible nsapis exceeds valid range + * (Only 11 nsapis possible for PDP-Contexts) */ + OSMO_ASSERT(nsapis_len <= 11); + + /* Encode applicable SAPIs */ + blob = 0; + for (i = 0; i < nsapis_len; i++) { + nsapi = nsapis[i]; + /* Only NSAPI 5 to 15 are applicable for user traffic (PDP- + * contexts). Only for these NSAPIs SNDCP-XID parameters + * can apply. See also 3GPP TS 44.065, 5.1 Service primitives */ + OSMO_ASSERT(nsapi >= 5 && nsapi <= 15); + blob |= (1 << nsapi); + } + + /* Store result */ + *dst = (blob >> 8) & 0xFF; + dst++; + *dst = blob & 0xFF; + + return 2; +} + +/* Encode rfc1144 parameter field + * (see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */ +static int encode_pcomp_rfc1144_params(uint8_t *dst, unsigned int dst_maxlen, + const struct + gprs_sndcp_pcomp_rfc1144_params *params) +{ + /* NOTE: Buffer *dst should offer at least 3 bytes + * of space to store the generation results */ + + int dst_counter = 0; + int rc; + + OSMO_ASSERT(dst_maxlen >= 3); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode s01 (see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */ + OSMO_ASSERT(params->s01 >= 0); + OSMO_ASSERT(params->s01 <= 255); + *dst = params->s01; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + +/* + * Encode rfc2507 parameter field + * (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) + */ +static int encode_pcomp_rfc2507_params(uint8_t *dst, unsigned int dst_maxlen, + const struct + gprs_sndcp_pcomp_rfc2507_params *params) +{ + /* NOTE: Buffer *dst should offer at least 3 bytes + * of space to store the generation results */ + + int dst_counter = 0; + int rc; + + OSMO_ASSERT(dst_maxlen >= 9); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode F_MAX_PERIOD (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->f_max_period >= 1); + OSMO_ASSERT(params->f_max_period <= 65535); + *dst = (params->f_max_period >> 8) & 0xFF; + dst++; + dst_counter++; + *dst = (params->f_max_period) & 0xFF; + dst++; + dst_counter++; + + /* Encode F_MAX_TIME (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->f_max_time >= 1); + OSMO_ASSERT(params->f_max_time <= 255); + *dst = params->f_max_time; + dst++; + dst_counter++; + + /* Encode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->max_header >= 60); + OSMO_ASSERT(params->max_header <= 255); + *dst = params->max_header; + dst++; + dst_counter++; + + /* Encode TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->tcp_space >= 3); + OSMO_ASSERT(params->tcp_space <= 255); + *dst = params->tcp_space; + dst++; + dst_counter++; + + /* Encode NON_TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + OSMO_ASSERT(params->non_tcp_space >= 3); + OSMO_ASSERT(params->non_tcp_space <= 65535); + *dst = (params->non_tcp_space >> 8) & 0xFF; + dst++; + dst_counter++; + *dst = (params->non_tcp_space) & 0xFF; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + +/* Encode ROHC parameter field + * (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ +static int encode_pcomp_rohc_params(uint8_t *dst, unsigned int dst_maxlen, + const struct gprs_sndcp_pcomp_rohc_params + *params) +{ + /* NOTE: Buffer *dst should offer at least 36 + * (2 * 16 Profiles + 2 * 3 Parameter) bytes + * of memory space to store generation results */ + + int i; + int dst_counter = 0; + int rc; + + OSMO_ASSERT(dst_maxlen >= 38); + + /* Bail if number of ROHC profiles exceeds limit + * (ROHC supports only a maximum of 16 different profiles) */ + OSMO_ASSERT(params->profile_len >= 0); + OSMO_ASSERT(params->profile_len <= 16); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode MAX_CID (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + OSMO_ASSERT(params->max_cid >= 0); + OSMO_ASSERT(params->max_cid <= 16383); + *dst = (params->max_cid >> 8) & 0xFF; + dst++; + *dst = params->max_cid & 0xFF; + dst++; + dst_counter += 2; + + /* Encode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + OSMO_ASSERT(params->max_header >= 60); + OSMO_ASSERT(params->max_header <= 255); + *dst = (params->max_header >> 8) & 0xFF; + dst++; + *dst = params->max_header & 0xFF; + dst++; + dst_counter += 2; + + /* Encode ROHC Profiles (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + for (i = 0; i < params->profile_len; i++) { + *dst = (params->profile[i] >> 8) & 0xFF; + dst++; + *dst = params->profile[i] & 0xFF; + dst++; + dst_counter += 2; + } + + /* Return generated length */ + return dst_counter; +} + +/* Encode V.42bis parameter field + * (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ +static int encode_dcomp_v42bis_params(uint8_t *dst, unsigned int dst_maxlen, + const struct + gprs_sndcp_dcomp_v42bis_params *params) +{ + /* NOTE: Buffer *dst should offer at least 6 bytes + * of space to store the generation results */ + + int dst_counter = 0; + int rc; + + OSMO_ASSERT(dst_maxlen >= 6); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode P0 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + OSMO_ASSERT(params->p0 >= 0); + OSMO_ASSERT(params->p0 <= 3); + *dst = params->p0 & 0x03; + dst++; + dst_counter++; + + /* Encode P1 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + OSMO_ASSERT(params->p1 >= 512); + OSMO_ASSERT(params->p1 <= 65535); + *dst = (params->p1 >> 8) & 0xFF; + dst++; + *dst = params->p1 & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P2 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + OSMO_ASSERT(params->p2 >= 6); + OSMO_ASSERT(params->p2 <= 250); + *dst = params->p2; + dst++; + dst_counter++; + + /* Return generated length */ + return dst_counter; +} + +/* Encode V44 parameter field + * (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ +static int encode_dcomp_v44_params(uint8_t *dst, unsigned int dst_maxlen, + const struct gprs_sndcp_dcomp_v44_params + *params) +{ + /* NOTE: Buffer *dst should offer at least 12 bytes + * of space to store the generation results */ + + int dst_counter = 0; + int rc; + + OSMO_ASSERT(dst_maxlen >= 12); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode applicable SAPIs */ + rc = encode_pcomp_applicable_sapis(dst, params->nsapi, + params->nsapi_len); + dst += rc; + dst_counter += rc; + + /* Encode C0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->c0 == 0x80 || params->c0 == 0xC0); + *dst = params->c0 & 0xC0; + dst++; + dst_counter++; + + /* Encode P0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p0 >= 0); + OSMO_ASSERT(params->p0 <= 3); + *dst = params->p0 & 0x03; + dst++; + dst_counter++; + + /* Encode P1T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p1t >= 256); + OSMO_ASSERT(params->p1t <= 65535); + *dst = (params->p1t >> 8) & 0xFF; + dst++; + *dst = params->p1t & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P1R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p1r >= 256); + OSMO_ASSERT(params->p1r <= 65535); + *dst = (params->p1r >> 8) & 0xFF; + dst++; + *dst = params->p1r & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P3T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p3t >= 0); + OSMO_ASSERT(params->p3t <= 65535); + OSMO_ASSERT(params->p3t >= 2 * params->p1t); + *dst = (params->p3t >> 8) & 0xFF; + dst++; + *dst = params->p3t & 0xFF; + dst++; + dst_counter += 2; + + /* Encode P3R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + OSMO_ASSERT(params->p3r >= 0); + OSMO_ASSERT(params->p3r <= 65535); + OSMO_ASSERT(params->p3r >= 2 * params->p1r); + *dst = (params->p3r >> 8) & 0xFF; + dst++; + *dst = params->p3r & 0xFF; + dst++; + dst_counter += 2; + + /* Return generated length */ + return dst_counter; +} + +/* Encode data or protocol control information compression field + * (see also: 3GPP TS 44.065, 6.6.1.1, Figure 9 and + * 3GPP TS 44.065, 6.5.1.1, Figure 7) */ +static int encode_comp_field(uint8_t *dst, unsigned int dst_maxlen, + const struct gprs_sndcp_comp_field *comp_field) +{ + int dst_counter = 0; + int len; + int expected_length; + int i; + + uint8_t payload_bytes[256]; + int payload_bytes_len = -1; + + /* If possible, try do encode payload bytes first */ + if (comp_field->rfc1144_params) { + payload_bytes_len = + encode_pcomp_rfc1144_params(payload_bytes, + sizeof(payload_bytes), + comp_field->rfc1144_params); + } else if (comp_field->rfc2507_params) { + payload_bytes_len = + encode_pcomp_rfc2507_params(payload_bytes, + sizeof(payload_bytes), + comp_field->rfc2507_params); + } else if (comp_field->rohc_params) { + payload_bytes_len = + encode_pcomp_rohc_params(payload_bytes, + sizeof(payload_bytes), + comp_field->rohc_params); + } else if (comp_field->v42bis_params) { + payload_bytes_len = + encode_dcomp_v42bis_params(payload_bytes, + sizeof(payload_bytes), + comp_field->v42bis_params); + } else if (comp_field->v44_params) { + payload_bytes_len = + encode_dcomp_v44_params(payload_bytes, + sizeof(payload_bytes), + comp_field->v44_params); + } else + OSMO_ASSERT(false); + + /* Bail immediately if payload byte generation failed */ + OSMO_ASSERT(payload_bytes_len >= 0); + + /* Bail if comp_len is out of bounds */ + OSMO_ASSERT(comp_field->comp_len <= sizeof(comp_field->comp)); + + /* Calculate length field of the data block */ + if (comp_field->p) { + len = + payload_bytes_len + + ceil((double)(comp_field->comp_len) / 2.0); + expected_length = len + 3; + } else { + len = payload_bytes_len; + expected_length = len + 2; + } + + /* Bail immediately if no sufficient memory space is supplied */ + OSMO_ASSERT(dst_maxlen >= expected_length); + + /* Check if the entity number is within bounds */ + OSMO_ASSERT(comp_field->entity <= 0x1f); + + /* Check if the algorithm number is within bounds */ + OSMO_ASSERT(comp_field->algo >= 0 || comp_field->algo <= 0x1f); + + /* Zero out buffer */ + memset(dst, 0, dst_maxlen); + + /* Encode Propose bit */ + if (comp_field->p) + *dst |= (1 << 7); + + /* Encode entity number */ + *dst |= comp_field->entity & 0x1F; + dst++; + dst_counter++; + + /* Encode algorithm number */ + if (comp_field->p) { + *dst |= comp_field->algo & 0x1F; + dst++; + dst_counter++; + } + + /* Encode length field */ + *dst |= len & 0xFF; + dst++; + dst_counter++; + + /* Encode PCOMP/DCOMP values */ + if (comp_field->p) { + for (i = 0; i < comp_field->comp_len; i++) { + /* Check if submitted PCOMP/DCOMP + values are within bounds */ + if ((comp_field->comp[i] < 0) + || (comp_field->comp[i] > 0x0F)) + return -EINVAL; + + if (i & 1) { + *dst |= comp_field->comp[i] & 0x0F; + dst++; + dst_counter++; + } else + *dst |= (comp_field->comp[i] << 4) & 0xF0; + } + + if (i & 1) { + dst++; + dst_counter++; + } + } + + /* Append payload bytes */ + memcpy(dst, payload_bytes, payload_bytes_len); + dst_counter += payload_bytes_len; + + /* Return generated length */ + return dst_counter; +} + +/* Find out to which compression class the specified comp-field belongs + * (header compression or data compression?) */ +int gprs_sndcp_get_compression_class(const struct gprs_sndcp_comp_field + *comp_field) +{ + OSMO_ASSERT(comp_field); + + if (comp_field->rfc1144_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->rfc2507_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->rohc_params) + return SNDCP_XID_PROTOCOL_COMPRESSION; + else if (comp_field->v42bis_params) + return SNDCP_XID_DATA_COMPRESSION; + else if (comp_field->v44_params) + return SNDCP_XID_DATA_COMPRESSION; + else + return -EINVAL; +} + +/* Convert all compression fields to bytstreams */ +static int gprs_sndcp_pack_fields(const struct llist_head *comp_fields, + uint8_t *dst, + unsigned int dst_maxlen, int class) +{ + struct gprs_sndcp_comp_field *comp_field; + int byte_counter = 0; + int rc; + + llist_for_each_entry_reverse(comp_field, comp_fields, list) { + if (class == gprs_sndcp_get_compression_class(comp_field)) { + rc = encode_comp_field(dst + byte_counter, + dst_maxlen - byte_counter, + comp_field); + + /* When input data is correct, there is + * no reason for the encoder to fail! */ + OSMO_ASSERT(rc >= 0); + + byte_counter += rc; + } + } + + /* Return generated length */ + return byte_counter; +} + +/* Transform a list with compression fields into an SNDCP-XID message (dst) */ +int gprs_sndcp_compile_xid(uint8_t *dst, unsigned int dst_maxlen, + const struct llist_head *comp_fields) +{ + int rc; + int byte_counter = 0; + uint8_t comp_bytes[512]; + uint8_t xid_version_number[1] = { CURRENT_SNDCP_VERSION }; + + OSMO_ASSERT(comp_fields); + OSMO_ASSERT(dst); + OSMO_ASSERT(dst_maxlen >= 2 + sizeof(xid_version_number)); + + /* Bail if there is no input */ + if (llist_empty(comp_fields)) + return -EINVAL; + + /* Prepend header */ + dst = + tlv_put(dst, SNDCP_XID_VERSION_NUMBER, + sizeof(xid_version_number), xid_version_number); + byte_counter += (sizeof(xid_version_number) + 2); + + /* Add data compression fields */ + rc = gprs_sndcp_pack_fields(comp_fields, comp_bytes, + sizeof(comp_bytes), + SNDCP_XID_DATA_COMPRESSION); + OSMO_ASSERT(rc >= 0); + + if (rc > 0) { + dst = tlv_put(dst, SNDCP_XID_DATA_COMPRESSION, rc, comp_bytes); + byte_counter += rc + 2; + } + + /* Add header compression fields */ + rc = gprs_sndcp_pack_fields(comp_fields, comp_bytes, + sizeof(comp_bytes), + SNDCP_XID_PROTOCOL_COMPRESSION); + OSMO_ASSERT(rc >= 0); + + if (rc > 0) { + dst = tlv_put(dst, SNDCP_XID_PROTOCOL_COMPRESSION, rc, + comp_bytes); + byte_counter += rc + 2; + } + + /* Return generated length */ + return byte_counter; +} + +/* FUNCTIONS RELATED TO SNDCP-XID DECODING */ + +/* Decode applicable sapis (works the same in all three compression schemes) */ +static int decode_pcomp_applicable_sapis(uint8_t *nsapis, + uint8_t *nsapis_len, + const uint8_t *src, + unsigned int src_len) +{ + uint16_t blob; + int i; + int nsapi_len = 0; + + /* Exit immediately if no result can be stored */ + if (!nsapis) + return -EINVAL; + + /* Exit immediately if not enough input data is available */ + if (src_len < 2) + return -EINVAL; + + /* Read bitmask */ + blob = *src; + blob = (blob << 8) & 0xFF00; + src++; + blob |= (*src) & 0xFF; + blob = (blob >> 5); + + /* Decode applicable SAPIs */ + for (i = 0; i < 15; i++) { + if ((blob >> i) & 1) { + nsapis[nsapi_len] = i + 5; + nsapi_len++; + } + } + + /* Return consumed length */ + *nsapis_len = nsapi_len; + return 2; +} + +/* Decode 16 bit field */ +static int decode_pcomp_16_bit_field(int *value_int, uint16_t * value_uint16, + const uint8_t *src, + unsigned int src_len, + int value_min, int value_max) +{ + uint16_t blob; + + /* Reset values to zero (just to be sure) */ + if (value_int) + *value_int = -1; + if (value_uint16) + *value_uint16 = 0; + + /* Exit if not enough src are available */ + if (src_len < 2) + return -EINVAL; + + /* Decode bit value */ + blob = *src; + blob = (blob << 8) & 0xFF00; + src++; + blob |= *src; + + /* Check if parsed value is within bounds */ + if (blob < value_min) + return -EINVAL; + if (blob > value_max) + return -EINVAL; + + /* Hand back results to the caller */ + if (value_int) + *value_int = blob; + if (value_uint16) + *value_uint16 = blob; + + /* Return consumed length */ + return 2; +} + +/* Decode 8 bit field */ +static int decode_pcomp_8_bit_field(int *value_int, uint8_t *value_uint8, + const uint8_t *src, + unsigned int src_len, + int value_min, int value_max) +{ + uint8_t blob; + + /* Reset values to invalid (just to be sure) */ + if (value_int) + *value_int = -1; + if (value_uint8) + *value_uint8 = 0; + + /* Exit if not enough src are available */ + if (src_len < 1) + return -EINVAL; + + /* Decode bit value */ + blob = *src; + + /* Check if parsed value is within bounds */ + if (blob < value_min) + return -EINVAL; + if (blob > value_max) + return -EINVAL; + + /* Hand back results to the caller */ + if (value_int) + *value_int = blob; + if (value_uint8) + *value_uint8 = blob; + + /* Return consumed length */ + return 1; +} + +/* Decode rfc1144 parameter field see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */ +static int decode_pcomp_rfc1144_params(struct gprs_sndcp_pcomp_rfc1144_params + *params, const uint8_t *src, + unsigned int src_len) +{ + int rc; + int byte_counter = 0; + + /* Mark all optional parameters invalid by default */ + params->s01 = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode parameter S0 -1 + * (see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */ + rc = decode_pcomp_8_bit_field(¶ms->s01, NULL, src, + src_len - byte_counter, 0, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Decode rfc2507 parameter field + * (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ +static int decode_pcomp_rfc2507_params(struct gprs_sndcp_pcomp_rfc2507_params + *params, const uint8_t *src, + unsigned int src_len) +{ + int rc; + int byte_counter = 0; + + /* Mark all optional parameters invalid by default */ + params->f_max_period = -1; + params->f_max_time = -1; + params->max_header = -1; + params->tcp_space = -1; + params->non_tcp_space = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode F_MAX_PERIOD (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_16_bit_field(¶ms->f_max_period, NULL, src, + src_len - byte_counter, 1, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode F_MAX_TIME (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_8_bit_field(¶ms->f_max_time, NULL, src, + src_len - byte_counter, 1, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_8_bit_field(¶ms->max_header, NULL, src, + src_len - byte_counter, 60, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_8_bit_field(¶ms->tcp_space, NULL, src, + src_len - byte_counter, 3, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode NON_TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */ + rc = decode_pcomp_16_bit_field(¶ms->non_tcp_space, NULL, src, + src_len - byte_counter, 3, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Decode ROHC parameter field (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ +static int decode_pcomp_rohc_params(struct gprs_sndcp_pcomp_rohc_params *params, + const uint8_t *src, unsigned int src_len) +{ + int rc; + int byte_counter = 0; + int i; + + /* Mark all optional parameters invalid by default */ + params->max_cid = -1; + params->max_header = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_CID (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + rc = decode_pcomp_16_bit_field(¶ms->max_cid, NULL, src, + src_len - byte_counter, 0, 16383); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + rc = decode_pcomp_16_bit_field(¶ms->max_header, NULL, src, + src_len - byte_counter, 60, 255); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode Profiles (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */ + for (i = 0; i < 16; i++) { + params->profile_len = 0; + rc = decode_pcomp_16_bit_field(NULL, ¶ms->profile[i], src, + src_len - byte_counter, 0, + 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + params->profile_len = i + 1; + } + + /* Return consumed length */ + return byte_counter; +} + +/* Decode V.42bis parameter field + * (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ +static int decode_dcomp_v42bis_params(struct gprs_sndcp_dcomp_v42bis_params + *params, const uint8_t *src, + unsigned int src_len) +{ + int rc; + int byte_counter = 0; + + /* Mark all optional parameters invalid by default */ + params->p0 = -1; + params->p1 = -1; + params->p2 = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode P0 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + rc = decode_pcomp_8_bit_field(¶ms->p0, NULL, src, + src_len - byte_counter, 0, 3); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + rc = decode_pcomp_16_bit_field(¶ms->p1, NULL, src, + src_len - byte_counter, 512, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P2 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ + rc = decode_pcomp_8_bit_field(¶ms->p2, NULL, src, + src_len - byte_counter, 6, 250); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Decode V44 parameter field (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ +static int decode_dcomp_v44_params(struct gprs_sndcp_dcomp_v44_params *params, + const uint8_t *src, unsigned int src_len) +{ + int rc; + int byte_counter = 0; + + /* Mark all optional parameters invalid by default */ + params->c0 = -1; + params->p0 = -1; + params->p1t = -1; + params->p1r = -1; + params->p3t = -1; + params->p3r = -1; + + /* Decode applicable SAPIs */ + rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, + src, src_len); + if (rc > 0) { + byte_counter += rc; + src += rc; + } else + return byte_counter; + + /* Decode C0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_8_bit_field(¶ms->c0, NULL, src, + src_len - byte_counter, 0, 255); + if (rc <= 0) + return byte_counter; + if ((params->c0 != 0x80) && (params->c0 != 0xC0)) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Decode P0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_8_bit_field(¶ms->p0, NULL, src, + src_len - byte_counter, 0, 3); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_16_bit_field(¶ms->p1t, NULL, src, + src_len - byte_counter, 265, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P1R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_16_bit_field(¶ms->p1r, NULL, src, + src_len - byte_counter, 265, 65535); + if (rc <= 0) + return byte_counter; + byte_counter += rc; + src += rc; + + /* Decode P3T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_16_bit_field(¶ms->p3t, NULL, src, + src_len - byte_counter, 265, 65535); + if (rc <= 0) + return byte_counter; + if (params->p3t < 2 * params->p1t) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Decode P3R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ + rc = decode_pcomp_16_bit_field(¶ms->p3r, NULL, src, + src_len - byte_counter, 265, 65535); + if (rc <= 0) + return byte_counter; + if (params->p3r < 2 * params->p1r) + return -EINVAL; + byte_counter += rc; + src += rc; + + /* Return consumed length */ + return byte_counter; +} + +/* Lookup algorithm identfier by entity ID */ +static int lookup_algorithm_identifier(int entity, const struct + entity_algo_table + *lt, unsigned int lt_len, int compclass) +{ + int i; + + if (!lt) + return -1; + + for (i = 0; i < lt_len; i++) { + if ((lt[i].entity == entity) + && (lt[i].compclass == compclass)) + return lt[i].algo; + } + + return -1; +} + +/* Helper function for decode_comp_field(), decodes + * numeric pcomp/dcomp values */ +static int decode_comp_values(struct gprs_sndcp_comp_field *comp_field, + const uint8_t *src, int compclass) +{ + int src_counter = 0; + int i; + + if (comp_field->p) { + /* Determine the number of expected PCOMP/DCOMP values */ + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + /* For protocol compression */ + switch (comp_field->algo) { + case RFC_1144: + comp_field->comp_len = RFC1144_PCOMP_NUM; + break; + case RFC_2507: + comp_field->comp_len = RFC2507_PCOMP_NUM; + break; + case ROHC: + comp_field->comp_len = ROHC_PCOMP_NUM; + break; + + /* Exit if the algorithem type encodes + something unknown / unspecified */ + default: + return -EINVAL; + } + } else { + /* For data compression */ + switch (comp_field->algo) { + case V42BIS: + comp_field->comp_len = V42BIS_DCOMP_NUM; + break; + case V44: + comp_field->comp_len = V44_DCOMP_NUM; + break; + + /* Exit if the algorithem type encodes + something unknown / unspecified */ + default: + return -EINVAL; + } + } + + for (i = 0; i < comp_field->comp_len; i++) { + if (i & 1) { + comp_field->comp[i] = (*src) & 0x0F; + src++; + src_counter++; + } else + comp_field->comp[i] = ((*src) >> 4) & 0x0F; + } + + if (i & 1) { + src++; + src_counter++; + } + } + + return src_counter; +} + +/* Helper function for decode_comp_field(), decodes the parameters + * which are protocol compression specific */ +static int decode_pcomp_params(struct gprs_sndcp_comp_field *comp_field, + const uint8_t *src, int src_len) +{ + int rc; + + switch (comp_field->algo) { + case RFC_1144: + comp_field->rfc1144_params = talloc_zero(comp_field, struct + gprs_sndcp_pcomp_rfc1144_params); + rc = decode_pcomp_rfc1144_params(comp_field->rfc1144_params, + src, src_len); + if (rc < 0) + talloc_free(comp_field->rfc1144_params); + break; + case RFC_2507: + comp_field->rfc2507_params = talloc_zero(comp_field, struct + gprs_sndcp_pcomp_rfc2507_params); + rc = decode_pcomp_rfc2507_params(comp_field->rfc2507_params, + src, src_len); + if (rc < 0) + talloc_free(comp_field->rfc1144_params); + break; + case ROHC: + comp_field->rohc_params = talloc_zero(comp_field, struct + gprs_sndcp_pcomp_rohc_params); + rc = decode_pcomp_rohc_params(comp_field->rohc_params, src, + src_len); + if (rc < 0) + talloc_free(comp_field->rohc_params); + break; + + /* If no suitable decoder is detected, + leave the remaining bytes undecoded */ + default: + rc = src_len; + } + + if (rc < 0) { + comp_field->rfc1144_params = NULL; + comp_field->rfc2507_params = NULL; + comp_field->rohc_params = NULL; + } + + return rc; +} + +/* Helper function for decode_comp_field(), decodes the parameters + * which are data compression specific */ +static int decode_dcomp_params(struct gprs_sndcp_comp_field *comp_field, + const uint8_t *src, int src_len) +{ + int rc; + + switch (comp_field->algo) { + case V42BIS: + comp_field->v42bis_params = talloc_zero(comp_field, struct + gprs_sndcp_dcomp_v42bis_params); + rc = decode_dcomp_v42bis_params(comp_field->v42bis_params, src, + src_len); + if (rc < 0) + talloc_free(comp_field->v42bis_params); + break; + case V44: + comp_field->v44_params = talloc_zero(comp_field, struct + gprs_sndcp_dcomp_v44_params); + rc = decode_dcomp_v44_params(comp_field->v44_params, src, + src_len); + if (rc < 0) + talloc_free(comp_field->v44_params); + break; + + /* If no suitable decoder is detected, + * leave the remaining bytes undecoded */ + default: + rc = src_len; + } + + if (rc < 0) { + comp_field->v42bis_params = NULL; + comp_field->v44_params = NULL; + } + + return rc; +} + +/* Decode data or protocol control information compression field + * (see also: 3GPP TS 44.065, 6.6.1.1, Figure 9 and + * 3GPP TS 44.065, 6.5.1.1, Figure 7) */ +static int decode_comp_field(struct gprs_sndcp_comp_field *comp_field, + const uint8_t *src, unsigned int src_len, + const struct entity_algo_table *lt, + unsigned int lt_len, int compclass) +{ + int src_counter = 0; + unsigned int len; + int rc; + + OSMO_ASSERT(comp_field); + + /* Exit immediately if it is clear that no + parseable data is present */ + if (src_len < 1 || !src) + return -EINVAL; + + /* Zero out target struct */ + memset(comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + + /* Decode Propose bit and Entity number */ + if ((*src) & 0x80) + comp_field->p = 1; + comp_field->entity = (*src) & 0x1F; + src_counter++; + src++; + + /* Decode algorithm number (if present) */ + if (comp_field->p) { + comp_field->algo = (*src) & 0x1F; + src_counter++; + src++; + } + /* Alternatively take the information from the lookup table */ + else + comp_field->algo = + lookup_algorithm_identifier(comp_field->entity, lt, + lt_len, compclass); + + /* Decode length field */ + len = *src; + src_counter++; + src++; + + /* Decode PCOMP/DCOMP values */ + rc = decode_comp_values(comp_field, src, compclass); + if (rc < 0) + return -EINVAL; + src_counter += rc; + src += rc; + len -= rc; + + /* Decode algorithm specific payload data */ + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + rc = decode_pcomp_params(comp_field, src, len); + else if (compclass == SNDCP_XID_DATA_COMPRESSION) + rc = decode_dcomp_params(comp_field, src, len); + else + return -EINVAL; + + if (rc >= 0) + src_counter += rc; + else + return -EINVAL; + + /* Return consumed length */ + return src_counter; +} + +/* Helper function for gprs_sndcp_decode_xid() to decode XID blocks */ +static int decode_xid_block(struct llist_head *comp_fields, uint8_t tag, + uint16_t tag_len, const uint8_t *val, + const struct entity_algo_table *lt, + unsigned int lt_len) +{ + struct gprs_sndcp_comp_field *comp_field; + int byte_counter = 0; + int comp_field_count = 0; + int rc; + + byte_counter = 0; + do { + /* Bail if more than the maximum number of + comp_fields is generated */ + if (comp_field_count > MAX_ENTITIES * 2) { + return -EINVAL; + } + + /* Parse and add comp_field */ + comp_field = + talloc_zero(comp_fields, struct gprs_sndcp_comp_field); + + rc = decode_comp_field(comp_field, val + byte_counter, + tag_len - byte_counter, lt, lt_len, tag); + + if (rc < 0) { + talloc_free(comp_field); + return -EINVAL; + } + + byte_counter += rc; + llist_add(&comp_field->list, comp_fields); + comp_field_count++; + } + while (tag_len - byte_counter > 0); + + return byte_counter; +} + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +static int gprs_sndcp_decode_xid(struct llist_head *comp_fields, + const uint8_t *src, unsigned int src_len, + const struct + entity_algo_table + *lt, unsigned int lt_len) +{ + int src_pos = 0; + uint8_t tag; + uint16_t tag_len; + const uint8_t *val; + int byte_counter = 0; + int rc; + int tlv_count = 0; + + /* Valid TLV-Tag and types */ + static const struct tlv_definition sndcp_xid_def = { + .def = { + [SNDCP_XID_VERSION_NUMBER] = {TLV_TYPE_TLV,}, + [SNDCP_XID_DATA_COMPRESSION] = {TLV_TYPE_TLV,}, + [SNDCP_XID_PROTOCOL_COMPRESSION] = {TLV_TYPE_TLV,}, + }, + }; + + /* Parse TLV-Encoded SNDCP-XID message and defer payload + to the apporpiate sub-parser functions */ + while (1) { + + /* Bail if an the maximum number of TLV fields + * have been parsed */ + if (tlv_count >= 3) { + talloc_free(comp_fields); + return -EINVAL; + } + + /* Parse TLV field */ + rc = tlv_parse_one(&tag, &tag_len, &val, &sndcp_xid_def, + src + src_pos, src_len - src_pos); + if (rc > 0) + src_pos += rc; + else { + talloc_free(comp_fields); + return -EINVAL; + } + + /* Decode compression parameters */ + if ((tag == SNDCP_XID_PROTOCOL_COMPRESSION) + || (tag == SNDCP_XID_DATA_COMPRESSION)) { + rc = decode_xid_block(comp_fields, tag, tag_len, val, + lt, lt_len); + + if (rc < 0) { + talloc_free(comp_fields); + return -EINVAL; + } else + byte_counter += rc; + } + + /* Stop when no further TLV elements can be expected */ + if (src_len - src_pos <= 2) + break; + + tlv_count++; + } + + return 0; +} + +/* Fill up lookutable from a list with comression entitiy fields */ +static int gprs_sndcp_fill_table(struct + entity_algo_table *lt, + unsigned int lt_len, + const struct llist_head *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field; + int i = 0; + + if (!comp_fields) + return -EINVAL; + if (!lt) + return -EINVAL; + + memset(lt, 0, lt_len * sizeof(lt)); + + llist_for_each_entry(comp_field, comp_fields, list) { + + lt[i].entity = comp_field->entity; + lt[i].algo = comp_field->algo; + lt[i].compclass = gprs_sndcp_get_compression_class(comp_field); + + if (lt[i].compclass < 0) { + memset(lt, 0, lt_len * sizeof(lt)); + return -EINVAL; + } + + i++; + } + + return i; +} + +/* Complete comp field params + * (if a param (dst) is not valid, it will be copied from source (src) */ +static int complete_comp_field_params(struct gprs_sndcp_comp_field + *comp_field_dst, const struct + gprs_sndcp_comp_field *comp_field_src) +{ + if (comp_field_dst->algo < 0) + return -EINVAL; + + if (comp_field_dst->rfc1144_params && comp_field_src->rfc1144_params) { + if (comp_field_dst->rfc1144_params->s01 < 0) { + comp_field_dst->rfc1144_params->s01 = + comp_field_src->rfc1144_params->s01; + } + return 0; + } + + if (comp_field_dst->rfc2507_params && comp_field_src->rfc2507_params) { + + if (comp_field_dst->rfc2507_params->f_max_period < 0) { + comp_field_dst->rfc2507_params->f_max_period = + comp_field_src->rfc2507_params->f_max_period; + } + if (comp_field_dst->rfc2507_params->f_max_time < 0) { + comp_field_dst->rfc2507_params->f_max_time = + comp_field_src->rfc2507_params->f_max_time; + } + if (comp_field_dst->rfc2507_params->max_header < 0) { + comp_field_dst->rfc2507_params->max_header = + comp_field_src->rfc2507_params->max_header; + } + if (comp_field_dst->rfc2507_params->tcp_space < 0) { + comp_field_dst->rfc2507_params->tcp_space = + comp_field_src->rfc2507_params->tcp_space; + } + if (comp_field_dst->rfc2507_params->non_tcp_space < 0) { + comp_field_dst->rfc2507_params->non_tcp_space = + comp_field_src->rfc2507_params->non_tcp_space; + } + return 0; + } + + if (comp_field_dst->rohc_params && comp_field_src->rohc_params) { + if (comp_field_dst->rohc_params->max_cid < 0) { + comp_field_dst->rohc_params->max_cid = + comp_field_src->rohc_params->max_cid; + } + if (comp_field_dst->rohc_params->max_header < 0) { + comp_field_dst->rohc_params->max_header = + comp_field_src->rohc_params->max_header; + } + if (comp_field_dst->rohc_params->profile_len > 0) { + memcpy(comp_field_dst->rohc_params->profile, + comp_field_src->rohc_params->profile, + sizeof(comp_field_dst->rohc_params->profile)); + comp_field_dst->rohc_params->profile_len = + comp_field_src->rohc_params->profile_len; + } + + return 0; + } + + if (comp_field_dst->v42bis_params && comp_field_src->v42bis_params) { + if (comp_field_dst->v42bis_params->p0 < 0) { + comp_field_dst->v42bis_params->p0 = + comp_field_src->v42bis_params->p0; + } + if (comp_field_dst->v42bis_params->p1 < 0) { + comp_field_dst->v42bis_params->p1 = + comp_field_src->v42bis_params->p1; + } + if (comp_field_dst->v42bis_params->p2 < 0) { + comp_field_dst->v42bis_params->p2 = + comp_field_src->v42bis_params->p2; + } + return 0; + } + + if (comp_field_dst->v44_params && comp_field_src->v44_params) { + if (comp_field_dst->v44_params->c0 < 0) { + comp_field_dst->v44_params->c0 = + comp_field_src->v44_params->c0; + } + if (comp_field_dst->v44_params->p0 < 0) { + comp_field_dst->v44_params->p0 = + comp_field_src->v44_params->p0; + } + if (comp_field_dst->v44_params->p1t < 0) { + comp_field_dst->v44_params->p1t = + comp_field_src->v44_params->p1t; + } + if (comp_field_dst->v44_params->p1r < 0) { + comp_field_dst->v44_params->p1r = + comp_field_src->v44_params->p1r; + } + if (comp_field_dst->v44_params->p3t < 0) { + comp_field_dst->v44_params->p3t = + comp_field_src->v44_params->p3t; + } + if (comp_field_dst->v44_params->p3r < 0) { + comp_field_dst->v44_params->p3r = + comp_field_src->v44_params->p3r; + } + return 0; + } + + /* There should be at least exist one param set + * in the destination struct, otherwise something + * must be wrong! */ + return -EINVAL; +} + +/* Complete missing parameters in a comp_field */ +static int gprs_sndcp_complete_comp_field(struct gprs_sndcp_comp_field + *comp_field, const struct llist_head + *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field_src; + int rc = 0; + + llist_for_each_entry(comp_field_src, comp_fields, list) { + if (comp_field_src->entity == comp_field->entity) { + + /* Complete header fields */ + if (comp_field_src->comp_len > 0) { + memcpy(comp_field->comp, + comp_field_src->comp, + sizeof(comp_field_src->comp)); + comp_field->comp_len = comp_field_src->comp_len; + } + + /* Complete parameter fields */ + rc = complete_comp_field_params(comp_field, + comp_field_src); + } + } + + return rc; +} + +/* Complete missing parameters of all comp_field in a list */ +static int gprs_sndcp_complete_comp_fields(struct llist_head + *comp_fields_incomplete, + const struct llist_head *comp_fields) +{ + struct gprs_sndcp_comp_field *comp_field_incomplete; + int rc; + + llist_for_each_entry(comp_field_incomplete, comp_fields_incomplete, + list) { + + rc = gprs_sndcp_complete_comp_field(comp_field_incomplete, + comp_fields); + if (rc < 0) + return -EINVAL; + + } + + return 0; +} + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +struct llist_head *gprs_sndcp_parse_xid(const void *ctx, + const uint8_t *src, + unsigned int src_len, + const struct llist_head + *comp_fields_req) +{ + int rc; + int lt_len; + struct llist_head *comp_fields; + struct entity_algo_table lt[MAX_ENTITIES * 2]; + + OSMO_ASSERT(src); + + comp_fields = talloc_zero(ctx, struct llist_head); + INIT_LLIST_HEAD(comp_fields); + + if (comp_fields_req) { + /* Generate lookup table */ + lt_len = + gprs_sndcp_fill_table(lt, MAX_ENTITIES * 2, + comp_fields_req); + if (lt_len < 0) { + talloc_free(comp_fields); + return NULL; + } + + /* Parse SNDCP-CID XID-Field */ + rc = gprs_sndcp_decode_xid(comp_fields, src, src_len, lt, + lt_len); + if (rc < 0) { + talloc_free(comp_fields); + return NULL; + } + + rc = gprs_sndcp_complete_comp_fields(comp_fields, + comp_fields_req); + if (rc < 0) { + talloc_free(comp_fields); + return NULL; + } + + } else { + /* Parse SNDCP-CID XID-Field */ + rc = gprs_sndcp_decode_xid(comp_fields, src, src_len, NULL, 0); + if (rc < 0) { + talloc_free(comp_fields); + return NULL; + } + } + + return comp_fields; +} + +/* Helper for gprs_sndcp_dump_comp_fields(), + * dumps protocol compression parameters */ +static void dump_pcomp_params(const struct gprs_sndcp_comp_field + *comp_field, unsigned int logl) +{ + int i; + + switch (comp_field->algo) { + case RFC_1144: + if (comp_field->rfc1144_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_pcomp_rfc1144_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_pcomp_rfc1144_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%d;\n", + comp_field->rfc1144_params->nsapi_len); + if (comp_field->rfc1144_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rfc1144_params->nsapi_len; i++) { + LOGP(DSNDCP, logl, + " nsapi[%d]=%d;\n", i, + comp_field->rfc1144_params->nsapi[i]); + } + LOGP(DSNDCP, logl, " s01=%d;\n", + comp_field->rfc1144_params->s01); + LOGP(DSNDCP, logl, " }\n"); + break; + case RFC_2507: + if (comp_field->rfc2507_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_pcomp_rfc2507_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_pcomp_rfc2507_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%d;\n", + comp_field->rfc2507_params->nsapi_len); + if (comp_field->rfc2507_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rfc2507_params->nsapi_len; i++) { + LOGP(DSNDCP, logl, + " nsapi[%d]=%d;\n", i, + comp_field->rfc2507_params->nsapi[i]); + } + LOGP(DSNDCP, logl, + " f_max_period=%d;\n", + comp_field->rfc2507_params->f_max_period); + LOGP(DSNDCP, logl, + " f_max_time=%d;\n", + comp_field->rfc2507_params->f_max_time); + LOGP(DSNDCP, logl, + " max_header=%d;\n", + comp_field->rfc2507_params->max_header); + LOGP(DSNDCP, logl, + " tcp_space=%d;\n", + comp_field->rfc2507_params->tcp_space); + LOGP(DSNDCP, logl, + " non_tcp_space=%d;\n", + comp_field->rfc2507_params->non_tcp_space); + LOGP(DSNDCP, logl, " }\n"); + break; + case ROHC: + if (comp_field->rohc_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_pcomp_rohc_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_pcomp_rohc_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%d;\n", + comp_field->rohc_params->nsapi_len); + if (comp_field->rohc_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->rohc_params->nsapi_len; i++) { + LOGP(DSNDCP, logl, + " nsapi[%d]=%d;\n", i, + comp_field->rohc_params->nsapi[i]); + } + LOGP(DSNDCP, logl, + " max_cid=%d;\n", comp_field->rohc_params->max_cid); + LOGP(DSNDCP, logl, + " max_header=%d;\n", + comp_field->rohc_params->max_header); + LOGP(DSNDCP, logl, + " profile_len=%d;\n", + comp_field->rohc_params->profile_len); + if (comp_field->rohc_params->profile_len == 0) + LOGP(DSNDCP, logl, " profile[] = NULL;\n"); + for (i = 0; i < comp_field->rohc_params->profile_len; i++) + LOGP(DSNDCP, logl, + " profile[%d]=%04x;\n", + i, comp_field->rohc_params->profile[i]); + LOGP(DSNDCP, logl, " }\n"); + break; + } + +} + +/* Helper for gprs_sndcp_dump_comp_fields(), + * data protocol compression parameters */ +static void dump_dcomp_params(const struct gprs_sndcp_comp_field + *comp_field, unsigned int logl) +{ + int i; + + switch (comp_field->algo) { + case V42BIS: + if (comp_field->v42bis_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_dcomp_v42bis_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_dcomp_v42bis_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%d;\n", + comp_field->v42bis_params->nsapi_len); + if (comp_field->v42bis_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->v42bis_params->nsapi_len; i++) + LOGP(DSNDCP, logl, + " nsapi[%d]=%d;\n", i, + comp_field->v42bis_params->nsapi[i]); + LOGP(DSNDCP, logl, " p0=%d;\n", + comp_field->v42bis_params->p0); + LOGP(DSNDCP, logl, " p1=%d;\n", + comp_field->v42bis_params->p1); + LOGP(DSNDCP, logl, " p2=%d;\n", + comp_field->v42bis_params->p2); + LOGP(DSNDCP, logl, " }\n"); + break; + case V44: + if (comp_field->v44_params == NULL) { + LOGP(DSNDCP, logl, + " gprs_sndcp_dcomp_v44_params=NULL\n"); + break; + } + LOGP(DSNDCP, logl, " gprs_sndcp_dcomp_v44_params {\n"); + LOGP(DSNDCP, logl, + " nsapi_len=%d;\n", + comp_field->v44_params->nsapi_len); + if (comp_field->v44_params->nsapi_len == 0) + LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); + for (i = 0; i < comp_field->v44_params->nsapi_len; i++) { + LOGP(DSNDCP, logl, + " nsapi[%d]=%d;\n", i, + comp_field->v44_params->nsapi[i]); + } + LOGP(DSNDCP, logl, " c0=%d;\n", + comp_field->v44_params->c0); + LOGP(DSNDCP, logl, " p0=%d;\n", + comp_field->v44_params->p0); + LOGP(DSNDCP, logl, " p1t=%d;\n", + comp_field->v44_params->p1t); + LOGP(DSNDCP, logl, " p1r=%d;\n", + comp_field->v44_params->p1r); + LOGP(DSNDCP, logl, " p3t=%d;\n", + comp_field->v44_params->p3t); + LOGP(DSNDCP, logl, " p3r=%d;\n", + comp_field->v44_params->p3r); + LOGP(DSNDCP, logl, " }\n"); + break; + } +} + +/* Dump a list with SNDCP-XID fields (Debug) */ +void gprs_sndcp_dump_comp_fields(const struct llist_head *comp_fields, + unsigned int logl) +{ + struct gprs_sndcp_comp_field *comp_field; + int i; + int compclass; + + OSMO_ASSERT(comp_fields); + + llist_for_each_entry(comp_field, comp_fields, list) { + LOGP(DSNDCP, logl, "SNDCP-XID:\n"); + LOGP(DSNDCP, logl, "struct gprs_sndcp_comp_field {\n"); + LOGP(DSNDCP, logl, " entity=%d;\n", comp_field->entity); + LOGP(DSNDCP, logl, " algo=%d;\n", comp_field->algo); + LOGP(DSNDCP, logl, " comp_len=%d;\n", comp_field->comp_len); + if (comp_field->comp_len == 0) + LOGP(DSNDCP, logl, " comp[] = NULL;\n"); + for (i = 0; i < comp_field->comp_len; i++) { + LOGP(DSNDCP, logl, " comp[%d]=%d;\n", i, + comp_field->comp[i]); + } + + compclass = gprs_sndcp_get_compression_class(comp_field); + + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + dump_pcomp_params(comp_field, logl); + } else if (compclass == SNDCP_XID_DATA_COMPRESSION) { + dump_dcomp_params(comp_field, logl); + } + + LOGP(DSNDCP, logl, "}\n"); + } + +} diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index ba5ca28..1debb2d 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 74af159..45d1780 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -31,6 +31,7 @@ $(top_builddir)/src/gprs/oap.o \ $(top_builddir)/src/gprs/oap_messages.o \ $(top_builddir)/src/gprs/gprs_llc_xid.o \ + $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ @@ -38,5 +39,5 @@ $(LIBOSMOGB_LIBS) \ $(LIBCARES_LIBS) \ $(LIBCRYPTO_LIBS) \ - -lgtp -lrt + -lgtp -lrt -lm diff --git a/openbsc/tests/sndcp_xid/Makefile.am b/openbsc/tests/sndcp_xid/Makefile.am new file mode 100644 index 0000000..99b9d1a --- /dev/null +++ b/openbsc/tests/sndcp_xid/Makefile.am @@ -0,0 +1,20 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) + +EXTRA_DIST = sndcp_xid_test.ok + +noinst_PROGRAMS = sndcp_xid_test + +sndcp_xid_test_SOURCES = sndcp_xid_test.c + +sndcp_xid_test_LDADD = \ + $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOGB_LIBS) \ + $(LIBCARES_LIBS) \ + $(LIBCRYPTO_LIBS) \ + -lgtp -lrt -lm + + diff --git a/openbsc/tests/sndcp_xid/sndcp_xid_test.c b/openbsc/tests/sndcp_xid/sndcp_xid_test.c new file mode 100644 index 0000000..3a33619 --- /dev/null +++ b/openbsc/tests/sndcp_xid/sndcp_xid_test.c @@ -0,0 +1,282 @@ +/* Test SNDCP-XID Encoding/Decoding */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include +#include + +#include + +#include +#include + +/* Test SNDCP-XID decoding with a real world sample */ +static void test_xid_decode_realworld(const void *ctx) +{ + struct llist_head *comp_fields; + int rc; + printf("Testing SNDCP XID-Decoder/Encoder (real world data)\n"); + + /* Example of a real world SNDCP-XID message */ + uint8_t xid[] = + { 0x00, 0x01, 0x00, 0x02, 0x31, 0x82, 0x02, 0x27, 0x89, 0xff, 0xe0, + 0x00, 0x0f, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, + 0x01, 0x02, 0x00, 0x03, 0x01, 0x03, 0x00, 0x04, 0x01, 0x04, 0x00, 0x05, + 0x01, 0x05, 0x00, 0x06, 0x00, 0x07, 0x01, 0x07, 0x00, 0x08, 0x01, 0x08, + 0x80, 0x00, 0x04, 0x12, 0x00, 0x40, 0x07 }; + uint8_t xid_r[512]; + + /* Parse and show contained comp fields */ + comp_fields = gprs_sndcp_parse_xid(ctx, xid, sizeof(xid), NULL); + OSMO_ASSERT(comp_fields); + printf("Decoded:\n"); + gprs_sndcp_dump_comp_fields(comp_fields, DSNDCP); + + /* Encode comp-fields again */ + rc = gprs_sndcp_compile_xid(xid_r,sizeof(xid_r), comp_fields); + printf("Result length=%i\n",rc); + printf("Encoded: %s\n", osmo_hexdump_nospc(xid, sizeof(xid))); + printf("Rencoded: %s\n", osmo_hexdump_nospc(xid_r, rc)); + + OSMO_ASSERT(rc == 54); + OSMO_ASSERT(memcmp(xid, xid_r, sizeof(xid)) == 0); + + /* Free comp fields */ + talloc_free(comp_fields); + + printf("\n"); +} + +/* Encode and decode test with artificial test data */ +static void test_xid_encode_decode(const void *ctx) +{ + printf("Testing SNDCP XID-Encoder/Decoder\n"); + + LLIST_HEAD(comp_fields); + struct gprs_sndcp_pcomp_rfc1144_params rfc1144_params; + struct gprs_sndcp_comp_field rfc1144_comp_field; + struct gprs_sndcp_pcomp_rfc2507_params rfc2507_params; + struct gprs_sndcp_comp_field rfc2507_comp_field; + struct gprs_sndcp_pcomp_rohc_params rohc_params; + struct gprs_sndcp_comp_field rohc_comp_field; + struct gprs_sndcp_dcomp_v42bis_params v42bis_params; + struct gprs_sndcp_comp_field v42bis_comp_field; + struct gprs_sndcp_dcomp_v44_params v44_params; + struct gprs_sndcp_comp_field v44_comp_field; + struct llist_head *comp_fields_dec; + + uint8_t xid[512]; + unsigned int xid_len = sizeof(xid); + int rc; + + memset(&rfc1144_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + memset(&rfc2507_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + memset(&rohc_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + memset(&v42bis_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + memset(&v44_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + + /* Setup which NSAPIs shall make use of rfc1144 */ + rfc1144_params.nsapi[0] = 5; + rfc1144_params.nsapi_len = 1; + + /* Setup rfc1144 operating parameters */ + rfc1144_params.s01 = 7; + + /* Setup rfc1144 compression field */ + rfc1144_comp_field.p = 1; + rfc1144_comp_field.entity = 0; + rfc1144_comp_field.algo = RFC_1144; + rfc1144_comp_field.comp[RFC1144_PCOMP1] = 1; + rfc1144_comp_field.comp[RFC1144_PCOMP2] = 2; + rfc1144_comp_field.comp_len = RFC1144_PCOMP_NUM; + rfc1144_comp_field.rfc1144_params = &rfc1144_params; + + /* Setup which NSAPIs shall make use of rfc1144 */ + rfc2507_params.nsapi[0] = 6; + rfc2507_params.nsapi_len = 1; + + /* Setup rfc2507 operating parameters */ + rfc2507_params.f_max_period = 256; + rfc2507_params.f_max_time = 5; + rfc2507_params.max_header = 168; + rfc2507_params.tcp_space = 15; + rfc2507_params.non_tcp_space = 15; + + /* Setup rfc2507 compression field */ + rfc2507_comp_field.p = 1; + rfc2507_comp_field.entity = 1; + rfc2507_comp_field.algo = RFC_2507; + rfc2507_comp_field.comp[RFC2507_PCOMP1] = 3; + rfc2507_comp_field.comp[RFC2507_PCOMP2] = 4; + rfc2507_comp_field.comp[RFC2507_PCOMP3] = 5; + rfc2507_comp_field.comp[RFC2507_PCOMP4] = 6; + rfc2507_comp_field.comp[RFC2507_PCOMP5] = 7; + rfc2507_comp_field.comp_len = RFC2507_PCOMP_NUM; + rfc2507_comp_field.rfc2507_params = &rfc2507_params; + + /* Setup which NSAPIs shall make use of ROHC */ + rohc_params.nsapi[0] = 5; + rohc_params.nsapi[1] = 6; + rohc_params.nsapi[2] = 7; + rohc_params.nsapi[3] = 8; + rohc_params.nsapi[4] = 9; + rohc_params.nsapi[5] = 10; + rohc_params.nsapi[6] = 11; + rohc_params.nsapi[7] = 12; + rohc_params.nsapi[8] = 13; + rohc_params.nsapi[9] = 14; + rohc_params.nsapi[10] = 15; + rohc_params.nsapi_len = 11; + + /* Setup ROHC operating parameters */ + rohc_params.max_cid = 15; /* default */ + rohc_params.max_header = 168; /* default */ + rohc_params.profile[0] = ROHC_UNCOMPRESSED; + rohc_params.profile[1] = ROHC_RTP; + rohc_params.profile[2] = ROHCV2_RTP; + rohc_params.profile[3] = ROHC_UDP; + rohc_params.profile[4] = ROHCv2_UDP; + rohc_params.profile[5] = ROHC_ESP; + rohc_params.profile[6] = ROHCV2_ESP; + rohc_params.profile[7] = ROHC_IP; + rohc_params.profile[8] = ROHCV2_IP; + rohc_params.profile[9] = ROHC_LLA; + rohc_params.profile[10] = ROHC_LLA_WITH_R_MODE; + rohc_params.profile[11] = ROHC_TCP; + rohc_params.profile[12] = ROHC_RTP_UDP_LITE; + rohc_params.profile[13] = ROHCV2_RTP_UDP_LITE; + rohc_params.profile[14] = ROHC_UDP_LITE; + rohc_params.profile[15] = ROHCV2_UDP_LITE; + rohc_params.profile_len = 16; + + /* Setup ROHC compression field */ + rohc_comp_field.p = 1; + rohc_comp_field.entity = 2; + rohc_comp_field.algo = ROHC; + rohc_comp_field.comp[ROHC_PCOMP1] = 8; + rohc_comp_field.comp[ROHC_PCOMP2] = 9; + rohc_comp_field.comp_len = ROHC_PCOMP_NUM; + rohc_comp_field.rohc_params = &rohc_params; + + /* Setup which NSAPIs shall make use of v42bis */ + v42bis_params.nsapi[0] = 5; + v42bis_params.nsapi_len = 1; + + /* Setup v42bis operating parameters */ + v42bis_params.p0 = 3; + v42bis_params.p1 = 2048; + v42bis_params.p2 = 20; + + /* Setup v42bis compression field */ + v42bis_comp_field.p = 1; + v42bis_comp_field.entity = 3; + v42bis_comp_field.algo = V42BIS; + v42bis_comp_field.comp[V42BIS_DCOMP1] = 10; + v42bis_comp_field.comp_len = V42BIS_DCOMP_NUM; + v42bis_comp_field.v42bis_params = &v42bis_params; + + /* Setup which NSAPIs shall make use of v44 */ + v44_params.nsapi[0] = 5; + v44_params.nsapi_len = 1; + + /* Setup v44 operating parameters */ + v44_params.c0 = 0x80; + v44_params.p0 = 3; + v44_params.p1t = 300; + v44_params.p1r = 300; + v44_params.p3t = 600; + v44_params.p3r = 600; + + /* Setup v44 compression field */ + v44_comp_field.p = 1; + v44_comp_field.entity = 3; + v44_comp_field.algo = V44; + v44_comp_field.comp[V44_DCOMP1] = 10; + v44_comp_field.comp[V44_DCOMP2] = 11; + v44_comp_field.comp_len = V44_DCOMP_NUM; + v44_comp_field.v44_params = &v44_params; + + /* Add compression field(s) to list */ + llist_add(&v44_comp_field.list, &comp_fields); + llist_add(&v42bis_comp_field.list, &comp_fields); + llist_add(&rfc1144_comp_field.list, &comp_fields); + llist_add(&rfc2507_comp_field.list, &comp_fields); + llist_add(&rohc_comp_field.list, &comp_fields); + printf("Test input data:\n"); + gprs_sndcp_dump_comp_fields(&comp_fields, DSNDCP); + + /* Encode SNDCP-XID fields */ + rc = gprs_sndcp_compile_xid(xid, xid_len, &comp_fields); + OSMO_ASSERT(rc > 0); + + printf("Encoded: %s (%i bytes)\n", osmo_hexdump_nospc(xid, rc), rc); + + /* Parse and show contained comp fields */ + comp_fields_dec = gprs_sndcp_parse_xid(ctx, xid, rc, NULL); + OSMO_ASSERT(comp_fields_dec); + + printf("Decoded:\n"); + gprs_sndcp_dump_comp_fields(comp_fields_dec, DSNDCP); + + /* Free comp fields */ + talloc_free(comp_fields_dec); +} + +static struct log_info_cat gprs_categories[] = { + [DSNDCP] = { + .name = "DSNDCP", + .description = + "GPRS Sub-Network Dependent Control Protocol (SNDCP)", + .enabled = 1,.loglevel = LOGL_DEBUG, + } +}; + +static struct log_info info = { + .cat = gprs_categories, + .num_cat = ARRAY_SIZE(gprs_categories), +}; + +int main(int argc, char **argv) +{ + void *xid_ctx; + + osmo_init_logging(&info); + + xid_ctx = talloc_named_const(NULL, 0, "xid_ctx"); + + test_xid_decode_realworld(xid_ctx); + test_xid_encode_decode(xid_ctx); + + printf("Done\n"); + + talloc_report_full(xid_ctx, stderr); + OSMO_ASSERT(talloc_total_blocks(xid_ctx) == 1); + return 0; +} + +/* stubs */ +struct osmo_prim_hdr; +int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) +{ + abort(); +} diff --git a/openbsc/tests/sndcp_xid/sndcp_xid_test.ok b/openbsc/tests/sndcp_xid/sndcp_xid_test.ok new file mode 100644 index 0000000..f357282 --- /dev/null +++ b/openbsc/tests/sndcp_xid/sndcp_xid_test.ok @@ -0,0 +1,11 @@ +Testing SNDCP XID-Decoder/Encoder (real world data) +Decoded: +Result length=54 +Encoded: 000100023182022789ffe0000f00a8000000010101000201020003010300040104000501050006000701070008010880000412004007 +Rencoded: 000100023182022789ffe0000f00a8000000010101000201020003010300040104000501050006000701070008010880000412004007 + +Testing SNDCP XID-Encoder/Decoder +Test input data: +Encoded: 000100011a83010dab00208003012c012c02580258830007a000200308001402408000041200200781010c3456700040010005a80f000f82022789ffe0000f00a80000000101010002010200030103000401040005010500060007010700080108 (97 bytes) +Decoded: +Done diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index 6470ab9..85a81d6 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -129,3 +129,10 @@ cat $abs_srcdir/xid/xid_test.ok > expout AT_CHECK([$abs_top_builddir/tests/xid/xid_test], [], [expout], [ignore]) AT_CLEANUP + +AT_SETUP([sndcp_xid]) +AT_KEYWORDS([sndcp_xid]) +cat $abs_srcdir/sndcp_xid/sndcp_xid_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/sndcp_xid/sndcp_xid_test], [], [expout], [ignore]) +AT_CLEANUP + -- To view, visit https://gerrit.osmocom.org/641 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e Gerrit-PatchSet: 14 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Tue Aug 30 17:48:19 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Tue, 30 Aug 2016 17:48:19 +0000 Subject: [PATCH] openbsc[master]: Adding compression control and final fixups In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/642 to look at the new patch set (#25). Adding compression control and final fixups - Add module to handle compression entities - Add module to control header compression - Introduce VTY commands for heade compression configuration - Add changes in sndcp and llc to integrate header compression Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 --- M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/gprs_llc.h M openbsc/include/openbsc/gprs_sndcp.h A openbsc/include/openbsc/gprs_sndcp_comp.h A openbsc/include/openbsc/gprs_sndcp_pcomp.h M openbsc/include/openbsc/sgsn.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/gprs_llc.c M openbsc/src/gprs/gprs_sndcp.c A openbsc/src/gprs/gprs_sndcp_comp.c A openbsc/src/gprs/gprs_sndcp_pcomp.c M openbsc/src/gprs/sgsn_libgtp.c M openbsc/src/gprs/sgsn_vty.c M openbsc/tests/sgsn/Makefile.am 14 files changed, 1,433 insertions(+), 30 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/42/642/25 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 9a093ab..850eb42 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,7 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ - iu.h slhc.h + iu.h slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h index c3b82b1..8b01467 100644 --- a/openbsc/include/openbsc/gprs_llc.h +++ b/openbsc/include/openbsc/gprs_llc.h @@ -174,6 +174,15 @@ * able to create the compression entity. */ struct llist_head *xid; + /* Compression entities */ + struct { + /* In these two list_heads we will store the + * data and protocol compression entities, + * together with their compression states */ + struct llist_head *proto; + struct llist_head *data; + } comp; + /* Internal management */ uint32_t age_timestamp; }; diff --git a/openbsc/include/openbsc/gprs_sndcp.h b/openbsc/include/openbsc/gprs_sndcp.h index fef871a..d970240 100644 --- a/openbsc/include/openbsc/gprs_sndcp.h +++ b/openbsc/include/openbsc/gprs_sndcp.h @@ -21,6 +21,16 @@ struct llist_head frag_list; struct osmo_timer_list timer; + + /* Holds state to know which compression mode is used + * when the packet is re-assembled */ + uint8_t pcomp; + uint8_t dcomp; + + /* Holds the pointers to the compression entity list + * that is used when the re-assembled packet is decompressed */ + struct llist_head *proto; + struct llist_head *data; }; /* See 6.7.1.2 Reassembly */ @@ -50,4 +60,20 @@ extern struct llist_head gprs_sndcp_entities; +/* Set of SNDCP-XID negotiation (See also: TS 144 065, + * Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_req(struct gprs_llc_lle *lle, uint8_t nsapi); + +/* Process SNDCP-XID indication (See also: TS 144 065, + * Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_ind(struct gprs_llc_xid_field *xid_field_indication, + struct gprs_llc_xid_field *xid_field_response, + struct gprs_llc_lle *lle); + +/* Process SNDCP-XID indication + * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_conf(struct gprs_llc_xid_field *xid_field_conf, + struct gprs_llc_xid_field *xid_field_request, + struct gprs_llc_lle *lle); + #endif /* INT_SNDCP_H */ diff --git a/openbsc/include/openbsc/gprs_sndcp_comp.h b/openbsc/include/openbsc/gprs_sndcp_comp.h new file mode 100644 index 0000000..87ab638 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_comp.h @@ -0,0 +1,82 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +/* Header / Data compression entity */ +struct gprs_sndcp_comp { + struct llist_head list; + + /* Serves as an ID in case we want to delete this entity later */ + unsigned int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + + /* Specifies to which NSAPIs the compression entity is assigned */ + uint8_t nsapi_len; /* Number of applicable NSAPIs (default 0) */ + uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */ + + /* Assigned pcomp values */ + uint8_t comp_len; /* Number of contained PCOMP / DCOMP values */ + uint8_t comp[MAX_COMP]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */ + + /* Algorithm parameters */ + int algo; /* Algorithm type (see gprs_sndcp_xid.h) */ + int compclass; /* See gprs_sndcp_xid.h/c */ + void *state; /* Algorithm status and parameters */ +}; + +#define MAX_COMP 16 /* Maximum number of possible pcomp/dcomp values */ +#define MAX_NSAPI 11 /* Maximum number usable NSAPIs */ + +/* Allocate a compression enitiy list */ +struct llist_head *gprs_sndcp_comp_alloc(const void *ctx); + +/* Free a compression entitiy list */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities); + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, unsigned int entity); + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_add(const void *ctx, + struct llist_head *comp_entities, + const struct gprs_sndcp_comp_field + *comp_field); + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head + *comp_entities, uint8_t comp); + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head + *comp_entities, uint8_t nsapi); + +/* Find a comp_index for a given pcomp/dcomp value */ +uint8_t gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp *comp_entity, + uint8_t comp); + +/* Find a pcomp/dcomp value for a given comp_index */ +uint8_t gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp *comp_entity, + uint8_t comp_index); diff --git a/openbsc/include/openbsc/gprs_sndcp_pcomp.h b/openbsc/include/openbsc/gprs_sndcp_pcomp.h new file mode 100644 index 0000000..0733866 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_pcomp.h @@ -0,0 +1,44 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field); + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity); + +/* Expand packet header */ +int gprs_sndcp_pcomp_expand(uint8_t *data_o, uint8_t *data_i, unsigned int len, + uint8_t pcomp, + const struct llist_head *comp_entities); + +/* Compress packet header */ +int gprs_sndcp_pcomp_compress(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t *pcomp, + const struct llist_head *comp_entities, + uint8_t nsapi); diff --git a/openbsc/include/openbsc/sgsn.h b/openbsc/include/openbsc/sgsn.h index 19496cb..2d70f5a 100644 --- a/openbsc/include/openbsc/sgsn.h +++ b/openbsc/include/openbsc/sgsn.h @@ -93,6 +93,13 @@ int dynamic_lookup; struct oap_config oap; + + /* RFC1144 TCP/IP header compression */ + struct { + int active; + int passive; + int s01; + } pcomp_rfc1144; }; struct sgsn_instance { diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 245636b..2910c02 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -27,7 +27,7 @@ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ - slhc.c + slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c index 32920da..98084af 100644 --- a/openbsc/src/gprs/gprs_llc.c +++ b/openbsc/src/gprs/gprs_llc.c @@ -40,6 +40,7 @@ #include #include #include +#include #include static struct gprs_llc_llme *llme_alloc(uint32_t tlli); @@ -140,6 +141,16 @@ struct llist_head *xid_fields; struct gprs_llc_xid_field *xid_field; + struct gprs_llc_xid_field *xid_field_request; + struct gprs_llc_xid_field *xid_field_request_l3 = NULL; + + /* Pick layer3 XID from the XID request we have sent last */ + if (lle->llme->xid) { + llist_for_each_entry(xid_field_request, lle->llme->xid, list) { + if (xid_field_request->type == GPRS_LLC_XID_T_L3_PAR) + xid_field_request_l3 = xid_field_request; + } + } /* Parse and analyze XID-Response */ xid_fields = gprs_llc_parse_xid(NULL, bytes, bytes_len); @@ -150,12 +161,10 @@ llist_for_each_entry(xid_field, xid_fields, list) { /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ - if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { - LOGP(DLLC, LOGL_NOTICE, - "Ignoring SNDCP-XID-Field: XID: type=%i, data_len=%i, data=%s\n", - xid_field->type, xid_field->data_len, - osmo_hexdump_nospc(xid_field->data, - xid_field->data_len)); + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR && + xid_field_request_l3) { + sndcp_sn_xid_conf(xid_field, + xid_field_request_l3, lle); } /* Process LLC-XID fields: */ @@ -204,10 +213,6 @@ struct gprs_llc_xid_field *xid_field; struct gprs_llc_xid_field *xid_field_response; - /* Flush eventually pending XID fields */ - talloc_free(lle->llme->xid); - lle->llme->xid = NULL; - /* Parse and analyze XID-Request */ xid_fields = gprs_llc_parse_xid(lle->llme, bytes_request, bytes_request_len); @@ -236,6 +241,23 @@ (lle->llme, xid_field); llist_add(&xid_field_response->list, xid_fields_response); + } + } + + /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ + llist_for_each_entry(xid_field, xid_fields, list) { + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { + + xid_field_response = + talloc_zero(lle->llme, + struct gprs_llc_xid_field); + rc = sndcp_sn_xid_ind(xid_field, + xid_field_response, lle); + if (rc == 0) + llist_add(&xid_field_response->list, + xid_fields_response); + else + talloc_free(xid_field_response); } } @@ -525,11 +547,16 @@ llist_add(&llme->list, &gprs_llc_llmes); + llme->comp.proto = gprs_sndcp_comp_alloc(llme); + llme->comp.data = gprs_sndcp_comp_alloc(llme); + return llme; } static void llme_free(struct gprs_llc_llme *llme) { + gprs_sndcp_comp_free(llme->comp.proto); + gprs_sndcp_comp_free(llme->comp.data); talloc_free(llme->xid); llist_del(&llme->list); talloc_free(llme); diff --git a/openbsc/src/gprs/gprs_sndcp.c b/openbsc/src/gprs/gprs_sndcp.c index 4f71121..4d6adda 100644 --- a/openbsc/src/gprs/gprs_sndcp.c +++ b/openbsc/src/gprs/gprs_sndcp.c @@ -35,6 +35,131 @@ #include #include #include +#include +#include +#include +#include + +#define DEBUG_IP_PACKETS 1 /* 0=Disabled, 1=Enabled */ + +#if DEBUG_IP_PACKETS == 1 +/* Calculate TCP/IP checksum */ +static uint16_t calc_ip_csum(uint8_t *data, int len) +{ + int i; + uint32_t accumulator = 0; + uint16_t *pointer = (uint16_t *) data; + + for (i = len; i > 1; i -= 2) { + accumulator += *pointer; + pointer++; + } + + if (len % 2) + accumulator += *pointer; + + accumulator = (accumulator & 0xffff) + ((accumulator >> 16) & 0xffff); + accumulator += (accumulator >> 16) & 0xffff; + return (~accumulator); +} + +/* Calculate TCP/IP checksum */ +static uint16_t calc_tcpip_csum(const void *ctx, uint8_t *packet, int len) +{ + uint8_t *buf; + uint16_t csum; + + buf = talloc_zero_size(ctx, len); + memset(buf, 0, len); + memcpy(buf, packet + 12, 8); + buf[9] = packet[9]; + buf[11] = (len - 20) & 0xFF; + buf[10] = (len - 20) >> 8 & 0xFF; + memcpy(buf + 12, packet + 20, len - 20); + csum = calc_ip_csum(buf, len - 20 + 12); + talloc_free(buf); + return csum; +} + +/* Show some ip packet details */ +static void debug_ip_packet(uint8_t *data, int len, int dir, char *info) +{ + uint8_t tcp_flags; + char flags_debugmsg[256]; + int len_short; + static unsigned int packet_count = 0; + static unsigned int tcp_csum_err_count = 0; + static unsigned int ip_csum_err_count = 0; + + packet_count++; + + if (len > 80) + len_short = 80; + else + len_short = len; + + if (dir) + DEBUGP(DSNDCP, "%s: PHONE => NETWORK: %s\n", info, + osmo_hexdump_nospc(data, len_short)); + else + DEBUGP(DSNDCP, "%s: PHONE <= NETWORK: %s\n", info, + osmo_hexdump_nospc(data, len_short)); + + DEBUGP(DSNDCP, "%s: Length.: %d\n", info, len); + DEBUGP(DSNDCP, "%s: NO.: %d\n", info, packet_count); + + if (len < 20) { + DEBUGP(DSNDCP, "%s: Error: Short IP packet!\n", info); + return; + } + + if (calc_ip_csum(data, 20) != 0) { + DEBUGP(DSNDCP, "%s: Bad IP-Header checksum!\n", info); + ip_csum_err_count++; + } else + DEBUGP(DSNDCP, "%s: IP-Header checksum ok.\n", info); + + if (data[9] == 0x06) { + if (len < 40) { + DEBUGP(DSNDCP, "%s: Error: Short TCP packet!\n", info); + return; + } + + DEBUGP(DSNDCP, "%s: Protocol type: TCP\n", info); + tcp_flags = data[33]; + + if (calc_tcpip_csum(NULL, data, len) != 0) { + DEBUGP(DSNDCP, "%s: Bad TCP checksum!\n", info); + tcp_csum_err_count++; + } else + DEBUGP(DSNDCP, "%s: TCP checksum ok.\n", info); + + memset(flags_debugmsg, 0, sizeof(flags_debugmsg)); + if (tcp_flags & 1) + strcat(flags_debugmsg, "FIN "); + if (tcp_flags & 2) + strcat(flags_debugmsg, "SYN "); + if (tcp_flags & 4) + strcat(flags_debugmsg, "RST "); + if (tcp_flags & 8) + strcat(flags_debugmsg, "PSH "); + if (tcp_flags & 16) + strcat(flags_debugmsg, "ACK "); + if (tcp_flags & 32) + strcat(flags_debugmsg, "URG "); + DEBUGP(DSNDCP, "%s: FLAGS: %s\n", info, flags_debugmsg); + } else if (data[9] == 0x11) { + DEBUGP(DSNDCP, "%s: Protocol type: UDP\n", info); + } else { + DEBUGP(DSNDCP, "%s: Protocol type: (%02x)\n", info, data[9]); + } + + DEBUGP(DSNDCP, "%s: IP-Header checksum errors: %d\n", info, + ip_csum_err_count); + DEBUGP(DSNDCP, "%s: TCP-Checksum errors: %d\n", info, + tcp_csum_err_count); +} +#endif /* Chapter 7.2: SN-PDU Formats */ struct sndcp_common_hdr { @@ -143,6 +268,9 @@ struct msgb *msg; unsigned int seg_nr; uint8_t *npdu; + int npdu_len; + int rc; + uint8_t *expnd; LOGP(DSNDCP, LOGL_DEBUG, "TLLI=0x%08x NSAPI=%u: Defragment output PDU %u " "num_seg=%u tot_len=%u\n", sne->lle->llme->tlli, sne->nsapi, @@ -173,16 +301,46 @@ talloc_free(dqe); } + npdu_len = sne->defrag.tot_len; + /* FIXME: cancel timer */ /* actually send the N-PDU to the SGSN core code, which then * hands it off to the correct GTP tunnel + GGSN via gtp_data_req() */ - return sgsn_rx_sndcp_ud_ind(&sne->ra_id, sne->lle->llme->tlli, - sne->nsapi, msg, sne->defrag.tot_len, npdu); + + /* Decompress packet */ +#if DEBUG_IP_PACKETS == 1 + DEBUGP(DSNDCP, " \n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, "===================================================\n"); +#endif + expnd = talloc_zero_size(msg, msg->len + 64); + rc = gprs_sndcp_pcomp_expand(expnd, npdu, npdu_len, + sne->defrag.pcomp, sne->defrag.proto); + if (rc < 0) { + LOGP(DSNDCP, LOGL_ERROR, + "TCP/IP Header decompression failed!\n"); + talloc_free(expnd); + return -EIO; + } else + npdu_len = rc; +#if DEBUG_IP_PACKETS == 1 + debug_ip_packet(expnd, npdu_len, 1, "defrag_segments()"); + DEBUGP(DSNDCP, "===================================================\n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, " \n"); +#endif + + /* Hand off packet to gtp */ + rc = sgsn_rx_sndcp_ud_ind(&sne->ra_id, sne->lle->llme->tlli, + sne->nsapi, msg, npdu_len, expnd); + + talloc_free(expnd); + return rc; } -static int defrag_input(struct gprs_sndcp_entity *sne, struct msgb *msg, uint8_t *hdr, - unsigned int len) +static int defrag_input(struct gprs_sndcp_entity *sne, struct msgb *msg, + uint8_t *hdr, unsigned int len) { struct sndcp_common_hdr *sch; struct sndcp_udata_hdr *suh; @@ -343,7 +501,8 @@ }; /* returns '1' if there are more fragments to send, '0' if none */ -static int sndcp_send_ud_frag(struct sndcp_frag_state *fs) +static int sndcp_send_ud_frag(struct sndcp_frag_state *fs, + uint8_t pcomp, uint8_t dcomp) { struct gprs_sndcp_entity *sne = fs->sne; struct gprs_llc_lle *lle = sne->lle; @@ -380,8 +539,8 @@ if (sch->first) { scomph = (struct sndcp_comp_hdr *) msgb_put(fmsg, sizeof(*scomph)); - scomph->pcomp = 0; - scomph->dcomp = 0; + scomph->pcomp = pcomp; + scomph->dcomp = dcomp; } /* append the user-data header */ @@ -446,8 +605,37 @@ struct sndcp_comp_hdr *scomph; struct sndcp_udata_hdr *suh; struct sndcp_frag_state fs; + uint8_t pcomp = 0; + uint8_t dcomp = 0; + int rc; + uint8_t *compr; /* Identifiers from UP: (TLLI, SAPI) + (BVCI, NSEI) */ + + /* Compress packet */ +#if DEBUG_IP_PACKETS == 1 + DEBUGP(DSNDCP, " \n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, "===================================================\n"); + debug_ip_packet(msg->data, msg->len, 0, "sndcp_initdata_req()"); +#endif + compr = talloc_zero_size(msg, msg->len); + rc = gprs_sndcp_pcomp_compress(compr, msg->data, msg->len, &pcomp, + lle->llme->comp.proto, nsapi); + if (rc < 0) { + LOGP(DSNDCP, LOGL_ERROR, "TCP/IP Header compression failed!\n"); + talloc_free(compr); + return -EIO; + } else { + msg->len = rc; + memcpy(msg->data, compr, rc); + } + talloc_free(compr); +#if DEBUG_IP_PACKETS == 1 + DEBUGP(DSNDCP, "===================================================\n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, " \n"); +#endif sne = gprs_sndcp_entity_by_lle(lle, nsapi); if (!sne) { @@ -469,7 +657,7 @@ /* call function to generate and send fragments until all * of the N-PDU has been sent */ while (1) { - int rc = sndcp_send_ud_frag(&fs); + int rc = sndcp_send_ud_frag(&fs,pcomp,dcomp); if (rc == 0) return 0; if (rc < 0) @@ -489,8 +677,8 @@ sne->tx_npdu_nr = (sne->tx_npdu_nr + 1) % 0xfff; scomph = (struct sndcp_comp_hdr *) msgb_push(msg, sizeof(*scomph)); - scomph->pcomp = 0; - scomph->dcomp = 0; + scomph->pcomp = pcomp; + scomph->dcomp = dcomp; /* prepend common SNDCP header */ sch = (struct sndcp_common_hdr *) msgb_push(msg, sizeof(*sch)); @@ -512,6 +700,8 @@ uint8_t *npdu; uint16_t npdu_num __attribute__((unused)); int npdu_len; + int rc; + uint8_t *expnd; sch = (struct sndcp_common_hdr *) hdr; if (sch->first) { @@ -540,26 +730,58 @@ /* FIXME: move this RA_ID up to the LLME or even higher */ bssgp_parse_cell_id(&sne->ra_id, msgb_bcid(msg)); + if(scomph) { + sne->defrag.pcomp = scomph->pcomp; + sne->defrag.dcomp = scomph->dcomp; + sne->defrag.proto = lle->llme->comp.proto; + sne->defrag.data = lle->llme->comp.data; + } + /* any non-first segment is by definition something to defragment * as is any segment that tells us there are more segments */ if (!sch->first || sch->more) return defrag_input(sne, msg, hdr, len); - if (scomph && (scomph->pcomp || scomph->dcomp)) { - LOGP(DSNDCP, LOGL_ERROR, "We don't support compression yet\n"); - return -EIO; - } - npdu_num = (suh->npdu_high << 8) | suh->npdu_low; npdu = (uint8_t *)suh + sizeof(*suh); - npdu_len = (msg->data + msg->len) - npdu; + npdu_len = (msg->data + msg->len) - npdu - 3; /* -3 'removes' the FCS */ + if (npdu_len <= 0) { LOGP(DSNDCP, LOGL_ERROR, "Short SNDCP N-PDU: %d\n", npdu_len); return -EIO; } /* actually send the N-PDU to the SGSN core code, which then * hands it off to the correct GTP tunnel + GGSN via gtp_data_req() */ - return sgsn_rx_sndcp_ud_ind(&sne->ra_id, lle->llme->tlli, sne->nsapi, msg, npdu_len, npdu); + + /* Decompress packet */ +#if DEBUG_IP_PACKETS == 1 + DEBUGP(DSNDCP, " \n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, "===================================================\n"); +#endif + expnd = talloc_zero_size(msg, npdu_len + 64); + rc = gprs_sndcp_pcomp_expand(expnd, npdu, npdu_len, + sne->defrag.pcomp, sne->defrag.proto); + if (rc < 0) { + LOGP(DSNDCP, LOGL_ERROR, + "TCP/IP Header decompression failed!\n"); + talloc_free(expnd); + return -EIO; + } else + npdu_len = rc; +#if DEBUG_IP_PACKETS == 1 + debug_ip_packet(expnd, npdu_len, 1, "sndcp_llunitdata_ind()"); + DEBUGP(DSNDCP, "===================================================\n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, " \n"); +#endif + + /* Hand off packet to gtp */ + rc = sgsn_rx_sndcp_ud_ind(&sne->ra_id, lle->llme->tlli, + sne->nsapi, msg, npdu_len, expnd); + + talloc_free(expnd); + return rc; } #if 0 @@ -619,3 +841,319 @@ case LL_STATUS_IND: } #endif + +/* Generate SNDCP-XID message */ +static int gprs_llc_gen_sndcp_xid(uint8_t *bytes, int bytes_len, uint8_t nsapi) +{ + int entity = 0; + LLIST_HEAD(comp_fields); + struct gprs_sndcp_pcomp_rfc1144_params rfc1144_params; + struct gprs_sndcp_comp_field rfc1144_comp_field; + + memset(&rfc1144_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + + /* Setup rfc1144 */ + if (sgsn->cfg.pcomp_rfc1144.active) { + rfc1144_params.nsapi[0] = nsapi; + rfc1144_params.nsapi_len = 1; + rfc1144_params.s01 = sgsn->cfg.pcomp_rfc1144.s01; + rfc1144_comp_field.p = 1; + rfc1144_comp_field.entity = entity; + rfc1144_comp_field.algo = RFC_1144; + rfc1144_comp_field.comp[RFC1144_PCOMP1] = 1; + rfc1144_comp_field.comp[RFC1144_PCOMP2] = 2; + rfc1144_comp_field.comp_len = RFC1144_PCOMP_NUM; + rfc1144_comp_field.rfc1144_params = &rfc1144_params; + entity++; + llist_add(&rfc1144_comp_field.list, &comp_fields); + } + + /* Compile bytestream */ + return gprs_sndcp_compile_xid(bytes, bytes_len, &comp_fields); +} + +/* Set of SNDCP-XID bnegotiation (See also: TS 144 065, + * Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_req(struct gprs_llc_lle *lle, uint8_t nsapi) +{ + /* Note: The specification requires the SNDCP-User to set of an + * SNDCP xid request. See also 3GPP TS 44.065, 6.8 XID parameter + * negotiation, Figure 11: SNDCP XID negotiation procedure. In + * our case the SNDCP-User is sgsn_libgtp.c, which calls + * sndcp_sn_xid_req directly. */ + + uint8_t l3params[1024]; + int xid_len; + struct gprs_llc_xid_field xid_field_request; + + /* Generate compression parameter bytestream */ + xid_len = gprs_llc_gen_sndcp_xid(l3params, sizeof(l3params), nsapi); + + /* Send XID with the SNDCP-XID bytetsream included */ + if (xid_len > 0) { + xid_field_request.type = GPRS_LLC_XID_T_L3_PAR; + xid_field_request.data = l3params; + xid_field_request.data_len = xid_len; + return gprs_ll_xid_req(lle, &xid_field_request); + } + + /* When bytestream can not be generated, proceed without SNDCP-XID */ + else { + return gprs_ll_xid_req(lle, NULL); + } +} + +/* Handle header compression entites */ +static int handle_pcomp_entities(struct gprs_sndcp_comp_field *comp_field, + struct gprs_llc_lle *lle) +{ + /* Note: This functions also transforms the comp_field into its + * echo form (strips comp values, resets propose bit etc...) + * the processed comp_fields can then be sent back as XID- + * Response without further modification. */ + + /* Delete propose bit */ + comp_field->p = 0; + + /* Process proposed parameters */ + switch (comp_field->algo) { + case RFC_1144: + if (sgsn->cfg.pcomp_rfc1144.passive && + comp_field->rfc1144_params->nsapi_len > 0) { + LOGP(DSNDCP, LOGL_DEBUG, + "Accepting RFC1144 header compression...\n"); + gprs_sndcp_comp_add(lle->llme, lle->llme->comp.proto, + comp_field); + } else { + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting RFC1144 header compression...\n"); + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + comp_field->rfc1144_params->nsapi_len = 0; + } + break; + case RFC_2507: + /* RFC 2507 is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting RFC2507 header compression...\n"); + comp_field->rfc2507_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + break; + case ROHC: + /* ROHC is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting ROHC header compression...\n"); + comp_field->rohc_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + break; + } + + return 0; +} + +/* Hanle data compression entites */ +static int handle_dcomp_entities(struct gprs_sndcp_comp_field *comp_field, + struct gprs_llc_lle *lle) +{ + /* See note in handle_pcomp_entities() */ + + /* Delete propose bit */ + comp_field->p = 0; + + /* Process proposed parameters */ + switch (comp_field->algo) { + case V42BIS: + /* V42BIS is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting V.42bis data compression...\n"); + comp_field->v42bis_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + break; + case V44: + /* V44 is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting V.44 data compression...\n"); + comp_field->v44_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + break; + } + + return 0; + +} + +/* Process SNDCP-XID indication + * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_ind(struct gprs_llc_xid_field *xid_field_indication, + struct gprs_llc_xid_field *xid_field_response, + struct gprs_llc_lle *lle) +{ + /* Note: This function computes the SNDCP-XID response that is sent + * back to the phone when a phone originated XID is received. The + * Input XID fields are directly processed and the result is directly + * handed back. */ + + int rc; + int compclass; + + struct llist_head *comp_fields; + struct gprs_sndcp_comp_field *comp_field; + + OSMO_ASSERT(xid_field_indication); + OSMO_ASSERT(xid_field_response); + OSMO_ASSERT(lle); + + /* Parse SNDCP-CID XID-Field */ + comp_fields = gprs_sndcp_parse_xid(lle->llme, + xid_field_indication->data, + xid_field_indication->data_len, + NULL); + if (!comp_fields) + return -EINVAL; + + /* Don't bother with empty indications */ + if (llist_empty(comp_fields)) { + xid_field_response->data = NULL; + xid_field_response->data_len = 0; + DEBUGP(DSNDCP, + "SNDCP-XID indication did not contain any parameters!\n"); + return 0; + } + + /* Handle compression entites */ + DEBUGP(DSNDCP, "SNDCP-XID-IND (phone):\n"); + gprs_sndcp_dump_comp_fields(comp_fields, LOGL_DEBUG); + + llist_for_each_entry(comp_field, comp_fields, list) { + compclass = gprs_sndcp_get_compression_class(comp_field); + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + rc = handle_pcomp_entities(comp_field, lle); + else if (compclass == SNDCP_XID_DATA_COMPRESSION) + rc = handle_dcomp_entities(comp_field, lle); + else { + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + rc = 0; + } + + if (rc < 0) { + talloc_free(comp_fields); + return -EINVAL; + } + } + + DEBUGP(DSNDCP, + "SNDCP-XID-RES (sgsn):\n"); + gprs_sndcp_dump_comp_fields(comp_fields, LOGL_DEBUG); + + /* Reserve some memory to store the modified SNDCP-XID bytes */ + xid_field_response->data = + talloc_zero_size(lle->llme, xid_field_indication->data_len); + + /* Set Type flag for response */ + xid_field_response->type = GPRS_LLC_XID_T_L3_PAR; + + /* Compile modified SNDCP-XID bytes */ + rc = gprs_sndcp_compile_xid(xid_field_response->data, + xid_field_indication->data_len, + comp_fields); + + if (rc > 0) + xid_field_response->data_len = rc; + else { + talloc_free(xid_field_response->data); + xid_field_response->data = NULL; + xid_field_response->data_len = 0; + return -EINVAL; + } + + talloc_free(comp_fields); + + return 0; +} + +/* Process SNDCP-XID indication + * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_conf(struct gprs_llc_xid_field *xid_field_conf, + struct gprs_llc_xid_field *xid_field_request, + struct gprs_llc_lle *lle) +{ + /* Note: This function handles an incomming SNDCP-XID confirmiation. + * Since the confirmation fields may lack important parameters we + * will reconstruct these missing fields using the original request + * we have sent. After that we will create (or delete) the + * compression entites */ + + struct llist_head *comp_fields_req; + struct llist_head *comp_fields_conf; + struct gprs_sndcp_comp_field *comp_field; + int rc; + int compclass; + + /* We need both, the confirmation that is sent back by the phone, + * and the original request we have sent. If one of this is missing + * we can not process the confirmation, the caller must check if + * request and confirmation fields are available. */ + OSMO_ASSERT(xid_field_conf); + OSMO_ASSERT(xid_field_request); + + /* Parse SNDCP-CID XID-Field */ + comp_fields_req = gprs_sndcp_parse_xid(lle->llme, + xid_field_request->data, + xid_field_request->data_len, + NULL); + if (!comp_fields_req) + return -EINVAL; + + DEBUGP(DSNDCP, "SNDCP-XID-REQ (sgsn):\n"); + gprs_sndcp_dump_comp_fields(comp_fields_req, LOGL_DEBUG); + + /* Parse SNDCP-CID XID-Field */ + comp_fields_conf = gprs_sndcp_parse_xid(lle->llme, + xid_field_conf->data, + xid_field_conf->data_len, + comp_fields_req); + if (!comp_fields_conf) + return -EINVAL; + + DEBUGP(DSNDCP, + "SNDCP-XID-CONF (phone):\n"); + gprs_sndcp_dump_comp_fields(comp_fields_conf, LOGL_DEBUG); + + /* Handle compression entites */ + llist_for_each_entry(comp_field, comp_fields_conf, list) { + compclass = gprs_sndcp_get_compression_class(comp_field); + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + rc = handle_pcomp_entities(comp_field, lle); + else if (compclass == SNDCP_XID_DATA_COMPRESSION) + rc = handle_dcomp_entities(comp_field, lle); + else { + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + rc = 0; + } + + if (rc < 0) { + talloc_free(comp_fields_req); + talloc_free(comp_fields_conf); + return -EINVAL; + } + } + + talloc_free(comp_fields_req); + talloc_free(comp_fields_conf); + + return 0; +} diff --git a/openbsc/src/gprs/gprs_sndcp_comp.c b/openbsc/src/gprs/gprs_sndcp_comp.c new file mode 100644 index 0000000..ede584e --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_comp.c @@ -0,0 +1,320 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +/* Create a new compression entity from a XID-Field */ +static struct gprs_sndcp_comp *gprs_sndcp_comp_create(const void *ctx, + const struct + gprs_sndcp_comp_field + *comp_field) +{ + struct gprs_sndcp_comp *comp_entity; + comp_entity = talloc_zero(ctx, struct gprs_sndcp_comp); + + /* Copy relevant information from the SNDCP-XID field */ + comp_entity->entity = comp_field->entity; + comp_entity->comp_len = comp_field->comp_len; + memcpy(comp_entity->comp, comp_field->comp, sizeof(comp_entity->comp)); + + if (comp_field->rfc1144_params) { + comp_entity->nsapi_len = comp_field->rfc1144_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc1144_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->rfc2507_params) { + comp_entity->nsapi_len = comp_field->rfc2507_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc2507_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->rohc_params) { + comp_entity->nsapi_len = comp_field->rohc_params->nsapi_len; + memcpy(comp_entity->nsapi, comp_field->rohc_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->v42bis_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->v44_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + sizeof(comp_entity->nsapi)); + } else { + /* The caller is expected to check carefully if the all + * data fields required for compression entity creation + * are present. Otherwise we blow an assertion here */ + OSMO_ASSERT(false); + } + comp_entity->algo = comp_field->algo; + + /* Check if an NSAPI is selected, if not, it does not make sense + * to create the compression entity, since the caller should + * have checked the presence of the NSAPI, we blow an assertion + * in case of missing NSAPIs */ + OSMO_ASSERT(comp_entity->nsapi_len > 0); + + /* Determine of which class our compression entity will be + * (Protocol or Data compresson ?) */ + comp_entity->compclass = gprs_sndcp_get_compression_class(comp_field); + + OSMO_ASSERT(comp_entity->compclass != -1); + + /* Create an algorithm specific compression context */ + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + if (gprs_sndcp_pcomp_init(ctx, comp_entity, comp_field) != 0) { + talloc_free(comp_entity); + comp_entity = NULL; + } + } else { + LOGP(DSNDCP, LOGL_ERROR, + "We don't support data compression yet!\n"); + talloc_free(comp_entity); + return NULL; + } + + /* Display info message */ + if (comp_entity == NULL) { + LOGP(DSNDCP, LOGL_ERROR, + "Header compression entity (%d) creation failed!\n", + comp_entity->entity); + return NULL; + } + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "New header compression entity (%d) created.\n", + comp_entity->entity); + } else { + LOGP(DSNDCP, LOGL_INFO, + "New data compression entity (%d) created.\n", + comp_entity->entity); + } + + return comp_entity; +} + +/* Allocate a compression enitiy list */ +struct llist_head *gprs_sndcp_comp_alloc(const void *ctx) +{ + struct llist_head *lh; + + lh = talloc_zero(ctx, struct llist_head); + INIT_LLIST_HEAD(lh); + + return lh; +} + +/* Free a compression entitiy list */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities) +{ + struct gprs_sndcp_comp *comp_entity; + + /* We expect the caller to take care of allocating a + * compression entity list properly. Attempting to + * free a non existing list clearly points out + * a malfunction. */ + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + /* Free compression entity */ + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %d ...\n", + comp_entity->entity); + gprs_sndcp_pcomp_term(comp_entity); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %d ...\n", + comp_entity->entity); + } + } + + talloc_free(comp_entities); +} + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, + unsigned int entity) +{ + struct gprs_sndcp_comp *comp_entity; + struct gprs_sndcp_comp *comp_entity_to_delete = NULL; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) { + comp_entity_to_delete = comp_entity; + break; + } + } + + if (!comp_entity_to_delete) + return; + + if (comp_entity_to_delete->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %d ...\n", + comp_entity_to_delete->entity); + gprs_sndcp_pcomp_term(comp_entity_to_delete); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %d ...\n", + comp_entity_to_delete->entity); + } + + /* Delete compression entity */ + llist_del(&comp_entity_to_delete->list); + talloc_free(comp_entity_to_delete); +} + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_add(const void *ctx, + struct llist_head *comp_entities, + const struct gprs_sndcp_comp_field + *comp_field) +{ + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(comp_entities); + OSMO_ASSERT(comp_field); + + /* Just to be sure, if the entity is already in + * the list it will be deleted now */ + gprs_sndcp_comp_delete(comp_entities, comp_field->entity); + + /* Create and add a new entity to the list */ + comp_entity = gprs_sndcp_comp_create(ctx, comp_field); + + if (!comp_entity) + return NULL; + + llist_add(&comp_entity->list, comp_entities); + return comp_entity; +} + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head + *comp_entities, uint8_t comp) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return comp_entity; + } + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given pcomp/dcomp value %d.\n", + comp); + return NULL; +} + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head + *comp_entities, uint8_t nsapi) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->nsapi_len; i++) { + if (comp_entity->nsapi[i] == nsapi) + return comp_entity; + } + } + + return NULL; +} + +/* Find a comp_index for a given pcomp/dcomp value */ +uint8_t gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp *comp_entity, + uint8_t comp) +{ + /* Note: This function returns a normalized version of the comp value, + * which matches up with the position of the comp field. Since comp=0 + * is reserved for "no compression", the index value starts counting + * at one. The return value is the PCOMPn/DCOMPn value one can find + * in the Specification (see e.g. 3GPP TS 44.065, 6.5.3.2, Table 7) */ + + int i; + OSMO_ASSERT(comp_entity); + + /* A pcomp/dcomp value of zero is reserved for "no comproession", + * So we just bail and return zero in this case */ + if (comp == 0) + return 0; + + /* Look in the pcomp/dcomp list for the index */ + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return i + 1; + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching comp_index for given pcomp/dcomp value %d\n", + comp); + return 0; +} + +/* Find a pcomp/dcomp value for a given comp_index */ +uint8_t gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp *comp_entity, + uint8_t comp_index) +{ + OSMO_ASSERT(comp_entity); + + /* A comp_index of zero translates to zero right away. */ + if (comp_index == 0) + return 0; + + if (comp_index > comp_entity->comp_len) { + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching pcomp/dcomp value for given comp_index value %d.\n", + comp_index); + return 0; + } + + /* Look in the pcomp/dcomp list for the comp_index, see + * note in gprs_sndcp_comp_get_idx() */ + return comp_entity->comp[comp_index - 1]; +} diff --git a/openbsc/src/gprs/gprs_sndcp_pcomp.c b/openbsc/src/gprs/gprs_sndcp_pcomp.c new file mode 100644 index 0000000..c5118cd --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_pcomp.c @@ -0,0 +1,288 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a new header compression + * entity is created by gprs_sndcp.c */ + + OSMO_ASSERT(comp_entity); + OSMO_ASSERT(comp_field); + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + comp_entity->state = + slhc_init(ctx, comp_field->rfc1144_params->s01 + 1, + comp_field->rfc1144_params->s01 + 1); + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression initalized.\n"); + return 0; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a header compression + * entity is deleted by gprs_sndcp.c */ + + OSMO_ASSERT(comp_entity); + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + if (comp_entity->state) { + slhc_free((struct slcompress *)comp_entity->state); + comp_entity->state = NULL; + } + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression terminated.\n"); + return; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Compress a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_compress(uint8_t *pcomp_index, + uint8_t *data_o, uint8_t *data_i, + unsigned int len, + struct slcompress *comp) +{ + uint8_t *comp_ptr; + int compr_len; + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Run compressor */ + compr_len = slhc_compress(comp, data_i, len, data_o, &comp_ptr, 0); + + /* Generate pcomp_index */ + if (data_o[0] & SL_TYPE_COMPRESSED_TCP) { + *pcomp_index = 2; + data_o[0] &= ~SL_TYPE_COMPRESSED_TCP; + } else if ((data_o[0] & SL_TYPE_UNCOMPRESSED_TCP) == + SL_TYPE_UNCOMPRESSED_TCP) { + *pcomp_index = 1; + data_o[0] &= 0x4F; + } else + *pcomp_index = 0; + + return compr_len; +} + +/* Expand a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_expand(uint8_t *data_o, uint8_t *data_i, + unsigned int len, + uint8_t pcomp_index, + struct slcompress *comp) +{ + int data_decompressed_len; + int type; + + /* Note: this function should never be called with pcomp_index=0, + * since this condition is already filtered + * out by gprs_sndcp_pcomp_expand() */ + + /* Determine the data type by the PCOMP index */ + switch (pcomp_index) { + case 0: + type = SL_TYPE_IP; + case 1: + type = SL_TYPE_UNCOMPRESSED_TCP; + break; + case 2: + type = SL_TYPE_COMPRESSED_TCP; + break; + default: + LOGP(DSNDCP, LOGL_ERROR, "gprs_sndcp_pcomp_rfc1144_expand() Invalid pcomp_index value (%d) detected, assuming no compression!\n", + pcomp_index); + type = SL_TYPE_IP; + break; + } + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Restore the original version nibble on + * marked uncompressed packets */ + if (type == SL_TYPE_UNCOMPRESSED_TCP) { + /* Just in case the phone tags uncompressed tcp-data + * (normally this is handled by pcomp so there is + * no need for tagging the data) */ + data_o[0] &= 0x4F; + data_decompressed_len = slhc_remember(comp, data_o, len); + return data_decompressed_len; + } + + /* Uncompress compressed packets */ + else if (type == SL_TYPE_COMPRESSED_TCP) { + data_decompressed_len = slhc_uncompress(comp, data_o, len); + return data_decompressed_len; + } + + /* Regular or unknown packets will not be touched */ + return len; +} + +/* Expand packet header */ +int gprs_sndcp_pcomp_expand(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t pcomp, + const struct llist_head *comp_entities) +{ + int rc; + uint8_t pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data_o); + OSMO_ASSERT(data_i); + OSMO_ASSERT(comp_entities); + + LOGP(DSNDCP, LOGL_DEBUG, "Header compression entity list: comp_entities=%p\n", + comp_entities); + + LOGP(DSNDCP, LOGL_DEBUG, "Header compression mode: pcomp=%d\n", pcomp); + + /* Skip on pcomp=0 */ + if (pcomp == 0) { + memcpy(data_o, data_i, len); + return len; + } + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_comp(comp_entities, pcomp); + + /* Skip compression if no suitable compression entity can be found */ + if (!comp_entity) { + memcpy(data_o, data_i, len); + return len; + } + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION); + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144); + + /* Find pcomp_index */ + pcomp_index = gprs_sndcp_comp_get_idx(comp_entity, pcomp); + + /* Run decompression algo */ + rc = gprs_sndcp_pcomp_rfc1144_expand(data_o, data_i, len, pcomp_index, + comp_entity->state); + slhc_i_status(comp_entity->state); + slhc_o_status(comp_entity->state); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header expansion done, old length=%d, new length=%d, entity=%p\n", + len, rc, comp_entity); + + return rc; +} + +/* Compress packet header */ +int gprs_sndcp_pcomp_compress(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t *pcomp, + const struct llist_head *comp_entities, + uint8_t nsapi) +{ + int rc; + uint8_t pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data_o); + OSMO_ASSERT(data_i); + OSMO_ASSERT(pcomp); + OSMO_ASSERT(comp_entities); + + LOGP(DSNDCP, LOGL_DEBUG, "Header compression entity list: comp_entities=%p\n", + comp_entities); + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_nsapi(comp_entities, nsapi); + + /* Skip compression if no suitable compression entity can be found */ + if (!comp_entity) { + *pcomp = 0; + memcpy(data_o, data_i, len); + return len; + } + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION); + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144); + + /* Run compression algo */ + rc = gprs_sndcp_pcomp_rfc1144_compress(&pcomp_index, data_o, data_i, + len, comp_entity->state); + slhc_i_status(comp_entity->state); + slhc_o_status(comp_entity->state); + + /* Find pcomp value */ + *pcomp = gprs_sndcp_comp_get_comp(comp_entity, pcomp_index); + + LOGP(DSNDCP, LOGL_DEBUG, "Header compression mode: pcomp=%d\n", *pcomp); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header compression done, old length=%d, new length=%d, entity=%p\n", + len, rc, comp_entity); + return rc; +} diff --git a/openbsc/src/gprs/sgsn_libgtp.c b/openbsc/src/gprs/sgsn_libgtp.c index be7637a..6e6bbfd 100644 --- a/openbsc/src/gprs/sgsn_libgtp.c +++ b/openbsc/src/gprs/sgsn_libgtp.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -307,6 +308,8 @@ static int send_act_pdp_cont_acc(struct sgsn_pdp_ctx *pctx) { struct sgsn_signal_data sig_data; + int rc; + struct gprs_llc_lle *lle; /* Inform others about it */ memset(&sig_data, 0, sizeof(sig_data)); @@ -314,7 +317,17 @@ osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_ACT, &sig_data); /* Send PDP CTX ACT to MS */ - return gsm48_tx_gsm_act_pdp_acc(pctx); + rc = gsm48_tx_gsm_act_pdp_acc(pctx); + if(rc < 0) + return rc; + + /* Send SNDCP XID to MS */ + lle = &pctx->mm->gb.llme->lle[pctx->sapi]; + rc = sndcp_sn_xid_req(lle,pctx->nsapi); + if(rc < 0) + return rc; + + return 0; } /* The GGSN has confirmed the creation of a PDP Context */ diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c index e6dc68d..0eea350 100644 --- a/openbsc/src/gprs/sgsn_vty.c +++ b/openbsc/src/gprs/sgsn_vty.c @@ -269,6 +269,14 @@ vty_out(vty, " timer t3395 %d%s", g_cfg->timers.T3395, VTY_NEWLINE); vty_out(vty, " timer t3397 %d%s", g_cfg->timers.T3397, VTY_NEWLINE); + if (g_cfg->pcomp_rfc1144.active) { + vty_out(vty, " compression rfc1144 active slots %d%s", + g_cfg->pcomp_rfc1144.s01 + 1, VTY_NEWLINE); + } else if (g_cfg->pcomp_rfc1144.passive) { + vty_out(vty, " compression rfc1144 passive%s", VTY_NEWLINE); + } else + vty_out(vty, " no compression rfc1144%s", VTY_NEWLINE); + return CMD_SUCCESS; } @@ -1074,6 +1082,41 @@ return CMD_SUCCESS; } +#define COMPRESSION_STR "Configure compression\n" +DEFUN(cfg_no_comp_rfc1144, cfg_no_comp_rfc1144_cmd, + "no compression rfc1144", + NO_STR COMPRESSION_STR "disable rfc1144 TCP/IP header compression\n") +{ + g_cfg->pcomp_rfc1144.active = 0; + g_cfg->pcomp_rfc1144.passive = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_comp_rfc1144, cfg_comp_rfc1144_cmd, + "compression rfc1144 active slots <1-256>", + COMPRESSION_STR + "RFC1144 Header compresion scheme\n" + "Compression is actively proposed\n" + "Number of compression state slots\n" + "Number of compression state slots\n") +{ + g_cfg->pcomp_rfc1144.active = 1; + g_cfg->pcomp_rfc1144.passive = 1; + g_cfg->pcomp_rfc1144.s01 = atoi(argv[0]) - 1; + return CMD_SUCCESS; +} + +DEFUN(cfg_comp_rfc1144p, cfg_comp_rfc1144p_cmd, + "compression rfc1144 passive", + COMPRESSION_STR + "RFC1144 Header compresion scheme\n" + "Compression is available on request\n") +{ + g_cfg->pcomp_rfc1144.active = 0; + g_cfg->pcomp_rfc1144.passive = 1; + return CMD_SUCCESS; +} + int sgsn_vty_init(void) { install_element_ve(&show_sgsn_cmd); @@ -1128,6 +1171,10 @@ install_element(SGSN_NODE, &cfg_sgsn_T3395_cmd); install_element(SGSN_NODE, &cfg_sgsn_T3397_cmd); + install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd); + install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd); + install_element(SGSN_NODE, &cfg_comp_rfc1144p_cmd); + return 0; } diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 3e66978..1804280 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -33,6 +33,8 @@ $(top_builddir)/src/gprs/gprs_llc_xid.o \ $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ $(top_builddir)/src/gprs/slhc.o \ + $(top_builddir)/src/gprs/gprs_sndcp_comp.o \ + $(top_builddir)/src/gprs/gprs_sndcp_pcomp.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ -- To view, visit https://gerrit.osmocom.org/642 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 Gerrit-PatchSet: 25 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Tue Aug 30 17:48:19 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Tue, 30 Aug 2016 17:48:19 +0000 Subject: [PATCH] openbsc[master]: V.42bis integration and unit test In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/644 to look at the new patch set (#32). V.42bis integration and unit test The previously committed V.42bis implementation has been edited to function outside IAXmodem. Debug printf statements were changed into DEBUGP statements. Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d --- M openbsc/.gitignore M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/debug.h M openbsc/include/openbsc/v42bis.h M openbsc/include/openbsc/v42bis_private.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/sgsn_main.c M openbsc/src/gprs/v42bis.c M openbsc/tests/Makefile.am M openbsc/tests/testsuite.at A openbsc/tests/v42bis/Makefile.am A openbsc/tests/v42bis/v42bis_test.c A openbsc/tests/v42bis/v42bis_test.ok 14 files changed, 1,027 insertions(+), 29 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/44/644/32 diff --git a/openbsc/.gitignore b/openbsc/.gitignore index e75b9eb..6fbd463 100644 --- a/openbsc/.gitignore +++ b/openbsc/.gitignore @@ -84,6 +84,7 @@ tests/xid/xid_test tests/sndcp_xid/sndcp_xid_test tests/slhc/slhc_test +tests/v42bis/v42bis_test tests/atconfig tests/atlocal diff --git a/openbsc/configure.ac b/openbsc/configure.ac index cebabdc..173c6c8 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -233,6 +233,7 @@ tests/xid/Makefile tests/sndcp_xid/Makefile tests/slhc/Makefile + tests/v42bis/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 850eb42..67ba551 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,9 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ - iu.h slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h + iu.h slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h v42bis.h \ + v42bis_private.h +>>>>>>> V.42bis integration and unit test openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 90ddca5..ca3d4ad 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -37,6 +37,7 @@ DGTPHUB, DRANAP, DSUA, + DV42BIS, Debug_LastEntry, }; diff --git a/openbsc/include/openbsc/v42bis.h b/openbsc/include/openbsc/v42bis.h index b947a61..607a58e 100644 --- a/openbsc/include/openbsc/v42bis.h +++ b/openbsc/include/openbsc/v42bis.h @@ -31,8 +31,12 @@ \section v42bis_page_sec_2 How does it work? */ +#include + #if !defined(_SPANDSP_V42BIS_H_) #define _SPANDSP_V42BIS_H_ + +#define SPAN_DECLARE(x) x #define V42BIS_MIN_STRING_SIZE 6 #define V42BIS_MAX_STRING_SIZE 250 @@ -55,6 +59,8 @@ V42BIS_COMPRESSION_MODE_ALWAYS, V42BIS_COMPRESSION_MODE_NEVER }; + +typedef void (*put_msg_func_t)(void *user_data, const uint8_t *msg, int len); /*! V.42bis compression/decompression descriptor. This defines the working state for a @@ -111,7 +117,8 @@ \param decode_user_data An opaque pointer passed to the decode callback handler. \param max_decode_len The maximum length that should be passed to the decode handler. \return The V.42bis context. */ -SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, +SPAN_DECLARE(v42bis_state_t *) v42bis_init(const void *ctx, + v42bis_state_t *s, int negotiated_p0, int negotiated_p1, int negotiated_p2, diff --git a/openbsc/include/openbsc/v42bis_private.h b/openbsc/include/openbsc/v42bis_private.h index 2c801eb..daa5ea3 100644 --- a/openbsc/include/openbsc/v42bis_private.h +++ b/openbsc/include/openbsc/v42bis_private.h @@ -120,7 +120,6 @@ v42bis_comp_state_t decompress; /*! \brief Error and flow logging control */ - logging_state_t logging; }; #endif diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 2910c02..f479d56 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -27,7 +27,7 @@ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ - slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c + slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c v42bis.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c index 894ce84..f01798b 100644 --- a/openbsc/src/gprs/sgsn_main.c +++ b/openbsc/src/gprs/sgsn_main.c @@ -297,6 +297,11 @@ .description = "RFC1144 TCP/IP Header compression (SLHC)", .enabled = 1, .loglevel = LOGL_DEBUG, }, + [DV42BIS] = { + .name = "DV42BIS", + .description = "V.42bis data compression (SNDCP)", + .enabled = 1, .loglevel = LOGL_DEBUG, + } }; static const struct log_info gprs_log_info = { diff --git a/openbsc/src/gprs/v42bis.c b/openbsc/src/gprs/v42bis.c index d025ea9..74c6db9 100644 --- a/openbsc/src/gprs/v42bis.c +++ b/openbsc/src/gprs/v42bis.c @@ -29,10 +29,6 @@ /*! \file */ -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - #include #include #include @@ -42,14 +38,13 @@ #include #include -#include "spandsp/telephony.h" -#include "spandsp/logging.h" -#include "spandsp/bit_operations.h" -#include "spandsp/async.h" -#include "spandsp/v42bis.h" +#include +#include +#include +#include -#include "spandsp/private/logging.h" -#include "spandsp/private/v42bis.h" +#define FALSE 0 +#define TRUE 1 /* Fixed parameters from the spec. */ /* Character size (bits) */ @@ -321,7 +316,7 @@ s = &ss->compress; if (!s->transparent) return; - span_log(&ss->logging, SPAN_LOG_FLOW, "Changing to compressed mode\n"); + DEBUGP(DV42BIS,"Changing to compressed mode\n"); /* Switch out of transparent now, between codes. We need to send the octet which did not match, just before switching. */ if (s->last_matched) @@ -344,7 +339,7 @@ s = &ss->compress; if (s->transparent) return; - span_log(&ss->logging, SPAN_LOG_FLOW, "Changing to transparent mode\n"); + DEBUGP(DV42BIS,"Changing to transparent mode\n"); /* Switch into transparent now, between codes, and the unmatched octet should go out in transparent mode, just below */ if (s->last_matched) @@ -543,7 +538,7 @@ { case V42BIS_ECM: /* Enter compressed mode */ - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_ECM\n"); + DEBUGP(DV42BIS,"Hit V42BIS_ECM\n"); send_string(s); s->transparent = FALSE; s->update_at = s->last_matched; @@ -552,20 +547,20 @@ continue; case V42BIS_EID: /* Escape symbol */ - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_EID\n"); + DEBUGP(DV42BIS,"Hit V42BIS_EID\n"); in = s->escape_code; s->escape_code += V42BIS_ESC_STEP; break; case V42BIS_RESET: /* Reset dictionary */ - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_RESET\n"); + DEBUGP(DV42BIS,"Hit V42BIS_RESET\n"); /* TODO: */ send_string(s); dictionary_init(s); i++; continue; default: - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_???? - %" PRIu32 "\n", in); + DEBUGP(DV42BIS,"Hit V42BIS_???? - %" PRIu32 "\n", in); return -1; } } @@ -634,7 +629,7 @@ { case V42BIS_ETM: /* Enter transparent mode */ - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_ETM\n"); + DEBUGP(DV42BIS,"Hit V42BIS_ETM\n"); s->bit_count = 0; s->transparent = TRUE; s->last_matched = 0; @@ -642,12 +637,12 @@ break; case V42BIS_FLUSH: /* Flush signal */ - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_FLUSH\n"); + DEBUGP(DV42BIS,"Hit V42BIS_FLUSH\n"); s->bit_count = 0; break; case V42BIS_STEPUP: /* Increase code word size */ - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_STEPUP\n"); + DEBUGP(DV42BIS,"Hit V42BIS_STEPUP\n"); s->v42bis_parm_c2++; s->v42bis_parm_c3 <<= 1; if (s->v42bis_parm_c2 > (s->v42bis_parm_n2 >> 3)) @@ -708,7 +703,8 @@ } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, +SPAN_DECLARE(v42bis_state_t *) v42bis_init(const void *ctx, + v42bis_state_t *s, int negotiated_p0, int negotiated_p1, int negotiated_p2, @@ -727,12 +723,10 @@ return NULL; if (s == NULL) { - if ((s = (v42bis_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (v42bis_state_t *) talloc_zero_size(ctx,sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); - span_log_init(&s->logging, SPAN_LOG_NONE, NULL); - span_log_set_protocol(&s->logging, "V.42bis"); if ((ret = v42bis_comp_init(&s->compress, negotiated_p1, negotiated_p2, encode_handler, encode_user_data, max_encode_len))) return NULL; @@ -758,6 +752,7 @@ { comp_exit(&s->compress); comp_exit(&s->decompress); + talloc_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index d5aa356..7acebc0 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid slhc +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid slhc v42bis if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index 5f37b8e..f18b734 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -141,3 +141,9 @@ cat $abs_srcdir/slhc/slhc_test.ok > expout AT_CHECK([$abs_top_builddir/tests/slhc/slhc_test], [], [expout], [ignore]) AT_CLEANUP + +AT_SETUP([v42bis]) +AT_KEYWORDS([v42bis]) +cat $abs_srcdir/v42bis/v42bis_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/v42bis/v42bis_test], [], [expout], [ignore]) +AT_CLEANUP diff --git a/openbsc/tests/v42bis/Makefile.am b/openbsc/tests/v42bis/Makefile.am new file mode 100644 index 0000000..9001c0f --- /dev/null +++ b/openbsc/tests/v42bis/Makefile.am @@ -0,0 +1,21 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) + +EXTRA_DIST = v42bis_test.ok + +noinst_PROGRAMS = v42bis_test + +v42bis_test_SOURCES = v42bis_test.c + +v42bis_test_LDADD = \ + $(top_builddir)/src/gprs/v42bis.o \ + $(top_builddir)/src/libcommon/libcommon.a \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOGB_LIBS) \ + $(LIBCARES_LIBS) \ + $(LIBCRYPTO_LIBS) \ + -lgtp -lrt -lm + + diff --git a/openbsc/tests/v42bis/v42bis_test.c b/openbsc/tests/v42bis/v42bis_test.c new file mode 100644 index 0000000..cbe13d5 --- /dev/null +++ b/openbsc/tests/v42bis/v42bis_test.c @@ -0,0 +1,424 @@ +/* Test v42bis Compression/Decompression */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#define P0 3 +#define P1 512 +#define P2 20 + +#define BLOCK_SIZE 1024 +#define MAX_BLOCK_SIZE 1024 + +/* Compressed sample packets, sniffed from real communication */ +#define COMPR_PACKETS_LEN 31 +char *compr_packets[] = { + "4500010268000700004006cefac0a80002550d93d740000050462c7ba7e4d1753a80184000aad500000101080a0001a670084dafb4474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992becf8918d0c9145465441939fcc6a1950a206b7e1fca38e1145eaebc129230aeb24f57bcab011c3c68829f5efe7bfcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0085a3a4e1c3466c6c649ea048d519d5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622e7fa7dac30ac602f9af40a9ef0236a54268247cd7f923946d0a8d1c3c68d1e35788c5002e54ad0a00100", + "4500010268000900004006cef8c0a80002550d93d740000050462c7ba7e4d1753a801840007e7f00000101080a0001d1cc084db0ae474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992becf8918d0c9145465441939fcc6a1950a206b7e1fca38e1145eaebc129230aeb24f57bcab011c3c68829f5efe7bfcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0085a3a4e1c3466c6c649ea048d519d5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622e7fa7dac30ac602f9af40a9ef0236a54268247cd7f923946d0a8d1c3c68d1e35788c5002e54ad0a00100", + "4500010268000b00004006cef6c0a80002550d93d740000050462c7ba7e4d1753b80193fff131c00000101080a00022884084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992be4e8918d8c9045465441939fcc6a1950a206b7e1dca38e1145eaebb929230aeb24f579cab011c3c68829f5efe7afcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0084a3a4e1c3466c6c649ea048dd19c5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622c7fa7dac30ac5c2f9af40a1ef0236a502682478dff913946d0a8d1c3c68d1e35788c5002e54ad0a00100", + "4500010268000c00004006cef5c0a80002550d93d740000050462c7ba7e4d1753b80193fff65ab00000101080a0002d5f4084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992be4e8918d8c9045465441939fcc6a1950a206b7e1dca38e1145eaebb929230aeb24f579cab011c3c68829f5efe7afcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0084a3a4e1c3466c6c649ea048dd19c5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622c7fa7dac30ac5c2f9af40a1ef0236a502682478dff913946d0a8d1c3c68d1e35788c5002e54ad0a00100", + "450001022d000f00004006ac5ec0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00", + "450001022d001000004006ac5dc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00", + "450001022d001100004006ac5cc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00", + "450001022d001200004006ac5bc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00", + "4500010268001300004006ceeec0a80002550d93d740000050462c7ba7e4d1753b80193fff7b4a00000101080a0003c054084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005bbb7e0d3b964dd9b369d7b6ddb3e60e9c372ef614beeb15ac58b2660513368cf8cdd63b68f65045ab96ed9cb58947b490d1422851a34861185923d50e9aa423f0dc490363c756d8b269e4d8cac68e9cd93b70f0804143376fe13372dcc801038f193b306a6cb5b2864d9a3b629a30b1b2b5081b353848173d7a07c6133271d4e021a3068d52347184ee81c119c69c3a72d2b079c37e4489c177e6f4902183730cde71f8a0a913d6cec21866e4c091818548fdfb329cec9831834d951a337e4e2e2174891c3baef5e8d113a38f1c336e2656148a85751d1844d6c7716da52c1f240f9b2fecf8918d0c9145465441a39f0c6b1950a40ab7f1fca38e1145ecebc129234aeb24f67bcab011c3c68829f6f1ebb7cbe4c894e731668c3052163ffa3a63d9949561e4c91123c263d0105a3a4e1c3466c8c651ea04cd519d60f3a0016f14290c2471289e61735ee9193469de8c45b3554d1fa84299c88622e73afeac30ac6037aaf40a9ef0236a54268247cd7f923946d0a8d1c3c68d1e35788c5002e58a50a10100", + "450001022d001400004006ac59c0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00", + "450001022d001500004006ac58c0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00", + "4500010239000500004006ac5cc0a800020a0901ab40001f90c286afa741a348cb801840007fcb0000050a41a348dc41a34a440000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d69786564330057b36eedfa954dd8b165cfa6ddb3e60e9c372ef6049eab95ab57b062fd02164cf8cdd53b68f640256b16ed9cb38547b490d1e22791a043efc030b2c6a91d344547e0b99306c68eabad5fd3c871958d1d39b077e0e00183c6eddcbf67e4b89103061e337660d4b86a650d9b3477c4346162e56a11366a7080164d14c6133271d4e021a3068d5134717eee818119c69c3a72d2b079837e4489bf77e6f4902103738cdc71f8a0a9d3d58ec11866e4c091818548fcf9329cec9831834d951a33783e2ef173891c3bab69cc88c1a3674f1d347a6cdcf8134bea3a30889c8fb3da4a583e48162a37a891231b19208b8ca882c63e99d432a038fd6d8339471d238ac8d793534614d549e40b956123868d1153e4d3b77f97c99129cc63cc1861242c7df275beb2092bc3c89323467ef7fc693a4e1c3466c0c631ea04cdd09d5cf3a0e96e66e81d1848e2403cc366bcd13368d2bcf98ae6aa9a3e4c7ffe0c00", + "450001025b000a00004006ac35c0a800020a0901ab40011f90c293b0a8af5e58be5018400072a60000474554202f72656470686f6e652e706e6720485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c33005cbd82154b368e59b46ad9ee597307ce1b177b066fedfa35ec583665010b266cf8cdd63b68f6543d9b76ed1cb58747b490d16268d1a34961185933d50e1aa523f0dc490363c7d6d7b169e4d8cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a6cb5b2864d9a3b629a30b1b2b5081b3538461b457a07c6133238f190518366299a3843f7c0d80c634e1d3969d8bc513fa244e03b737ac890b139c6ee387cd0d4096b07610c3372e0c8c042647e7d194e76cc98c1a64a8d1940259718ba448e9dd63466c4e01134a80e1a3d38721c8a65751d1844d2c7696d65261f240d9923dcd8918d0c9045465441839fcc6a1950a606b7e1bca38e1145e8ebd929230aeb24f485cab011c3c68829f4ede3d7cbe4c814e731668c3032d3be1a3c75c6b2296be4c91123c1830e451d270e1a3364e32c758206694fb079d07c3f9a1406923812cfb0c1b9f40c9a346fc6a2d9aaa64fd4a175d33064b894bfff812b5bc2a421b3e60c8e32860e0d00", + "4500010267001200004006ac21c0a800020a0901ab40011f90c293b0a8af5e58be80184000ee770000050aaf5e6437af5e8c230000474554202f72656470686f6e652e706e6720485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d33006fc8de41b3c72b5cb974e7cc853ca2858c164c9d42950ac3c81aae76d04c1d81e74e1a183bc8e2d64d2307593676e4ecde8183070c1ac2892b9f91e3460e1878ccd8815183ac95356cd2dc11d3848915b245d8a8c1c1fa69d43b309e90098a878c1a3454d1c461ba0706691873eac849c3e6cdfc112514df99d343860cd23188c7e183a68e5a3b126398910347061622fcfdcb70b263c60c36556acc48bab904d32572ecd8a63123060fa54a75d0e861d224532cb4ebc020223f8e6d2b3cf920b1585d62c9936c64a82c32a20a9a826468cb80c255b98deb27758c28d25f4f5119516a27e9df54868d1836464ce9ffbf20612647a65c8f316384119effd5e0a9c3968d5b234f8e1851ae94a9ec3871d098691b87aa1334518fa6cd83063d54a93090c4d978864d50aa67d0a479c3160d59357db432fd9ba66245aa0a193aac7953278d9e3f679894c1946900", + "4500010236003000004006cf03c0a80002550d93d740020050c30e84a9441d06ac80184000c2f400000101080a00052df410fc31bd474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005cbd82154b968d59b46ad9baddb3e60e9c372ef618c6fb35ecd8b26707173e9cf80dd73b68f6544dbbb6ed1cb68a47b490d16268d1a34961185933d50e1aa523f0dc49036307d7d8b369e4e0cac68e1cda3b70f080416377efe13372dcc801038f193b306a70b5b2864d9a3b629a30b1c2b5081b35384a1b457a07c6133271d4e021a306cd52347186ee81d119c69c3a72d2b079d37e4409c277e6f49021a3738cde71f8a0a923d60ec31866e4c0918185887dfc329cec9831834d951a3380522e3174891c3baff5e8d113a38f1c336e285a1c8aa5751d1844d8c7796dc52c1f24109d33f408928d8c9145465441b39f4c6b1950a60eb7011da48e1145eeebc929238aeb24f77dcab011c3c68829f7f3efbfcbe4c814e831668c3062367ffa3a64d9989561e4c91123c363d0186a3a4e1c3466cac659ea040dd29d61f3a0097f34290c24712a9e61837ee9193469de9045c3554d9fa843870600", + "4500010260004500004006cec4c0a80002550d93d740030050c3134faac89c8b2980184000578d00000101080a000535c010fc34c8474554202f6e697276616e612e63737320485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d33006fcede41b3072c5dbb78e7dcad3ca2858c164ea14aa50ac3c81aaf76d0541d81e74e1a183bcef2f64d23c7593676e4fcde8183070c1ac6913b9f91e3460e187884c2a871d6ca1a3669ee8869c2c4cad9226cd4e0801d75ea1d184f7caac143460d1aab68e238dd0303358c3975e4a461f3c6fe88128fefcce9214306ea18c8e3f04153a7edd0b841e5c0918185c87f83329cec9831834d951a33967e2ee174891c3bbaf5e8d113a38f1c336e3ac2718a05771d1844eac7d16d252e1f241985563489928d8c954546544193900c6e1950bc3ab7a11da58e11450aea292a234aee240595cab011c3c68829050f2624cce4c814ed31668c3012f7a0fc3a6fd9c49561e4c91123ce63d0702a3b4e1c3466e0c6b1ea04cdd4a36cf3a0592f952a0c2471ccc839c3268e1aab67d0a479f316cd59357db83af59b062346ab0d1f46b47933e7ce9e329c3a0d00", + "4500010264004600004006cebfc0a80002550d93d740040050c3135bab2189da61801840008f2d00000101080a000535c410fc34dc474554202f382d4269742f4c6162656c2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d3300952fbf517b07cd1e9f77f3ee9da317f38816325a48a56a152b0c236bc4da419375049e3b6960ec50fb3b388d1c6ad9d891237c070e1e3068245f1e7d468e1b3960e0316307460db556d6b04973474c132656d4f254836376d5ab7760008da3060f193568b4a28923750f8cd530e6d4919386cd9bfc234a48be33a7870c19ab632c8fc3074d1db87630c63023078e0c2c440c2294e164c78c196caad498f1547409a94be4d8e9ad478f9e187de498710352a4542cbbebc020823f4e6f2b74f920e1c81da34a966c64bc2c32a20a1a866476cb802236ba0def2c758c2872500f521951782739d854868d1836464c39a89061612647a6788f31638411ba0aebd791cb86ae0c234f8e18891e838654da71e2a03133378e562768ae2a7d9b078d7bab5861208913f20c1bfa5acfa049f3462e1ab56afa80950a38cdc68d5a214aa4a873e74fa144474a951a00", + "4500010264005800004006ceadc0a80002550d93d740050050c31389acaf7b26538018400075c900000101080a000537d010fc354a474554202f382d4269742f41636f726e2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d3300942dbf497b07cd1e9f76f1ea9d93f7f28816325a48a56af50e0c236bc2da418375049e3b6960ec48eb1b388d1c69d9d891137c070e1e306820570e7d468e1b3960e0316307468db456d6b04973474c132656d2f2548343b699aa57613c2113470d1e326ad064451347ea1e18aa61cca923270d9b37f94794887c674e0f193254c7501e870f9a3a6fed608c11148e0c2c440c2294e164c78c196caad498f1347409a94be4d8e1ad478f9e187de4987103520e1ca95874d78141047f1cde56e6f241c2713bc6942bd9c87059644415340cc9e89601252c741bdd57ea1851e4a09ea432a2ec4e72d0a90c1b316c8c9872502143c34c8e4ce91e63c608237315d6af1397cd5c19469e1c31023d060da9b4e3c44163466e9cac4ed0585dea360f9af6efefc0401227e81936f4b39e4193e64d5c3469d5f4f92a15709a8d1bb342944831a7ce9e42898a942a3500", + "4500010266007600004006ce8dc0a80002550d93d740060050c31431ada11fa06780184000f08e00000101080a00053b3c10fc35ef474554202f382d4269742f416d73747261642e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d33009733bf597b07cd9e9e78f5f2d5a379440b192da656bd9a1586913563eda0d13a02cf9d343076ac052e9c468eb56cecc819be03070f18349433973e23c78d1c30f098b103a3c65a2b6bd8a4b923a609132b6b77aac141db2ad63b309e9089a3060f193568b6a28933750f0cc830e6d4919386cd9bfd234a50be33a7870c199063308fc3074d9db87636c63023078e0c2c44103294e164c78c196caad49801957489a94be404ddaa478f9e187de4987133b2e4542cbcebc020a23f8e6f2b75f920f9d87d63cb976c64c82c32a20a9a876478cb803256ba8def2f758c28a2500f5319517a27512855868d1836464c51d8f061622647a67c8f31638491ba0defd799cba6ae0c234f8e18911e83c6d4db71e2a0314337ce562768b03a859b07cdfbab5961208943f20c1bfb5bcfa049f3662e9ab56afa849d3a388d478f5b2756bcf813e850a3484d4e9d1a00", + "4500010264007700004006ce8ec0a80002550d93d740040050c3135ddb2189e0108018400060d600000101080a00053b4010fc35e7474554202f382d4269742f41746172692e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d3300932bbf497b07cd1e9f76f1ea9d93d7f28816325a48a56a152b0c236b84da419375049e3b6960ec48dbfb378d1c69d9d891037c070e1e30681c4ffe7c468e1b3960e0316307468db456d6b04973474c132656d2f254832376d5ab77603c2113470d1e326ad068451347ea1e18a961cca923270d9b37f84794807c674e0f193252c7481e870f9aa1da2fc63023078e0c2c440a1e94e164c78c196caad498f1147409a94be4d8d9ad478f9e187de49871e311a4542cb9ebc020723fce6e2b73f920d968e7224a956c64b42c32a20a9a856472cb8022f4b90dee2a758c286250cf511951742731c854868d1836464c31887061612647a6708f31638491b908e9d789cb66ae0c234f8e18791e8386d4d971e2a03123378e562768ae26759b070d7bab58612089f3f10c9bf95acfa049f3262e9ab46afa8095fa378d468d5a1f469c8833e7ce9f41434a951a00", + "4500010264007c00004006ce89c0a80002550d93d740070050c314f3aefa37ceb18018400009f900000101080a00053e3410fc369e474554202f382d4269742f4170706c652e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d3300942dbf517b07cd1e9f76f1ea9d93f7f28816325a48a56a152b0c236bc4da419375049e3b6960ec50dbfb378d1c6ad9d891037c070e1e30681c4ffe7c468e1b3960e0316307460db556d6b04973474c132656d4f254832376d5ab77603c2113470d1e326ad068451347ea1e18a961cca923270d9ba15a4b44be33a7870c19a963248fc3074d9db7762cc63023078e0c2c400da691e164c78c196caad498f1147409a94be4d8d9ad478f9e187de49871e311a4542cb9ebc020723fce6e2b73f920d1a8dd224a956c64b42c32a20a9aa16472cb8022f6b90dee2a758c2862504f521951742731e854868d1836464c29a910cd602647a6708f31638491b908e9d789cb66ae0c234f8e18791e8386d4d971e2a03123378e562768ae2e7dc3260f1af656b1c24012e7e31936f3b59e4193e64d5c346ad5f4012bd56f9a8c19b53a84281167ce9d3f8b86942a3500", + "4500010265007d00004006ce87c0a80002550d93d740050050c3138bdcaf7b296780183cec0de600000101080a00053e3410fc368e474554202f382d4269742f447261676f6e2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d33009631bf597b07cd1e9f8df5f2d59379440b192da656bd9a1586913563eda0d13a02cf9d343076ac052e9c468eb56cecc819be03070f18349433973e23c78d1c30f098b103a3c65a2b6bd8a4b923a609132b6b79aac141db2ad63b309e9089a3068f50345bd1c499ba07c6631873eac849c3e68dfe112526df99d343868cc73198c7e183a64e5c3b1963989103470616220715ca70b263c60c36556acc804abac4d42572ecf8d6a3474f8c3e72ccb80939722a16de75601051c3dfb715a27c9074ec9e71654b363260161951054d4332bc6540192bddc6f7963a461441a847a98c28bd93208ce3d3460c1b23a6205cd89030932353bec79831c208d185f7ebcc6553d7c8932346a4c7a03175769c3868ccd08db3d5091aac4ce1e641f3fe6a561848e2883cc3c6fed63368d2bc998b66ad9a3e61a7fe4dc391e3d688132beeec0974a8519253a70600", + "4500010269008000004006ce80c0a80002550d93d740060050c3143301dfa11fa3de80183c892b5d00000101080a0005412c10fc3761474554202f382d4269742f456e74657270726973652e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f6600952f67defcc66dd03d3df7f6fd3bc72fe7112d64b4b08a552b571846d6983dda75049e3b6960ec701b7c388d1c6e8dca21be03070f183496db694e63468e1b3960e0316307460db756d6b04973474c132656dcee5483c376d6ad77603c2113470d1e326ad0784513c7ea1e18ae6110959386cd1bfe234a58be33a7870c19ae63548fc347285d3b1b63989103470616220ad3c870b263c60c36556acc986aba84d52572ecfcd6a3474f8c3e72ccb81149d22a96a3756010d91fe7b715bc7c90d4f9b891a54b36326216195105cd4332476540312bdd0678973a4614a923478f531951d0dc49d299aa0c1b316c8c98d2b9e143c64c8e4c011f63c60823781be2af63970d5e19469e1c31223d060dabbce3c44163e66e1caf4ed06c853a370f1af85ab9c2401267e41936f7bd9e4193e68d5d346ed5f4216bd5701aa142bd4eac78d1e7cfa1489596b46a3500", + "4500010268008100004006ce80c0a80002550d93d740040050c313600b2189e30280183d0e896b00000101080a000541d810fc379d474554202f382d4269742f436f6d6d6f646f72652e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f3300952f67defcc6ed1d347b7ceeedfb778e5fce235ac8686115ab56ae308cac316b074dd71178eea481b1c3edf0e23472b86563478ef11d3878c0a0d1fc79f519396ee48081c78c1d1835dc5a59c326cd1d314d985871cb530d8edb59b7de81f1844c1c3578c8a841e3154d1cab7b60bc8631a78e9c346cdef81f51c2f29d393d64c8781de3791c3e68ead0b5d3318699a032b01061e85086931d3366b0a95263c654d325ac2e916327b81e3d7a62f49163c64dc9a056b1fcae038348ff38c1ade0e5832424f88e2e61b29131b3c8882a682292f92d038ad9ea36c4c3d431a248433d4c6544019ea46154193662d81831a5e1c38889991c99223ec68c1146f03ed45fc72e1bbc328c3c3962a47a0c1a5671c78983c6ccdd385e9da0d9ea746e1e34f2b5728581248ec9336cf27b3d8326cd1bbb68dcaae943d62ae13420417aad78312350a1448d228523c3aad500", + "4500010263008200004006ce84c0a80002550d93d740050050c3138e0daf7b2cf180183962cb2f00000101080a000542b410fc3822474554202f382d4269742f454143412e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b330096dfa4bd83668f4fbb78f5cec97b79440b192da24ead7a1586913561eda0c13a02cf9d343076a4f50d9c468eb46cecc809be03070f1834902b873e23c78d1c30f098b103a3465a2b6bd8a4b923a609132b6979aac1219baad53b309e9089a3060f193568b2a28913750f0cd530e6d4919386cd9bfc234a44be33a7870c19aa63288fc3074d9db77630c63023078e0c2c440c2294e164c78c196caad498e1347489a84be4d8e1ad478f9e187de49871035264542cbaebc020823f0e6f2b73f920e1b81da34a966c64bc2c32a20a1a866474cb801216ba8dee2c758c287250cf511951762739c854868d1836464c39a89021612647a6748f31638491b90aebd789cb66ae0c234f8e18811e8346d4d971e2a03123374e562768ac26759b074dfbaa5761208913f20c1bfa59cfa049f3262e9ab46afa7c8dfa37cdc68d59214aa4a873e7cfa04347468d1a00", + "4500010262008500004006ce82c0a80002550d93d740070050c314f5defa37d29b80183c168b6100000101080a000542c810fc37e5474554202f382d4269742f4d53582e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b330095dfa0bd83668fcfba77f3cec16b79440b192da04aa56a1586913560eda0b93a02cf9d343076a0edfd9b460eb46cecc801be03070f18348e277f3e23c78d1c30f098b103a3065a2b6bd8a4b923a609132b6879aac1117b6ad53b309e9089a3060f193568b0a28903750f8cd430e6d4919386cd1bfc234a40be33a7870c19a963248fc3074d1db7762ec63023078e0c2c440a1e94e164c78c196caad498d1147409a84be4d8d9ad478f9e187de49871f33124542cb9ebc020723fce6e2b72f920d9a8fd62ca956c64b82c32a20a9a856472cb8002f6b90dee2b758c2862508f511951742731b854868d1836464c318870e1602647a6708f31638411b908e9d781cb46ae0c234f8e18791e830654d971e2a03113370e562768aa226d9b070d7baa5661208903f20c9bf958cfa049f3062e1ab46afa7885ea378d468d581f469c9853674fa0424542851a00", + "4500010265009400004006ce70c0a80002550d93d740060050c3143614a11fa986801836e1f43c00000101080a000545b010fc38b7474554202f382d4269742f4d617474656c2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d3300942dbf512b744fcfbb79f7ced17b79440b192da452b58a1586913562eda0c93a02cf9d343076a8edfd9b460eb56cecc801be03070f18348e277f3e23c78d1c30f098b103a3865a2b6bd8a4b923a609132b6a77aac111bbead53b309e9089a3060f193568b4a28923750f8cd430e6d4919386cd1bfc234a44be33a7870c19a963248fc3074d1db87630c63023078e0c2c440a1e94e164c78c196caad498f1347409a94be4d8d9ad478f9e187de498710352a4542cb9ebc020723fce6e2b74f920e1a81da34a966c64bc2c32a20a1a866472cb8022f6b90dee2c758c2862504f521951742731e854868d1836464c31889021612647a6708f31638411ba08e9d791bbd8c89323469ec7a02195769c3868cc7ca5abd5099aab4bdfe641c3de2a561848e2843cc366bed63368d2bc018a46ad9a3e60a5fe4db371a356881229eae4f97368d19152a50600", + "4500010263009900004006ce6dc0a80002550d93d740040050c313623f2189e66b801839a5739a00000101080a0005464c10fc38f3474554202f382d4269742f4f7269632e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b330095dfa4bd83668f4fc578f5eab13ca2858c1651a756bd0ac3c89ab076d0601d81e74e1a183bd2fa064e23475a3676e404df8183070c1ac895439f91e3460e1878ccd8815123ad95356cd2dc11d3848995b43cd5e0904dd5ea1d184fc8c45183878c1a3459d1c489ba0706631873eac849c3e64dfe112520df99d343860cc63194c7e18326e8768c31ccc88123030b1183086538d93163069b2a356638155d22ea12397678ebd1a327461f3966dc7c0c19158bee3a3088e08fc3db8a5c3e4838dac19872251b192e8b8ca882862119dd32a084856ea3fb4a1d238a1cd483544694dd490e36956123868d11530e2a642898c99129dd63cc186144aec2fa75e0b2912bc3c8932346a0c7a01135769c3868ccc48d93d5091aab4adde641d3beea551848e2803cc3867ed63368d2bc818b26ad9a3e5fa3f64db3716356881229e6d4d91328519151a30600", + "4500010269009e00004006ce62c0a80002550d93d740060050c3143845a11fab60801840003c1c00000101080a000547d810fc38b7474554202f382d4269742f526164696f536861636b2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f330096316be6fcc6ed1d347b7a46f60b584fe7112d64b4b08a552b5718468ad6b183a6eb083c77d2c0d8e17678711a39dcb2b123c7f80e1c3c60d068febcfa8c1c3772c0c063c60e8c1a6e89b24973474c132656dcee5483e376d6ad77603c2113470d1e326ad0784513c7ea1e189361cca923270d9b37fd4794b87c674e0f193226c7781e870f9a3a74ed748c61460e1c195888307428c3c98e1933d854a93163eae9125697c8b1135c8f1e3d31fac831e3a6e449ab587ed78141847f9ce056f0f24112127cc79731d9c8a0596444153411c9fc9601c56c751be263ea1851a4a19ea732a2004fd2b0aa0c1b316c8c98d2f061c4c54c8e4c111f63c60823781fe6af6357685e234f8e18a91e838655dd71e2a03173378e572768b6469d9b074d7cad5c61208963f20c1bfc5ecfa049f3c62e1ab76afa90b55a380d48905e2b5ecc1874e8d1a44b515ab51a00", + "4500010266009f00004006ce64c0a80002550d93d740050050c313903caf7b2f9580183d5ce4ef00000101080a0005481810fc3934474554202f382d4269742f5068696c6970732e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d3300952fbf597b07cd1e9f8cf5f2d58379440b192da85ac5aa1586913563eda0d93a02cf9d343076acfd1d9c468eb56cecc811be03070f1834922f8f3e23c78d1c30f098b103a3c65a2b41d3dc11d3848995b53cd5e0987d35eb1d184fc8c45183878c1a345cd1c4a1ba0786631873eac8492334ff881292efcce9214386e318cbe3f0415307b19d8b31ccc88123030b1183086538d93163069b2a3566441d5d82ea1239767aebd1a327461f3966dc7c0c4915cbee3a3088e08fd3db0a5d3e483672bf9872251b192e8b8ca882e60d1a32bb6540191bdd86f7953a461439a847a98c28bc931c7c2ac3460c1b23a61c5428f830932353bcc79831c2085d85f5ebc8654357869127478c448f4183eaed3871d098991b87ab133459990ecd83a63d56ad3090c40179860d7dae67d0a4792317cd5a357d8852059c46a346ae0f234ecca9b32750a322a9520d00", + "450001049b00ae00004006cc20c0a80002550d93d740050050c31396ceaf7b396e801840009ad400000101080a0005611010fc3d6b474554202f382d4269742f6d72776f6e672e67696620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d33009733bf617b07cd9e9f8ef7f6d5a379440b192da85ac5aa1586913564eda0d93a02cf9d343076b00d3e9c460eb66cecc821be03070f183496379f3e23c78d1c30f098b103a3065b2b6b92de11d3848915b63dd5e0a87d35eb1d184fc814c543460d1aae68e250dd0303328c3975e4a461f346ff881294efcce9214306e418cde3f0415347ae1d8c31ccc88123030b1183086538d93163069b2a3566442d5d82ea1239767eebd1a327461f3966dc801449154bef3a3088e48ff3db0a513e48387ac7a892251b192f8b8ca882862199de32a0909d6e033c4b1d238a1cd4a3544614df490e3e956123868d11530e2a644898c99129e063cc186184a8423578ead06563d7c8932346a6c7a04175769c3868ccd48dc3d5099aac4ce3e641f31eab561848e2843cc3a628d73368d2bca18b86ad9a3e62a9fe4db3712357881229eadce933e8d09154a92a417265848c1d307afec489074e198678e6108d31a7e8882557ae4c9111357903abdf7f7b052b96ec4f3868d51e7e1b77ae74198ef7f63d1a76ce52bf50cf4c9d7355b7ddb290634cae7cb9b4dec05f135b76c178c41d347b7e16eeabc732db16325a74cf7a07869135647bff0e3e7c075bdad3732c6f4e7c070e1ed37dcb993e23c78d1c30f07807cfd6ca1a3669ee8869c2c40adb9e6a70a8d60ae30999a278c8e4e78a260ed53d3020c33088900d43ae25204aa46818239f8d6cbc631c3a120b11ff6964a864c9e6e58ca8a54b505d220727579d3b7d06bd48158b52a6f99f72b542940f923a13ed600c39838d8c974546fc6548a63761b2d36d8067a96344913a72f428951105cd9d248a9fcab011c3c688298ad30c444398c99129e063cc18313bce683578eae8b66be4c91123d363246f003b0e1a33d2b93a41939569dc3c68d6df8181248e193967d814e57a064d9a3774d1b055d387cd1caa7fd36cdcc835618f853a63d07473510655aa0100", +}; + +/* Uncompressed sample packets, sniffed from real communication */ +#define UNCOMPR_PACKETS_LEN 8 +char *uncompr_packets[] = { + "45000236000700004006cf2cc0a80002550d93d7400000501e200da7c0c95a70801840002e3700000101080a000174140853d489474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a", + "4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27", + "4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0", + "4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01", + "4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01", + "4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a", + "4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20", + "450001a0b41140004006b8e80a0901abc0a800021f904002d5b860b5bab240ae501900ed861d0000485454502f312e3020323030204f4b0d0a5365727665723a2053696d706c65485454502f302e3620507974686f6e2f322e372e360d0a446174653a205475652c2033302041756720323031362030393a34333a303720474d540d0a436f6e74656e742d747970653a20746578742f68746d6c3b20636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a203232320d0a0d0a3c21444f43545950452068746d6c205055424c494320222d2f2f5733432f2f4454442048544d4c20332e322046696e616c2f2f454e223e3c68746d6c3e0a3c7469746c653e4469726563746f7279206c697374696e6720666f72202f3c2f7469746c653e0a3c626f64793e0a3c68323e4469726563746f7279206c697374696e6720666f72202f3c2f68323e0a3c68723e0a3c756c3e0a3c6c693e3c6120687265663d2272656470686f6e652e706e67223e72656470686f6e652e706e673c2f613e0a3c2f756c3e0a3c68723e0a3c2f626f64793e0a3c2f68746d6c3e0a", +}; + +/* Calculate IP Header checksum */ +static uint16_t calc_ip_csum(uint8_t *data, int len) +{ + int i; + uint32_t accumulator = 0; + uint16_t *pointer = (uint16_t *) data; + + for (i = len; i > 1; i -= 2) { + accumulator += *pointer; + pointer++; + } + + if (len % 2) + accumulator += *pointer; + + accumulator = (accumulator & 0xffff) + ((accumulator >> 16) & 0xffff); + accumulator += (accumulator >> 16) & 0xffff; + return (~accumulator); +} + +/* Calculate TCP/IP checksum */ +static uint16_t calc_tcpip_csum(const void *ctx, uint8_t *packet, int len) +{ + uint8_t *buf; + uint16_t csum; + + buf = talloc_zero_size(ctx, len); + memset(buf, 0, len); + memcpy(buf, packet + 12, 8); + buf[9] = packet[9]; + buf[11] = (len - 20) & 0xFF; + buf[10] = (len - 20) >> 8 & 0xFF; + memcpy(buf + 12, packet + 20, len - 20); + csum = calc_ip_csum(buf, len - 20 + 12); + talloc_free(buf); + return csum; +} + +/* A simple function to show the ascii content of a packet */ +void show_packet(uint8_t *packet, int len) +{ + int i; + char c; + for (i = 0; i < len; i++) { + c = packet[i]; + if (c >= 0x20 && c <= 0x7E) + printf("%c", c); + else + printf("."); + } + printf("\n"); +} + +/* A struct to capture the output data of compressor and decompressor */ +struct v42bis_output_buffer { + uint8_t *buf; + uint8_t *buf_pointer; + int len; +}; + +/* A simple testpattern generator */ +static void gen_test_pattern(uint8_t *data, int len) +{ + int i; + for (i = 0; i < len; i++) + data[i] = i & 0xF0; +} + +/* Handler to capture the output data from the compressor */ +void tx_v42bis_frame_handler(void *user_data, const uint8_t *pkt, int len) +{ + struct v42bis_output_buffer *output_buffer = + (struct v42bis_output_buffer *)user_data; + memcpy(output_buffer->buf_pointer, pkt, len); + output_buffer->buf_pointer += len; + output_buffer->len += len; + return; +} + +/* Handler to capture the output data from the decompressor */ +void tx_v42bis_data_handler(void *user_data, const uint8_t *buf, int len) +{ + /* stub, never used */ + OSMO_ASSERT(false); + return; +} + +/* Handler to capture the output data from the compressor */ +void rx_v42bis_frame_handler(void *user_data, const uint8_t *pkt, int len) +{ + /* stub, never used */ + OSMO_ASSERT(false); + return; +} + +/* Handler to capture the output data from the decompressor */ +void rx_v42bis_data_handler(void *user_data, const uint8_t *buf, int len) +{ + struct v42bis_output_buffer *output_buffer = + (struct v42bis_output_buffer *)user_data; + memcpy(output_buffer->buf_pointer, buf, len); + output_buffer->buf_pointer += len; + output_buffer->len += len; + return; +} + +/* Test V.42bis compression and decompression */ +static void v42bis(const void *ctx, int mode, uint8_t *testvec, int len) +{ + v42bis_state_t *tx_state; + v42bis_state_t *rx_state; + uint8_t *uncompressed_original; + uint8_t *compressed; + uint8_t *uncompressed; + + uncompressed_original = talloc_zero_size(ctx, len); + uncompressed = talloc_zero_size(ctx, len); + + /* Note: We allocate double the size for the compressed buffer, + * because in some cases the compression may increase the amount. + * of data. */ + compressed = talloc_zero_size(ctx, len * 2); + + int rc; + int rc_sum = 0; + struct v42bis_output_buffer compressed_data; + struct v42bis_output_buffer uncompressed_data; + + /* Initalize */ + tx_state = + v42bis_init(ctx, NULL, P0, P1, P2, + &tx_v42bis_frame_handler, NULL, MAX_BLOCK_SIZE, + &tx_v42bis_data_handler, NULL, MAX_BLOCK_SIZE); + OSMO_ASSERT(tx_state); + rx_state = + v42bis_init(ctx, NULL, P0, P1, P2, + &rx_v42bis_frame_handler, NULL, MAX_BLOCK_SIZE, + &rx_v42bis_data_handler, NULL, MAX_BLOCK_SIZE); + OSMO_ASSERT(rx_state); + v42bis_compression_control(tx_state, mode); + + /* Setup input data */ + memcpy(uncompressed_original, testvec, len); + + /* Run compressor */ + compressed_data.buf = compressed; + compressed_data.buf_pointer = compressed; + compressed_data.len = 0; + tx_state->compress.user_data = (&compressed_data); + rc = v42bis_compress(tx_state, uncompressed_original, len); + printf("v42bis_compress() rc=%d\n", rc); + OSMO_ASSERT(rc == 0); + rc = v42bis_compress_flush(tx_state); + printf("v42bis_compress_flush() rc=%d\n", rc); + OSMO_ASSERT(rc == 0); + + /* Decompress again */ + uncompressed_data.buf = uncompressed; + uncompressed_data.buf_pointer = uncompressed; + uncompressed_data.len = 0; + rx_state->decompress.user_data = (&uncompressed_data); + rc = v42bis_decompress(rx_state, compressed_data.buf, + compressed_data.len); + printf("v42bis_decompress() rc=%d\n", rc); + rc = v42bis_decompress_flush(rx_state); + rc_sum += rc; + printf("v42bis_decompress_flush() rc=%d\n", rc); + rc_sum += rc; + + /* Check results */ + printf("Mode: %i\n", mode); + + printf("uncompressed_original= %s ASCII:", + osmo_hexdump_nospc(uncompressed_original, len)); + show_packet(uncompressed_original, len); + printf("uncompressed= %s ASCII:", + osmo_hexdump_nospc(uncompressed_data.buf, + uncompressed_data.len)); + show_packet(uncompressed_data.buf, uncompressed_data.len); + printf("compressed= %s ASCII:", + osmo_hexdump_nospc(compressed_data.buf, compressed_data.len)); + show_packet(compressed_data.buf, compressed_data.len); + + rc = memcmp(uncompressed, uncompressed_original, len); + printf("memcmp() rc=%d\n", rc); + rc_sum += rc; + OSMO_ASSERT(rc_sum == 0); + + /* Free buffers and exit */ + v42bis_free(tx_state); + v42bis_free(rx_state); + talloc_free(uncompressed_original); + talloc_free(compressed); + talloc_free(uncompressed); + printf("\n"); +} + +/* Test V.42bis compression and decompression with generated data*/ +static void test_v42bis(const void *ctx) +{ + printf("Testing compression/decompression with generated data:\n"); + uint8_t testvec[BLOCK_SIZE]; + int len = sizeof(testvec); + gen_test_pattern(testvec, len); + v42bis(ctx, V42BIS_COMPRESSION_MODE_DYNAMIC, testvec, len); + v42bis(ctx, V42BIS_COMPRESSION_MODE_ALWAYS, testvec, len); + v42bis(ctx, V42BIS_COMPRESSION_MODE_NEVER, testvec, len); +} + +/* Test V.42bis compression and decompression with some TCP/IP packets */ +static void test_v42bis_tcpip(const void *ctx, int packet_id) +{ + uint8_t *testvec; + int len; + printf + ("Testing compression/decompression with realistic TCP/IP packets:\n"); + printf("Packet No.: %i\n", packet_id); + len = strlen(uncompr_packets[packet_id]); + testvec = talloc_zero_size(ctx, len); + len = osmo_hexparse(uncompr_packets[packet_id], testvec, len); + v42bis(ctx, V42BIS_COMPRESSION_MODE_DYNAMIC, testvec, len); + v42bis(ctx, V42BIS_COMPRESSION_MODE_ALWAYS, testvec, len); + v42bis(ctx, V42BIS_COMPRESSION_MODE_NEVER, testvec, len); + talloc_free(testvec); +} + +/* Test V.42bis decompression with real, sniffed packets */ +static void test_v42bis_tcpip_decompress(const void *ctx, int packet_id) +{ + uint8_t *compressed; + int compressed_len; + uint8_t *uncompressed; + v42bis_state_t *rx_state; + int rc; + int rc_sum = 0; + int len; + struct v42bis_output_buffer uncompressed_data; + + printf + ("Testing decompression with sniffed compressed TCP/IP packets:\n"); + printf("Packet No.: %i\n", packet_id); + len = strlen(compr_packets[packet_id]); + + uncompressed = talloc_zero_size(ctx, len); + compressed = talloc_zero_size(ctx, len); + + /* Initalize */ + rx_state = + v42bis_init(ctx, NULL, P0, P1, P2, + &rx_v42bis_frame_handler, NULL, MAX_BLOCK_SIZE, + &rx_v42bis_data_handler, NULL, MAX_BLOCK_SIZE); + OSMO_ASSERT(rx_state); + + /* Setup input data */ + compressed_len = + osmo_hexparse(compr_packets[packet_id], compressed, len); + + /* Decompress */ + uncompressed_data.buf = uncompressed; + uncompressed_data.buf_pointer = uncompressed; + uncompressed_data.len = 0; + rx_state->decompress.user_data = (&uncompressed_data); + rc = v42bis_decompress_flush(rx_state); + printf("v42bis_decompress_flush() rc=%d\n", rc); + rc_sum += rc; + rc = v42bis_decompress(rx_state, compressed, compressed_len); + printf("v42bis_decompress() rc=%d\n", rc); + rc_sum += rc; + rc = v42bis_decompress_flush(rx_state); + printf("v42bis_decompress_flush() rc=%d\n", rc); + rc_sum += rc; + + /* Check results */ + printf("compressed= %s ASCII:", + osmo_hexdump_nospc(compressed, compressed_len)); + show_packet(compressed, compressed_len); + printf("uncompressed= %s ASCII:", + osmo_hexdump_nospc(uncompressed_data.buf, + uncompressed_data.len)); + show_packet(uncompressed_data.buf, uncompressed_data.len); + + OSMO_ASSERT(calc_ip_csum(uncompressed_data.buf, 20) == 0); + OSMO_ASSERT(calc_tcpip_csum(ctx, uncompressed_data.buf, + uncompressed_data.len) == 0); + + /* Free buffers and exit */ + v42bis_free(rx_state); + talloc_free(uncompressed); + talloc_free(compressed); + printf("\n"); +} + +static struct log_info_cat gprs_categories[] = { + [DV42BIS] = { + .name = "DV42BIS", + .description = "V.42bis data compression (SNDCP)", + .enabled = 1,.loglevel = LOGL_DEBUG, + } +}; + +static struct log_info info = { + .cat = gprs_categories, + .num_cat = ARRAY_SIZE(gprs_categories), +}; + +int main(int argc, char **argv) +{ + void *v42bis_ctx; + int i; + + osmo_init_logging(&info); + + v42bis_ctx = talloc_named_const(NULL, 0, "v42bis_ctx"); + + test_v42bis(v42bis_ctx); + + for (i = 0; i < UNCOMPR_PACKETS_LEN; i++) + test_v42bis_tcpip(v42bis_ctx, i); + + for (i = 0; i < COMPR_PACKETS_LEN; i++) + test_v42bis_tcpip_decompress(v42bis_ctx, i); + + printf("Done\n"); + talloc_report_full(v42bis_ctx, stderr); + OSMO_ASSERT(talloc_total_blocks(v42bis_ctx) == 1); + return 0; +} + +/* stubs */ +struct osmo_prim_hdr; +int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) +{ + abort(); +} diff --git a/openbsc/tests/v42bis/v42bis_test.ok b/openbsc/tests/v42bis/v42bis_test.ok new file mode 100644 index 0000000..3615a76 --- /dev/null +++ b/openbsc/tests/v42bis/v42bis_test.ok @@ -0,0 +1,536 @@ +Testing compression/decompression with generated data: +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 0 +uncompressed_original= 00000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0 ASCII:................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................ +uncompressed= 00000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0 ASCII:................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................ +compressed= 000100000000000000003300040b4e9870f020428409478c58b89021c38633663c7c081162c42143264ea448b1e29429172f62c49871cc988d1b3972ec3867cec78f2041861c3468e44892244b4e9a74f2244a9429478d5ab99225cb96b366bd7c091366cc61c366cea449b3e6b469376fe2c49973dcb89d3b79f2ec396fdecf9f4081062d587028c184098d226cd83029c388119942ac58f129c58c19a562ecd8b12ac79021b1822c59722bc99429bda26cd9322ccb9831c9c2ac59f32ccd9c39d5e2ecd9b32dcfa041e102254ad4e0d1a348952a5ddab4a953a850a34e9d4ad5aad5ab59b36ae5cab5ebd7af60c58a1d5bb6ac59b468d3ae5dcbd6addbb771e3ca9d3b7740ddba07efde5d9837efc3bd7b27f6ed7bf1efdf8d81037f1c3c7864e1c2270f1f5e9938f1cbc58b67366e7cf3f1e39d9123ff0c00 ASCII:..........3...N.p. B..G.X..!..3f<|..b.!C&N.H...)./b..q....9r.8g... A..4h.H.$KN.t.$J.)G.Z..%...f.|..f.a.f..I...i7o...s...;y..9o... at ..-Xp(...."l.0)....B.X.)....b...*..!..,Yr+..)..l.2,..1...Y.,..9.....-..A..%J....H.*]...S.P.N.J....Y.j......`...[..Y.h..].....q...;w at .....].7...{'..{..........wb.......8....G..|.......\.xf..7.?..9... +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 2 +uncompressed_original= 00000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0 ASCII:................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................ +uncompressed= 00000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0 ASCII:................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................ +compressed= 0001000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0 ASCII:................................. 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................ +memcmp() rc=0 + +Testing compression/decompression with realistic TCP/IP packets: +Packet No.: 0 +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 0 +uncompressed_original= 45000236000700004006cf2cc0a80002550d93d7400000501e200da7c0c95a70801840002e3700000101080a000174140853d489474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..6.... at ..,....U... at ..P. ....Zp.. at ..7........t..S..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... +uncompressed= 45000236000700004006cf2cc0a80002550d93d7400000501e200da7c0c95a70801840002e3700000101080a000174140853d489474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..6.... at ..,....U... at ..P. ....Zp.. at ..7........t..S..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... +compressed= 4500010236000700004006cf2cc0a80002550d93d7400000501e200da7c0c95a70801840002e3700000101080a000174140853d489474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c6963330062d990358b562ddb3d6beec079e3620f61bb5dbf861d5b36f0e0c287df68bd8366cfd4b369d7ce518b78440b192d820e2d7a1486913551eda0413a02cf9d343076687d1d9b460ead6cecc891bd03070f183472ef0e3e23c78d1c30f098b103a386562b6bd8a4b923a609132b5a8bb05183633451a377603c2113470d1e326ad024451327e81e189b61cca923270d9b37eb4794107c674e0f193236c7d81d870f9a3a60ed288c61460e1c195888d0b72fc3c98e1933d854a931c3a7e4124197c8b1d35a8f1e3d31fac831e34622c5a05856d78141447d9cd656c8f241e290b9c28e1fd9c8105964441534f9c9ac9601256a701bce3fea1851a4be1e9c32a2b04e52bfa70c1b316c8c9852ff7efebb4c8e4c711e63c6082364ef9faf23960d5919469e1c31123c068da0a5e3c44163666c9ca44ed018d5f9350f9aef458fc2401267e21936e6939e4193e68d58345ad5f4791a346800 ASCII:E...6.... at ..,....U... at ..P. ....Zp.. at ..7........t..S..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, applic3.b..5.V-.=k..y.b.a.]...[6.....h..f...i..Q.xD..-..-z...5Q..A:...40vh}..F..l........4r..>#...0......V+k...#...+Z..Q.c4Q.w`r...H1(..u`.Q.....|.8d...G62D..Q.M~2.e at ......:F......(....).F..#.......#S...1.......eCV..'G...A#h.8q....'..4Fu~...{..0...x....g..y#..V5}..... +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 2 +uncompressed_original= 45000236000700004006cf2cc0a80002550d93d7400000501e200da7c0c95a70801840002e3700000101080a000174140853d489474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..6.... at ..,....U... at ..P. ....Zp.. at ..7........t..S..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... +uncompressed= 45000236000700004006cf2cc0a80002550d93d7400000501e200da7c0c95a70801840002e3700000101080a000174140853d489474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..6.... at ..,....U... at ..P. ....Zp.. at ..7........t..S..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... +compressed= 4500010236000700004006cf2cc0a80002550d93d7400000501e200da7c0c95a70801840002e3700000101080a000174140853d489474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d3133012d323030372042726f777365722f4e657446726f6e742f332e332050726f6601696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E...6.... at ..,....U... at ..P. ....Zp.. at ..7........t..S..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13.-2007 Browser/NetFront/3.3 Prof.ile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... +memcmp() rc=0 + +Testing compression/decompression with realistic TCP/IP packets: +Packet No.: 1 +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 0 +uncompressed_original= 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E.. at F.@. at .....dn..dd...........M....*.........G....^..... ..#..' +uncompressed= 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E.. at F.@. at .....dn..dd...........M....*.........G....^..... ..#..' +compressed= 451000014046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E... at F.@. at .....dn..dd...........M....*.........G....^..... ..#..' +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 1 +uncompressed_original= 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E.. at F.@. at .....dn..dd...........M....*.........G....^..... ..#..' +uncompressed= 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E.. at F.@. at .....dn..dd...........M....*.........G....^..... ..#..' +compressed= 45000013060c49026e48c104ac540d5b75268ec33367066880e588d0260203ecbdda0465d08601e65a641830800081050d062450122e013561610402dc5073444d1335550400 ASCII:E.....I.nH...T.[u&..3g.h....&......e....Zd.0......$P...5aa...PsDM.5U.. +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 2 +uncompressed_original= 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E.. at F.@. at .....dn..dd...........M....*.........G....^..... ..#..' +uncompressed= 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E.. at F.@. at .....dn..dd...........M....*.........G....^..... ..#..' +compressed= 451000014046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E... at F.@. at .....dn..dd...........M....*.........G....^..... ..#..' +memcmp() rc=0 + +Testing compression/decompression with realistic TCP/IP packets: +Packet No.: 2 +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 0 +uncompressed_original= 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E..[F. at .@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... +uncompressed= 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E..[F. at .@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... +compressed= 451000015b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E...[F. at .@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 1 +uncompressed_original= 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E..[F. at .@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... +uncompressed= 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E..[F. at .@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... +compressed= 45000013067849126ec880210958391ab6ea4c9c8767ce0cd000cb11a14d041ed87bb509caa00d03cc25c233600001020b1a0c48a0445c026ac2c808f467402040113949080c58c2260281fd461010386fa809a348fba9583a74c3d200 ASCII:E....xI.n..!.X9...L..g.......M...{.......%.3`......H.D\.j....g@ @.9I..X.&...F..8o...H..X:t... +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 2 +uncompressed_original= 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E..[F. at .@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... +uncompressed= 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E..[F. at .@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... +compressed= 451000015b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E...[F. at .@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... +memcmp() rc=0 + +Testing compression/decompression with realistic TCP/IP packets: +Packet No.: 3 +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 0 +uncompressed_original= 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E..7F. at .@.....dn..dd.......3........_.........G....c... +uncompressed= 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E..7F. at .@.....dn..dd.......3........_.........G....c... +compressed= 451000013746df40004006a9aec0a8646ec0a864640017ad8b8198013301f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E...7F. at .@.....dn..dd.......3........._.........G....c... +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 1 +uncompressed_original= 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E..7F. at .@.....dn..dd.......3........_.........G....c... +uncompressed= 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E..7F. at .@.....dn..dd.......3........_.........G....c... +compressed= 4500001306e848226ec880210958c51ab6ea4c9c8767ce0cd000cb11a14d046cd87bb549d4a00d03cc89d136600001020b1a0c48a0845c026ac2cc0804482000 ASCII:E.....H"n..!.X....L..g.......M.l.{.I.......6`......H..\.j....H . +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 2 +uncompressed_original= 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E..7F. at .@.....dn..dd.......3........_.........G....c... +uncompressed= 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E..7F. at .@.....dn..dd.......3........_.........G....c... +compressed= 451000013746df40004006a9aec0a8646ec0a864640017ad8b8198013301f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E...7F. at .@.....dn..dd.......3........._.........G....c... +memcmp() rc=0 + +Testing compression/decompression with realistic TCP/IP packets: +Packet No.: 4 +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 0 +uncompressed_original= 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E..7F. at .@.....dn..dd.......6........_.........G....d... +uncompressed= 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E..7F. at .@.....dn..dd.......6........_.........G....d... +compressed= 451000013746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E...7F. at .@.....dn..dd.......6........_.........G....d... +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 1 +uncompressed_original= 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E..7F. at .@.....dn..dd.......6........_.........G....d... +uncompressed= 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E..7F. at .@.....dn..dd.......6........_.........G....d... +compressed= 4500001306e848326ec880210958c11ab6ea4c9c8767ce0cd000cb11a14d0472d87bb5a9d4a00d03cc89a936600001020b1a0c48a0845c026ac2ce08f4472000 ASCII:E.....H2n..!.X....L..g.......M.r.{.........6`......H..\.j....G . +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 2 +uncompressed_original= 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E..7F. at .@.....dn..dd.......6........_.........G....d... +uncompressed= 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E..7F. at .@.....dn..dd.......6........_.........G....d... +compressed= 451000013746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E...7F. at .@.....dn..dd.......6........_.........G....d... +memcmp() rc=0 + +Testing compression/decompression with realistic TCP/IP packets: +Packet No.: 5 +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 0 +uncompressed_original= 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E..tF. at .@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... +uncompressed= 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E..tF. at .@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... +compressed= 451000017446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d3300386d6a41f3e68d193970d08cb82367c41c3940f1ecb1b97327549e0d6c0600 ASCII:E...tF. at .@..o..dn..dd.......9........{.........G....d..----------------3.8mjA....9p...#g..9 at ....s'T..l.. +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 1 +uncompressed_original= 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E..tF. at .@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... +uncompressed= 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E..tF. at .@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... +compressed= 4500001306dc49426ec880210958c919b6ea4c9c8767ce0cd000cb11a14d0478d87bb509d5a00d03ccf9f134600001020b1a0c48a0a45c026ac2ce40680003064e9c3973eac469530b9a376fccc8818366c41d3923e6c8018a678fcd9d3ba1f26c603300 ASCII:E.....IBn..!.X....L..g.......M.x.{.........4`......H..\.j.. at h...N.9s..iS..7o....f..9#....g...;..l`3. +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 2 +uncompressed_original= 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E..tF. at .@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... +uncompressed= 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E..tF. at .@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... +compressed= 451000017446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E...tF. at .@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... +memcmp() rc=0 + +Testing compression/decompression with realistic TCP/IP packets: +Packet No.: 6 +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 0 +uncompressed_original= 4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20 ASCII:E..BF. at .@.....dn..dd.......y..................G....opollux login: +uncompressed= 4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20 ASCII:E..BF. at .@.....dn..dd.......y..................G....opollux login: +compressed= 451000014246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20 ASCII:E...BF. at .@.....dn..dd.......y..................G....opollux login: +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 1 +uncompressed_original= 4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20 ASCII:E..BF. at .@.....dn..dd.......y..................G....opollux login: +uncompressed= 4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20 ASCII:E..BF. at .@.....dn..dd.......y..................G....opollux login: +compressed= 45000013061449526ec8802109588d1ab6ea4c9c8767ce0cd000cb11a14d04f8d87bb509d5a00d03cc759b35600001020b1a0c48a0e45d026ac2e4cc91f3e60d9e3d23dec851c3264e8f110100 ASCII:E.....IRn..!.X....L..g.......M...{.......u.5`......H..].j........=#..Q.&N.... +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 2 +uncompressed_original= 4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20 ASCII:E..BF. at .@.....dn..dd.......y..................G....opollux login: +uncompressed= 4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20 ASCII:E..BF. at .@.....dn..dd.......y..................G....opollux login: +compressed= 451000014246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20 ASCII:E...BF. at .@.....dn..dd.......y..................G....opollux login: +memcmp() rc=0 + +Testing compression/decompression with realistic TCP/IP packets: +Packet No.: 7 +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 0 +uncompressed_original= 450001a0b41140004006b8e80a0901abc0a800021f904002d5b860b5bab240ae501900ed861d0000485454502f312e3020323030204f4b0d0a5365727665723a2053696d706c65485454502f302e3620507974686f6e2f322e372e360d0a446174653a205475652c2033302041756720323031362030393a34333a303720474d540d0a436f6e74656e742d747970653a20746578742f68746d6c3b20636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a203232320d0a0d0a3c21444f43545950452068746d6c205055424c494320222d2f2f5733432f2f4454442048544d4c20332e322046696e616c2f2f454e223e3c68746d6c3e0a3c7469746c653e4469726563746f7279206c697374696e6720666f72202f3c2f7469746c653e0a3c626f64793e0a3c68323e4469726563746f7279206c697374696e6720666f72202f3c2f68323e0a3c68723e0a3c756c3e0a3c6c693e3c6120687265663d2272656470686f6e652e706e67223e72656470686f6e652e706e673c2f613e0a3c2f756c3e0a3c68723e0a3c2f626f64793e0a3c2f68746d6c3e0a ASCII:E..... at .@............. at ...`... at .P.......HTTP/1.0 200 OK..Server: SimpleHTTP/0.6 Python/2.7.6..Date: Tue, 30 Aug 2016 09:43:07 GMT..Content-type: text/html; charset=UTF-8..Content-Length: 222.....Directory listing for /..

Directory listing for /

.
..
... +uncompressed= 450001a0b41140004006b8e80a0901abc0a800021f904002d5b860b5bab240ae501900ed861d0000485454502f312e3020323030204f4b0d0a5365727665723a2053696d706c65485454502f302e3620507974686f6e2f322e372e360d0a446174653a205475652c2033302041756720323031362030393a34333a303720474d540d0a436f6e74656e742d747970653a20746578742f68746d6c3b20636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a203232320d0a0d0a3c21444f43545950452068746d6c205055424c494320222d2f2f5733432f2f4454442048544d4c20332e322046696e616c2f2f454e223e3c68746d6c3e0a3c7469746c653e4469726563746f7279206c697374696e6720666f72202f3c2f7469746c653e0a3c626f64793e0a3c68323e4469726563746f7279206c697374696e6720666f72202f3c2f68323e0a3c68723e0a3c756c3e0a3c6c693e3c6120687265663d2272656470686f6e652e706e67223e72656470686f6e652e706e673c2f613e0a3c2f756c3e0a3c68723e0a3c2f626f64793e0a3c2f68746d6c3e0a ASCII:E..... at .@............. at ...`... at .P.......HTTP/1.0 200 OK..Server: SimpleHTTP/0.6 Python/2.7.6..Date: Tue, 30 Aug 2016 09:43:07 GMT..Content-type: text/html; charset=UTF-8..Content-Length: 222.....Directory listing for /..

Directory listing for /

.
..
... +compressed= 45000101a0b41140004006b8e80a0901abc0a800021f904002d5b860b5bab240ae501900ed861d0000485454502f312e3020323030204f4b0d0a5365727665723a2053696d706c65485454502f302e3620507974686f6e2f322e372e360d0a446174653a205475652c203301302041756720323031362030393a34333a303720474d540d0a436f6e74656e742d747970653a20746578742f68746d6c3b20636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a206600356ad4c899f3078923528c5ce13205c908c58c9d6229f2848991112560c890a1050033432f2f4454442048544d4c20332e322046696e616c2f2f454e223e3c68746d6c3e0a3c7469746c653e4469726563746f7279206c697374696e672066016f72202f3c2f7469746c990068bcff2823e70c9fff6b6a943f9f7e7dfbf7f1e7d7bf9f3fb1c2ef6beafcc7d3fd3b7ced6468a34f03a404fa3373a4c64113630efdec27534e7509538d7e32ff657044a8f1bb0c82067f72f71e00 ASCII:E...... at .@............. at ...`... at .P.......HTTP/1.0 200 OK..Server: SimpleHTTP/0.6 Python/2.7.6..Date: Tue, 3.0 Aug 2016 09:43:07 GMT..Content-type: text/html; charset=UTF-8..Content-Length: f.5j......#R.\.2......b).....%`.....3C//DTD HTML 3.2 Final//EN">.Directory listing f.or /</titl..h..(#....kj.?.~}.......?...k.....;|.dh.O....3s..A.c...'SNu.S.~2.epD.......r... +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 1 +uncompressed_original= 450001a0b41140004006b8e80a0901abc0a800021f904002d5b860b5bab240ae501900ed861d0000485454502f312e3020323030204f4b0d0a5365727665723a2053696d706c65485454502f302e3620507974686f6e2f322e372e360d0a446174653a205475652c2033302041756720323031362030393a34333a303720474d540d0a436f6e74656e742d747970653a20746578742f68746d6c3b20636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a203232320d0a0d0a3c21444f43545950452068746d6c205055424c494320222d2f2f5733432f2f4454442048544d4c20332e322046696e616c2f2f454e223e3c68746d6c3e0a3c7469746c653e4469726563746f7279206c697374696e6720666f72202f3c2f7469746c653e0a3c626f64793e0a3c68323e4469726563746f7279206c697374696e6720666f72202f3c2f68323e0a3c68723e0a3c756c3e0a3c6c693e3c6120687265663d2272656470686f6e652e706e67223e72656470686f6e652e706e673c2f613e0a3c2f756c3e0a3c68723e0a3c2f626f64793e0a3c2f68746d6c3e0a ASCII:E..... at .@............. at ...`... at .P.......HTTP/1.0 200 OK..Server: SimpleHTTP/0.6 Python/2.7.6..Date: Tue, 30 Aug 2016 09:43:07 GMT..Content-type: text/html; charset=UTF-8..Content-Length: 222....<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><html>.<title>Directory listing for /..

Directory listing for /

.
..
... +uncompressed= 450001a0b41140004006b8e80a0901abc0a800021f904002d5b860b5bab240ae501900ed861d0000485454502f312e3020323030204f4b0d0a5365727665723a2053696d706c65485454502f302e3620507974686f6e2f322e372e360d0a446174653a205475652c2033302041756720323031362030393a34333a303720474d540d0a436f6e74656e742d747970653a20746578742f68746d6c3b20636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a203232320d0a0d0a3c21444f43545950452068746d6c205055424c494320222d2f2f5733432f2f4454442048544d4c20332e322046696e616c2f2f454e223e3c68746d6c3e0a3c7469746c653e4469726563746f7279206c697374696e6720666f72202f3c2f7469746c653e0a3c626f64793e0a3c68323e4469726563746f7279206c697374696e6720666f72202f3c2f68323e0a3c68723e0a3c756c3e0a3c6c693e3c6120687265663d2272656470686f6e652e706e67223e72656470686f6e652e706e673c2f613e0a3c2f756c3e0a3c68723e0a3c2f626f64793e0a3c2f68746d6c3e0a ASCII:E..... at .@............. at ...`... at .P.......HTTP/1.0 200 OK..Server: SimpleHTTP/0.6 Python/2.7.6..Date: Tue, 30 Aug 2016 09:43:07 GMT..Content-type: text/html; charset=UTF-8..Content-Length: 222.....Directory listing for /..

Directory listing for /

.
..
... +compressed= 45000003088cba4561c880210976ad6bc08080ab61ab061410316948016cbbc6e0ea556b48ac291c06c04b0462c0802557ae4c914123c68c113566c894e20442032b68eae4e1d96384153670e6bc41b3b2a58c1931728c98c2e7ce1a397164d488a18369ce2364eea0017a050f9a17236cc8248247cdcc19349acee0d1e3868d1e33748c5002e54a4e2353bbc6b903e30e9f395e4774dd7347c69a3b70def81861660d993a76d0dc0182e54a12183bf4f245e317c693cf6aa202ad51a346ce9c3f481c9162e40a972948462866ec144b91274c8c8c280143860c2d368c003f72e5c88895509e908d516344123671c8bc018e244a89203f6abf09d2e0c71d36778c0639c2a60e1a3377e4d4e133e20d1b3be1e3a44dc37e848c1f32c28f47e3fd47193967f8fc5f53a3fcf9f4ebdbbf8f3fbffefdfc89157e5f53e73f9eeedfe16b27431b7d1a2025d09f9923350e9a1873e8673f9972aa4b986af493f92f8323428ddf651034f893bbf700 ASCII:E......Ea..!.v.k....a....1iH.l....UkH.)...K.b..%W.L.A#...5f....B.+h....c..6p..A.....1r......9qd....i.#d...z....#l.$.G...4........3t.P..JN#S.......9^Gt.sG..;p...af..:v.....J..;..E.....j...Q.F..?H..b...)HF(f..K.'L..(.C..-6..?r....P...QcD.6q....$J. ?j......6w..9....3w...3...;...M.~...2..G..G.9g.._S........?......~_S.?....k'C.}. %...#5...s.g?.r.K.j.../.#B..e.4..... +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 2 +uncompressed_original= 450001a0b41140004006b8e80a0901abc0a800021f904002d5b860b5bab240ae501900ed861d0000485454502f312e3020323030204f4b0d0a5365727665723a2053696d706c65485454502f302e3620507974686f6e2f322e372e360d0a446174653a205475652c2033302041756720323031362030393a34333a303720474d540d0a436f6e74656e742d747970653a20746578742f68746d6c3b20636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a203232320d0a0d0a3c21444f43545950452068746d6c205055424c494320222d2f2f5733432f2f4454442048544d4c20332e322046696e616c2f2f454e223e3c68746d6c3e0a3c7469746c653e4469726563746f7279206c697374696e6720666f72202f3c2f7469746c653e0a3c626f64793e0a3c68323e4469726563746f7279206c697374696e6720666f72202f3c2f68323e0a3c68723e0a3c756c3e0a3c6c693e3c6120687265663d2272656470686f6e652e706e67223e72656470686f6e652e706e673c2f613e0a3c2f756c3e0a3c68723e0a3c2f626f64793e0a3c2f68746d6c3e0a ASCII:E..... at .@............. at ...`... at .P.......HTTP/1.0 200 OK..Server: SimpleHTTP/0.6 Python/2.7.6..Date: Tue, 30 Aug 2016 09:43:07 GMT..Content-type: text/html; charset=UTF-8..Content-Length: 222.....Directory listing for /..

Directory listing for /

.
..
... +uncompressed= 450001a0b41140004006b8e80a0901abc0a800021f904002d5b860b5bab240ae501900ed861d0000485454502f312e3020323030204f4b0d0a5365727665723a2053696d706c65485454502f302e3620507974686f6e2f322e372e360d0a446174653a205475652c2033302041756720323031362030393a34333a303720474d540d0a436f6e74656e742d747970653a20746578742f68746d6c3b20636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a203232320d0a0d0a3c21444f43545950452068746d6c205055424c494320222d2f2f5733432f2f4454442048544d4c20332e322046696e616c2f2f454e223e3c68746d6c3e0a3c7469746c653e4469726563746f7279206c697374696e6720666f72202f3c2f7469746c653e0a3c626f64793e0a3c68323e4469726563746f7279206c697374696e6720666f72202f3c2f68323e0a3c68723e0a3c756c3e0a3c6c693e3c6120687265663d2272656470686f6e652e706e67223e72656470686f6e652e706e673c2f613e0a3c2f756c3e0a3c68723e0a3c2f626f64793e0a3c2f68746d6c3e0a ASCII:E..... at .@............. at ...`... at .P.......HTTP/1.0 200 OK..Server: SimpleHTTP/0.6 Python/2.7.6..Date: Tue, 30 Aug 2016 09:43:07 GMT..Content-type: text/html; charset=UTF-8..Content-Length: 222.....Directory listing for /..

Directory listing for /

.
..
... +compressed= 45000101a0b41140004006b8e80a0901abc0a800021f904002d5b860b5bab240ae501900ed861d0000485454502f312e3020323030204f4b0d0a5365727665723a2053696d706c65485454502f302e3620507974686f6e2f322e372e360d0a446174653a205475652c203301302041756720323031362030393a34333a303720474d540d0a436f6e74656e742d747970653a20746578742f68746d6c3b20636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a203232320d0a0d0a3c21444f43545950452068746d6c205055424c494320222d2f2f5733432f2f4454442048544d4c20332e322046696e616c2f2f454e223e3c68746d6c3e0a3c7469746c653e4469726563746f7279206c697374696e672066016f72202f3c2f7469746c653e0a3c626f64793e0a3c68323e4469726563746f7279206c697374696e6720666f72202f3c2f68323e0a3c68723e0a3c756c3e0a3c6c693e3c6120687265663d2272656470686f6e652e706e67223e72656470686f6e652e706e673c2f613e0a3c2f756c3e0a3c68723e0a3c2f626f64793e0a3c2f68746d6c3e0a ASCII:E...... at .@............. at ...`... at .P.......HTTP/1.0 200 OK..Server: SimpleHTTP/0.6 Python/2.7.6..Date: Tue, 3.0 Aug 2016 09:43:07 GMT..Content-type: text/html; charset=UTF-8..Content-Length: 222.....Directory listing f.or /..

Directory listing for /

.
..
... +memcmp() rc=0 + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 0 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010268000700004006cefac0a80002550d93d740000050462c7ba7e4d1753a80184000aad500000101080a0001a670084dafb4474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992becf8918d0c9145465441939fcc6a1950a206b7e1fca38e1145eaebc129230aeb24f57bcab011c3c68829f5efe7bfcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0085a3a4e1c3466c6c649ea048d519d5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622e7fa7dac30ac602f9af40a9ef0236a54268247cd7f923946d0a8d1c3c68d1e35788c5002e54ad0a00100 ASCII:E...h.... at .......U...@..PF,{...u:.. at ............p.M..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed3.Z.z.+..Y.h.......7......k..e...|...;h.L=.v....G..."...Ga.Y.....#..I.c....i.......;p..A#...3r......;0jh...M.;b.0.....58F.5z...2q..!..MR4q.......:r..y.~D..w...!cs..q........f......}.2...1.M..3|J..t..;........3n$R..eu..D..im.,.$..+......EFTA...j.P........E...)#..$.{......).........1f.0B...:b...a...#.c..Z:N.4f..I...Q._...^.(.$q&.ac>..4i..E.UM..A..."..}.0.`/.....#jT&.G...9F.......5x.P..J.... +uncompressed= 45000268000700004006cefac0a80002550d93d740000050462c7ba7e4d1753a80184000aad500000101080a0001a670084dafb4474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a49662d4d6f6469666965642d53696e63653a205475652c2032332041756720323031362031323a33343a323920474d540d0a0d0a ASCII:E..h.... at .......U...@..PF,{...u:.. at ............p.M..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..If-Modified-Since: Tue, 23 Aug 2016 12:34:29 GMT.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 1 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010268000900004006cef8c0a80002550d93d740000050462c7ba7e4d1753a801840007e7f00000101080a0001d1cc084db0ae474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992becf8918d0c9145465441939fcc6a1950a206b7e1fca38e1145eaebc129230aeb24f57bcab011c3c68829f5efe7bfcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0085a3a4e1c3466c6c649ea048d519d5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622e7fa7dac30ac602f9af40a9ef0236a54268247cd7f923946d0a8d1c3c68d1e35788c5002e54ad0a00100 ASCII:E...h.... at .......U...@..PF,{...u:.. at .~............M..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed3.Z.z.+..Y.h.......7......k..e...|...;h.L=.v....G..."...Ga.Y.....#..I.c....i.......;p..A#...3r......;0jh...M.;b.0.....58F.5z...2q..!..MR4q.......:r..y.~D..w...!cs..q........f......}.2...1.M..3|J..t..;........3n$R..eu..D..im.,.$..+......EFTA...j.P........E...)#..$.{......).........1f.0B...:b...a...#.c..Z:N.4f..I...Q._...^.(.$q&.ac>..4i..E.UM..A..."..}.0.`/.....#jT&.G...9F.......5x.P..J.... +uncompressed= 45000268000900004006cef8c0a80002550d93d740000050462c7ba7e4d1753a801840007e7f00000101080a0001d1cc084db0ae474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a49662d4d6f6469666965642d53696e63653a205475652c2032332041756720323031362031323a33343a323920474d540d0a0d0a ASCII:E..h.... at .......U...@..PF,{...u:.. at .~............M..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..If-Modified-Since: Tue, 23 Aug 2016 12:34:29 GMT.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 2 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010268000b00004006cef6c0a80002550d93d740000050462c7ba7e4d1753b80193fff131c00000101080a00022884084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992be4e8918d8c9045465441939fcc6a1950a206b7e1dca38e1145eaebb929230aeb24f579cab011c3c68829f5efe7afcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0084a3a4e1c3466c6c649ea048dd19c5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622c7fa7dac30ac5c2f9af40a1ef0236a502682478dff913946d0a8d1c3c68d1e35788c5002e54ad0a00100 ASCII:E...h.... at .......U...@..PF,{...u;..?...........(..M.XGET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed3.Z.z.+..Y.h.......7......k..e...|...;h.L=.v....G..."...Ga.Y.....#..I.c....i.......;p..A#...3r......;0jh...M.;b.0.....58F.5z...2q..!..MR4q.......:r..y.~D..w...!cs..q........f......}.2...1.M..3|J..t..;........3n$R..eu..D..im.,.$..+......EFTA...j.P........E...)#..$.y......).........1f.0B...:b...a...#.c..J:N.4f..I....._...^.(.$q&.ac>..4i..E.UM..A..."..}.0.\/.....#jP&.G...9F.......5x.P..J.... +uncompressed= 45000268000b00004006cef6c0a80002550d93d740000050462c7ba7e4d1753b80193fff131c00000101080a00022884084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a49662d4d6f6469666965642d53696e63653a205475652c2032332041756720323031362031323a33343a323920474d540d0a0d0a ASCII:E..h.... at .......U...@..PF,{...u;..?...........(..M.XGET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..If-Modified-Since: Tue, 23 Aug 2016 12:34:29 GMT.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 3 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010268000c00004006cef5c0a80002550d93d740000050462c7ba7e4d1753b80193fff65ab00000101080a0002d5f4084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992be4e8918d8c9045465441939fcc6a1950a206b7e1dca38e1145eaebb929230aeb24f579cab011c3c68829f5efe7afcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0084a3a4e1c3466c6c649ea048dd19c5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622c7fa7dac30ac5c2f9af40a1ef0236a502682478dff913946d0a8d1c3c68d1e35788c5002e54ad0a00100 ASCII:E...h.... at .......U...@..PF,{...u;..?.e............M.XGET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed3.Z.z.+..Y.h.......7......k..e...|...;h.L=.v....G..."...Ga.Y.....#..I.c....i.......;p..A#...3r......;0jh...M.;b.0.....58F.5z...2q..!..MR4q.......:r..y.~D..w...!cs..q........f......}.2...1.M..3|J..t..;........3n$R..eu..D..im.,.$..+......EFTA...j.P........E...)#..$.y......).........1f.0B...:b...a...#.c..J:N.4f..I....._...^.(.$q&.ac>..4i..E.UM..A..."..}.0.\/.....#jP&.G...9F.......5x.P..J.... +uncompressed= 45000268000c00004006cef5c0a80002550d93d740000050462c7ba7e4d1753b80193fff65ab00000101080a0002d5f4084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a49662d4d6f6469666965642d53696e63653a205475652c2032332041756720323031362031323a33343a323920474d540d0a0d0a ASCII:E..h.... at .......U...@..PF,{...u;..?.e............M.XGET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..If-Modified-Since: Tue, 23 Aug 2016 12:34:29 GMT.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 4 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 450001022d000f00004006ac5ec0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00 ASCII:E...-.... at ..^........ at ..@F.......P. at ..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application3.\....g..8o\...vj..Y........w..I..k.9`..h!....;{.0....4>G........O......9.w........g......3v`..je..4w.4ab.j.6jpd.....'d...CF...h....#2.9u..a.&...x...!CF.....AS....1...#.....e8.1c..*5f.D\...9vF....G..:h..H.&..u`...g...|...._"E62...Q..{2.e at 9z..q.:F.Y....(....).F..#..o..-.#S...1......`e.U..'G...y.s.8h.d......1..AS}gO.H. <....3h.......>Eo... +uncompressed= 4500022d000f00004006ac5ec0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a2031302e392e312e3137313a383030300d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..-.... at ..^........ at ..@F.......P. at ..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: 10.9.1.171:8000..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 5 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 450001022d001000004006ac5dc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00 ASCII:E...-.... at ..]........ at ..@F.......P. at ..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application3.\....g..8o\...vj..Y........w..I..k.9`..h!....;{.0....4>G........O......9.w........g......3v`..je..4w.4ab.j.6jpd.....'d...CF...h....#2.9u..a.&...x...!CF.....AS....1...#.....e8.1c..*5f.D\...9vF....G..:h..H.&..u`...g...|...._"E62...Q..{2.e at 9z..q.:F.Y....(....).F..#..o..-.#S...1......`e.U..'G...y.s.8h.d......1..AS}gO.H. <....3h.......>Eo... +uncompressed= 4500022d001000004006ac5dc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a2031302e392e312e3137313a383030300d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..-.... at ..]........ at ..@F.......P. at ..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: 10.9.1.171:8000..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 6 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 450001022d001100004006ac5cc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00 ASCII:E...-.... at ..\........ at ..@F.......P. at ..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application3.\....g..8o\...vj..Y........w..I..k.9`..h!....;{.0....4>G........O......9.w........g......3v`..je..4w.4ab.j.6jpd.....'d...CF...h....#2.9u..a.&...x...!CF.....AS....1...#.....e8.1c..*5f.D\...9vF....G..:h..H.&..u`...g...|...._"E62...Q..{2.e at 9z..q.:F.Y....(....).F..#..o..-.#S...1......`e.U..'G...y.s.8h.d......1..AS}gO.H. <....3h.......>Eo... +uncompressed= 4500022d001100004006ac5cc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a2031302e392e312e3137313a383030300d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..-.... at ..\........ at ..@F.......P. at ..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: 10.9.1.171:8000..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 7 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 450001022d001200004006ac5bc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00 ASCII:E...-.... at ..[........ at ..@F.......P. at ..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application3.\....g..8o\...vj..Y........w..I..k.9`..h!....;{.0....4>G........O......9.w........g......3v`..je..4w.4ab.j.6jpd.....'d...CF...h....#2.9u..a.&...x...!CF.....AS....1...#.....e8.1c..*5f.D\...9vF....G..:h..H.&..u`...g...|...._"E62...Q..{2.e at 9z..q.:F.Y....(....).F..#..o..-.#S...1......`e.U..'G...y.s.8h.d......1..AS}gO.H. <....3h.......>Eo... +uncompressed= 4500022d001200004006ac5bc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a2031302e392e312e3137313a383030300d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..-.... at ..[........ at ..@F.......P. at ..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: 10.9.1.171:8000..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 8 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010268001300004006ceeec0a80002550d93d740000050462c7ba7e4d1753b80193fff7b4a00000101080a0003c054084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005bbb7e0d3b964dd9b369d7b6ddb3e60e9c372ef614beeb15ac58b2660513368cf8cdd63b68f65045ab96ed9cb58947b490d1422851a34861185923d50e9aa423f0dc490363c756d8b269e4d8cac68e9cd93b70f0804143376fe13372dcc801038f193b306a6cb5b2864d9a3b629a30b1b2b5081b353848173d7a07c6133271d4e021a3068d52347184ee81c119c69c3a72d2b079c37e4489c177e6f4902183730cde71f8a0a913d6cec21866e4c091818548fdfb329cec9831834d951a337e4e2e2174891c3baef5e8d113a38f1c336e2656148a85751d1844d6c7716da52c1f240f9b2fecf8918d0c9145465441a39f0c6b1950a40ab7f1fca38e1145ecebc129234aeb24f67bcab011c3c68829f6f1ebb7cbe4c894e731668c3052163ffa3a63d9949561e4c91123c263d0105a3a4e1c3466c8c651ea04cd519d60f3a0016f14290c2471289e61735ee9193469de8c45b3554d1fa84299c88622e73afeac30ac6037aaf40a9ef0236a54268247cd7f923946d0a8d1c3c68d1e35788c5002e58a50a10100 ASCII:E...h.... at .......U...@..PF,{...u;..?.{J.........T.M.XGET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed3.[.~.;.M..i.......7.......X.f..6....;h.PE......G...B(Q.Ha.Y#....#..I.c.V..i.......;p..AC7o.3r......;0jl...M.;b.0.....58H.=z...2q..!...R4q.......:r..y.~D..w...!.s..q........f.....H..2...1.M..3~N.!t..;........3n&V...u..D..qm.,.$../......EFTA...k.P........E...)#J.$.{......).........1f.0R.?.:c...a...#.c..Z:N.4f..Q...Q.`...o.).$q(.as^..4i..E.UM..B...".:..0.`7.....#jT&.G...9F.......5x.P...P... +uncompressed= 45000268001300004006ceeec0a80002550d93d740000050462c7ba7e4d1753b80193fff7b4a00000101080a0003c054084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a49662d4d6f6469666965642d53696e63653a205475652c2032332041756720323031362031323a33343a323920474d540d0a0d0a ASCII:E..h.... at .......U...@..PF,{...u;..?.{J.........T.M.XGET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..If-Modified-Since: Tue, 23 Aug 2016 12:34:29 GMT.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 9 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 450001022d001400004006ac59c0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00 ASCII:E...-.... at ..Y........@.. at F.......P.@..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application3.\....g..8o\...vj..Y........w..I..k.9`..h!....;{.0....4>G........O......9.w........g......3v`..je..4w.4ab.j.6jpd.....'d...CF...h....#2.9u..a.&...x...!CF.....AS....1...#.....e8.1c..*5f.D\...9vF....G..:h..H.&..u`...g...|...._"E62...Q..{2.e at 9z..q.:F.Y....(....).F..#..o..-.#S...1......`e.U..'G...y.s.8h.d......1..AS}gO.H. <....3h.......>Eo... +uncompressed= 4500022d001400004006ac59c0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a2031302e392e312e3137313a383030300d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..-.... at ..Y........@.. at F.......P.@..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: 10.9.1.171:8000..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 10 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 450001022d001500004006ac58c0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00 ASCII:E...-.... at ..X........@.. at F.......P.@..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application3.\....g..8o\...vj..Y........w..I..k.9`..h!....;{.0....4>G........O......9.w........g......3v`..je..4w.4ab.j.6jpd.....'d...CF...h....#2.9u..a.&...x...!CF.....AS....1...#.....e8.1c..*5f.D\...9vF....G..:h..H.&..u`...g...|...._"E62...Q..{2.e at 9z..q.:F.Y....(....).F..#..o..-.#S...1......`e.U..'G...y.s.8h.d......1..AS}gO.H. <....3h.......>Eo... +uncompressed= 4500022d001500004006ac58c0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a2031302e392e312e3137313a383030300d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..-.... at ..X........@.. at F.......P.@..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: 10.9.1.171:8000..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 11 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010239000500004006ac5cc0a800020a0901ab40001f90c286afa741a348cb801840007fcb0000050a41a348dc41a34a440000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d69786564330057b36eedfa954dd8b165cfa6ddb3e60e9c372ef6049eab95ab57b062fd02164cf8cdd53b68f640256b16ed9cb38547b490d1e22791a043efc030b2c6a91d344547e0b99306c68eabad5fd3c871958d1d39b077e0e00183c6eddcbf67e4b89103061e337660d4b86a650d9b3477c4346162e56a11366a7080164d14c6133271d4e021a3068d5134717eee818119c69c3a72d2b079837e4489bf77e6f4902103738cdc71f8a0a9d3d58ec11866e4c091818548fcf9329cec9831834d951a33783e2ef173891c3bab69cc88c1a3674f1d347a6cdcf8134bea3a30889c8fb3da4a583e48162a37a891231b19208b8ca882c63e99d432a038fd6d8339471d238ac8d793534614d549e40b956123868d1153e4d3b77f97c99129cc63cc1861242c7df275beb2092bc3c89323467ef7fc693a4e1c3466c0c631ea04cdd09d5cf3a0e96e66e81d1848e2403cc366bcd13368d2bcf98ae6aa9a3e4c7ffe0c00 ASCII:E...9.... at ..\........ at .......A.H...@.......A.H.A.JD..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed3.W.n...M..e.......7.......W.b...L...;h.@%k.....G....'..C..0....4EG........_..q...9.w........g......3v`..je..4w.4ab.j.6jp..M...2q..!...Q4q~......:r..y.~D..w...!.s..q........f.....H..2...1.M..3x>..s..;.i....gO.4zl...K.:0.....JX>H.*7..#.. .....>..2.8.m.9G.#....SF..I...a#...S.......).c..a$,}.u...+...#F~..i:N.4f..1.....\...nf...H.@<.f..3h.......>L.... +uncompressed= 45000239000500004006ac5cc0a800020a0901ab40001f90c286afa741a348cb801840007fcb0000050a41a348dc41a34a440000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a2031302e392e312e3137313a383038300d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..9.... at ..\........ at .......A.H...@.......A.H.A.JD..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: 10.9.1.171:8080..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 12 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 450001025b000a00004006ac35c0a800020a0901ab40011f90c293b0a8af5e58be5018400072a60000474554202f72656470686f6e652e706e6720485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c33005cbd82154b368e59b46ad9ee597307ce1b177b066fedfa35ec583665010b266cf8cdd63b68f6543d9b76ed1cb58747b490d16268d1a34961185933d50e1aa523f0dc490363c7d6d7b169e4d8cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a6cb5b2864d9a3b629a30b1b2b5081b3538461b457a07c6133238f190518366299a3843f7c0d80c634e1d3969d8bc513fa244e03b737ac890b139c6ee387cd0d4096b07610c3372e0c8c042647e7d194e76cc98c1a64a8d1940259718ba448e9dd63466c4e01134a80e1a3d38721c8a65751d1844d2c7696d65261f240d9923dcd8918d0c9045465441839fcc6a1950a606b7e1bca38e1145e8ebd929230aeb24f485cab011c3c68829f4ede3d7cbe4c814e731668c3032d3be1a3c75c6b2296be4c91123c1830e451d270e1a3364e32c758206694fb079d07c3f9a1406923812cfb0c1b9f40c9a346fc6a2d9aaa64fd4a175d33064b894bfff812b5bc2a421b3e60c8e32860e0d00 ASCII:E...[.... at ..5........@........^X.P. at .r...GET /redphone.png HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed,3.\...K6.Y.j..Ys....{.o..5.X6e..&l...;h.T=.v....G...bh..Ia.Y3....#..I.c....i.......;p..A#...3r......;0jl...M.;b.0.....58F.Ez...28..Q.f).8C....cN.9i..Q?.D.;sz...9..8|...k.a.3r...Bd~}.Nv....J..@%...D...4f...4...=8r..eu..D..ime&.$..#......EFTA...j.P........E...)#..$........).........1f.02.......;h.TM......G...bh..Ia.Y3....#..I.c....i.......;p..Acw..3r......;0jp...M.;b.0.....58J.Ez...2q..!...R4q.......:r..y.~D..w...!.s..q...#....f......}.2...1.M..3.R.1t..;........3n(Z...u..D..ym.,.$..3......EFTA..Lk.P........E...)#..$.}......).........1f.0b6..:d...a...#.c..j:N.4f..Y.....a....4).$q*.a.~..4i..E.UM..C... +uncompressed= 45000236003000004006cf03c0a80002550d93d740020050c30e84a9441d06ac80184000c2f400000101080a00052df410fc31bd474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..6.0.. at .......U...@..P....D..... at ...........-...1.GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 15 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010260004500004006cec4c0a80002550d93d740030050c3134faac89c8b2980184000578d00000101080a000535c010fc34c8474554202f6e697276616e612e63737320485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d33006fcede41b3072c5dbb78e7dcad3ca2858c164ea14aa50ac3c81aaf76d0541d81e74e1a183bcef2f64d23c7593676e4fcde8183070c1ac6913b9f91e3460e187884c2a871d6ca1a3669ee8869c2c4cad9226cd4e0801d75ea1d184f7caac143460d1aab68e238dd0303358c3975e4a461f3c6fe88128fefcce9214306ea18c8e3f04153a7edd0b841e5c0918185c87f83329cec9831834d951a33967e2ee174891c3bbaf5e8d113a38f1c336e3ac2718a05771d1844eac7d16d252e1f241985563489928d8c954546544193900c6e1950bc3ab7a11da58e11450aea292a234aee240595cab011c3c68829050f2624cce4c814ed31668c3012f7a0fc3a6fd9c49561e4c91123ce63d0702a3b4e1c3466e0c6b1ea04cdd4a36cf3a0592f952a0c2471ccc839c3268e1aab67d0a479f316cd59357db83af59b062346ab0d1f46b47933e7ce9e329c3a0d00 ASCII:E...`.E.. at .......U...@..P..O....).. at .W.........5...4.GET /nirvana.css HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xm3.o..A..,].x...<....N.J......v.T...N..;...M#.Y6v..........;...F..x...q...6i..i...."l....u...O|..CF...h.8...5.9u..a.........!C......AS....A........2...1.M..3.~..t..;........3n:.q..w..D...m%..$..V4.....EFTA...n.P.:......E..)*#J.$........)..&$.....1f.0....:o...a...#.c.p*;N.4f........l..Y/.*.$q..9.&...g..y...Y5}.:...#F...F.y3...2.:.. +uncompressed= 45000260004500004006cec4c0a80002550d93d740030050c3134faac89c8b2980184000578d00000101080a000535c010fc34c8474554202f6e697276616e612e63737320485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..`.E.. at .......U...@..P..O....).. at .W.........5...4.GET /nirvana.css HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 16 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010264004600004006cebfc0a80002550d93d740040050c3135bab2189da61801840008f2d00000101080a000535c410fc34dc474554202f382d4269742f4c6162656c2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d3300952fbf517b07cd1e9f77f3ee9da317f38816325a48a56a152b0c236bc4da419375049e3b6960ec50fb3b388d1c6ad9d891237c070e1e3068245f1e7d468e1b3960e0316307460db556d6b04973474c132656d4f254836376d5ab7760008da3060f193568b4a28923750f8cd530e6d4919386cd9bfc234a48be33a7870c19ab632c8fc3074d1db87630c63023078e0c2c440c2294e164c78c196caad498f1547409a94be4d8e9ad478f9e187de498710352a4542cbbebc020823f4e6f2b74f920e1c81da34a966c64bc2c32a20a1a866476cb802236ba0def2c758c2872500f521951782739d854868d1836464c39a89061612647a6788f31638411ba0aebd791cb86ae0c234f8e18891e838654da71e2a03133378e562768ae2a7d9b078d7bab5861208913f20c1bfa5acfa049f3462e1ab56afa80950a38cdc68d5a214aa4a873e74fa144474a951a00 ASCII:E...d.F.. at .......U...@..P..[.!..a.. at ..-........5...4.GET /8-Bit/Label.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtm3../.Q{....w........2ZH.j.+.#k..A.u..;i`.P.;8..j...#|...0h$_.}F..9`.1c.F..V..IsGL.&V..T.cv..w`......5h...#u...0........#JH.3.....c,...M..v0.0#...,D."..d...l....Tt..K....G...}..q.R.T,... .?No+t. ....J.ld.,2....dv.."6...,u.(rP.R.Qx'9.T...6FL9..aa&G.x.1c...........#O......T.q..137.V'h.*}...{.Xa ......Z..I.F...j....8...Z!J..s.O.DGJ... +uncompressed= 45000264004600004006cebfc0a80002550d93d740040050c3135bab2189da61801840008f2d00000101080a000535c410fc34dc474554202f382d4269742f4c6162656c2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..d.F.. at .......U...@..P..[.!..a.. at ..-........5...4.GET /8-Bit/Label.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 17 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010264005800004006ceadc0a80002550d93d740050050c31389acaf7b26538018400075c900000101080a000537d010fc354a474554202f382d4269742f41636f726e2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d3300942dbf497b07cd1e9f76f1ea9d93f7f28816325a48a56af50e0c236bc2da418375049e3b6960ec48eb1b388d1c69d9d891137c070e1e306820570e7d468e1b3960e0316307468db456d6b04973474c132656d2f2548343b699aa57613c2113470d1e326ad064451347ea1e18aa61cca923270d9b37f94794887c674e0f193254c7501e870f9a3a6fed608c11148e0c2c440c2294e164c78c196caad498f1347409a94be4d8e1ad478f9e187de4987103520e1ca95874d78141047f1cde56e6f241c2713bc6942bd9c87059644415340cc9e89601252c741bdd57ea1851e4a09ea432a2ec4e72d0a90c1b316c8c9872502143c34c8e4ce91e63c608237315d6af1397cd5c19469e1c31023d060da9b4e3c44163466e9cac4ed0585dea360f9af6efefc0401227e81936f4b39e4193e64d5c3469d5f4f92a15709a8d1bb342944831a7ce9e42898a942a3500 ASCII:E...d.X.. at .......U...@..P.....{&S.. at .u.........7...5JGET /8-Bit/Acorn.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtm3..-.I{....v........2ZH.j...#k..A.u..;i`.H..8..i....|...0h W.}F..9`.1c.F..V..IsGL.&V..T.C...Wa#...0......Z+k...#...+kw..A.*.;0.......5h...3u...0........#JP.3.....c0...M..v6.0#...,D.2..d...l.....t..K....G...}..q3..T,... .?.o+u. ..}c..ld.,2....dx..2V.../u.(.P.S.Qz'Q(U...6FLQ..ab&G.|.1c...........#O........q..1C7.V'h.:......Ya .C....[..I.f...j...:8.G.['V....P.HMN... +uncompressed= 45000266007600004006ce8dc0a80002550d93d740060050c31431ada11fa06780184000f08e00000101080a00053b3c10fc35ef474554202f382d4269742f416d73747261642e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..f.v.. at .......U...@..P..1....g.. at ...........;<..5.GET /8-Bit/Amstrad.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 19 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010264007700004006ce8ec0a80002550d93d740040050c3135ddb2189e0108018400060d600000101080a00053b4010fc35e7474554202f382d4269742f41746172692e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d3300932bbf497b07cd1e9f76f1ea9d93d7f28816325a48a56a152b0c236b84da419375049e3b6960ec48dbfb378d1c69d9d891037c070e1e30681c4ffe7c468e1b3960e0316307468db456d6b04973474c132656d2f254832376d5ab77603c2113470d1e326ad068451347ea1e18a961cca923270d9b37f84794807c674e0f193252c7481e870f9aa1da2fc63023078e0c2c440a1e94e164c78c196caad498f1147409a94be4d8d9ad478f9e187de49871e311a4542cb9ebc020723fce6e2b73f920d968e7224a956c64b42c32a20a9a856472cb8022f4b90dee2a758c286250cf511951742731c854868d1836464c31887061612647a6708f31638491b908e9d789cb66ae0c234f8e18791e8386d4d971e2a03123378e562768ae26759b070d7bab58612089f3f10c9bf95acfa049f3262e9ab46afa8095fa378d468d5a1f469c8833e7ce9f41434a951a00 ASCII:E...d.w.. at .......U...@..P..].!..... at .`.........;@..5.GET /8-Bit/Atari.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtm3..+.I{....v........2ZH.j.+.#k..A.u..;i`.H..7..i....|...0h.O.|F..9`.1c.F..V..IsGL.&V..T.#v..w`4..6.GET /8-Bit/Apple.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtm3..-.Q{....v........2ZH.j.+.#k..A.u..;i`.P..7..j....|...0h.O.|F..9`.1c.F..V..IsGL.&V..T.#v..w`4..6.GET /8-Bit/Apple.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 21 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010265007d00004006ce87c0a80002550d93d740050050c3138bdcaf7b296780183cec0de600000101080a00053e3410fc368e474554202f382d4269742f447261676f6e2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d33009631bf597b07cd1e9f8df5f2d59379440b192da656bd9a1586913563eda0d13a02cf9d343076ac052e9c468eb56cecc819be03070f18349433973e23c78d1c30f098b103a3c65a2b6bd8a4b923a609132b6b79aac141db2ad63b309e9089a3068f50345bd1c499ba07c6631873eac849c3e68dfe112526df99d343868cc73198c7e183a64e5c3b1963989103470616220715ca70b263c60c36556acc804abac4d42572ecf8d6a3474f8c3e72ccb80939722a16de75601051c3dfb715a27c9074ec9e71654b363260161951054d4332bc6540192bddc6f7963a461441a847a98c28bd93208ce3d3460c1b23a6205cd89030932353bec79831c208d185f7ebcc6553d7c8932346a4c7a03175769c3868ccd08db3d5091aac4ce1e641f3fe6a561848e2883cc3c6fed63368d2bc998b66ad9a3e61a7fe4dc391e3d688132beeec0974a8519253a70600 ASCII:E...e.}.. at .......U...@..P.....{)g..<...........>4..6.GET /8-Bit/Dragon.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtm3..1.Y{.........yD..-.V.....5c...:...40v....F..l........4.3.>#...0......Z+k...#...+ky..A.*.;0......P4[......c.s..I.....%&...C...1.....N\;.c...G.."...p.c..6Uj..J...%r....GO.>r...9r*..u`.Q.....|.t..qeK62`..Q.MC2.e at .+....:F.A.G..(.. ...F..#. \..0.#S...1.......eS...#F...1uv.8h........L..A..jV.H..<....3h....f..>a..M......+...t.Q.S... +uncompressed= 45000265007d00004006ce87c0a80002550d93d740050050c3138bdcaf7b296780183cec0de600000101080a00053e3410fc368e474554202f382d4269742f447261676f6e2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..e.}.. at .......U...@..P.....{)g..<...........>4..6.GET /8-Bit/Dragon.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 22 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010269008000004006ce80c0a80002550d93d740060050c3143301dfa11fa3de80183c892b5d00000101080a0005412c10fc3761474554202f382d4269742f456e74657270726973652e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f6600952f67defcc66dd03d3df7f6fd3bc72fe7112d64b4b08a552b571846d6983dda75049e3b6960ec701b7c388d1c6e8dca21be03070f183496db694e63468e1b3960e0316307460db756d6b04973474c132656dcee5483c376d6ad77603c2113470d1e326ad0784513c7ea1e18ae6110959386cd1bfe234a58be33a7870c19ae63548fc347285d3b1b63989103470616220ad3c870b263c60c36556acc986aba84d52572ecfcd6a3474f8c3e72ccb81149d22a96a3756010d91fe7b715bc7c90d4f9b891a54b36326216195105cd4332476540312bdd0678973a4614a923478f531951d0dc49d299aa0c1b316c8c98d2b9e143c64c8e4c011f63c60823781be2af63970d5e19469e1c31223d060dabbce3c44163e66e1caf4ed06c853a370f1af85ab9c2401267e41936f7bd9e4193e68d5d346ed5f4216bd5701aa142bd4eac78d1e7cfa1489596b46a3500 ASCII:E...i.... at .......U...@..P..3........<.+]........A,..7aGET /8-Bit/Enterprise.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/f../g...m.==...;./..-d...U+W.F..=.u..;i`.p.|8..n..!.....4..iNcF..9`.1c.F..V..IsGL.&V..T..v..w`r...I.*..u`.......|......K62b..Q..C2Ge at 1+..x.:F..#G.S.Q..I.....1l.....C.L.L..c..#x...c..^.F..1"=......Ac.n..N.l.:7...Z.. at .g..6...A...]4n..!k.p..B.N.x....H...j5. +uncompressed= 45000269008000004006ce80c0a80002550d93d740060050c31433dfa11fa3de80183c892b5d00000101080a0005412c10fc3761474554202f382d4269742f456e74657270726973652e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..i.... at .......U...@..P..3.......<.+]........A,..7aGET /8-Bit/Enterprise.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 23 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010268008100004006ce80c0a80002550d93d740040050c313600b2189e30280183d0e896b00000101080a000541d810fc379d474554202f382d4269742f436f6d6d6f646f72652e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f3300952f67defcc6ed1d347b7ceeedfb778e5fce235ac8686115ab56ae308cac316b074dd71178eea481b1c3edf0e23472b86563478ef11d3878c0a0d1fc79f519396ee48081c78c1d1835dc5a59c326cd1d314d985871cb530d8edb59b7de81f1844c1c3578c8a841e3154d1cab7b60bc8631a78e9c346cdef81f51c2f29d393d64c8781de3791c3e68ead0b5d3318699a032b01061e85086931d3366b0a95263c654d325ac2e916327b81e3d7a62f49163c64dc9a056b1fcae038348ff38c1ade0e5832424f88e2e61b29131b3c8882a682292f92d038ad9ea36c4c3d431a248433d4c6544019ea46154193662d81831a5e1c38889991c99223ec68c1146f03ed45fc72e1bbc328c3c3962a47a0c1a5671c78983c6ccdd385e9da0d9ea746e1e34f2b5728581248ec9336cf27b3d8326cd1bbb68dcaae943d62ae13420417aad78312350a1448d228523c3aad500 ASCII:E...h.... at .......U...@..P..`.!.....=..k........A...7.GET /8-Bit/Commodore.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/3../g.....4{|...w._.#Z.ha..V.0..1k.M..x........4r.ecG...8x....y..9n.......5.ZY.&..1M.Xq.S...Y.....L.5x..A..M..{`..1...4l...Q...9=d.x..y.>h....1...2..a.P...3f..Rc.T.%...c'..=zb..c.M..V.....H.8.....$$...a..1...*h"..-....6...1.HC=LeD...aT.6b..1........">...F.>._....2.<9b.z..Vq......8^....tn.4..r..$..3l.{=.&...h...C.*.4 Az.x1#P.D.".#.... +uncompressed= 45000268008100004006ce80c0a80002550d93d740040050c313600b2189e30280183d0e896b00000101080a000541d810fc379d474554202f382d4269742f436f6d6d6f646f72652e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..h.... at .......U...@..P..`.!.....=..k........A...7.GET /8-Bit/Commodore.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 24 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010263008200004006ce84c0a80002550d93d740050050c3138e0daf7b2cf180183962cb2f00000101080a000542b410fc3822474554202f382d4269742f454143412e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b330096dfa4bd83668f4fbb78f5cec97b79440b192da24ead7a1586913561eda0c13a02cf9d343076a4f50d9c468eb46cecc809be03070f1834902b873e23c78d1c30f098b103a3465a2b6bd8a4b923a609132b6979aac1219baad53b309e9089a3060f193568b2a28913750f0cd530e6d4919386cd9bfc234a44be33a7870c19aa63288fc3074d9db77630c63023078e0c2c440c2294e164c78c196caad498e1347489a84be4d8e1ad478f9e187de49871035264542cbaebc020823f0e6f2b73f920e1b81da34a966c64bc2c32a20a1a866474cb801216ba8dee2c758c287250cf511951762739c854868d1836464c39a89021612647a6748f31638491b90aebd789cb66ae0c234f8e18811e8346d4d971e2a03123374e562768ac26759b074dfbaa5761208913f20c1bfa59cfa049f3262e9ab46afa7c8dfa37cdc68d59214aa4a873e7cfa04347468d1a00 ASCII:E...c.... at .......U...@..P.....{,...9b./........B...8"GET /8-Bit/EACA.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+3......f.O.x...{yD..-.N.z...5a...:...40v....F..l........4.+.>#...0.....FZ+k...#...+iy..!...;0.......5h....u...0........#JD.3.....c(...M..v0.0#...,D."..d...l....4t..K....G...}..q.RdT,... .?.o+s. ....J.ld.,2....dt.......,u.(rP.Q.Qv'9.T...6FL9..!a&G.t.1c........f..#O.....F..q..1#7NV'h.&u..M..Wa ......Y..I.&...j.|..7...Y!J..s...CGF... +uncompressed= 45000263008200004006ce84c0a80002550d93d740050050c3138e0daf7b2cf180183962cb2f00000101080a000542b410fc3822474554202f382d4269742f454143412e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..c.... at .......U...@..P.....{,...9b./........B...8"GET /8-Bit/EACA.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 25 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010262008500004006ce82c0a80002550d93d740070050c314f5defa37d29b80183c168b6100000101080a000542c810fc37e5474554202f382d4269742f4d53582e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b330095dfa0bd83668fcfba77f3cec16b79440b192da04aa56a1586913560eda0b93a02cf9d343076a0edfd9b460eb46cecc801be03070f18348e277f3e23c78d1c30f098b103a3065a2b6bd8a4b923a609132b6879aac1117b6ad53b309e9089a3060f193568b0a28903750f8cd430e6d4919386cd1bfc234a40be33a7870c19a963248fc3074d1db7762ec63023078e0c2c440a1e94e164c78c196caad498d1147409a84be4d8d9ad478f9e187de49871f33124542cb9ebc020723fce6e2b72f920d9a8fd62ca956c64b82c32a20a9a856472cb8002f6b90dee2b758c2862508f511951742731b854868d1836464c318870e1602647a6708f31638411b908e9d781cb46ae0c234f8e18791e830654d971e2a03113370e562768aa226d9b070d7baa5661208903f20c9bf958cfa049f3062e1ab46afa7885ea378d468d581f469c9853674fa0424542851a00 ASCII:E...b.... at .......U...@..P.....7....<..a........B...7.GET /8-Bit/MSX.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+3......f...w...kyD..-.J.j...5`...:...40v....F..l........4.'.>#...0......Z+k...#...+hy...{j.;0.......5h....u...0........#J at .3.....c$...M..v..0#...,D....d...l.....t..K....G...}..q.1$T,... r?.n+r. ...b..ld.,2....dr.......+u.(bP.Q.Qt'1.T...6FL1.p.`&G.p.1c........F..#O..y...T.q..1.7.V'h."m...{.Va ......X..I.....j.x..7.F.X.F..SgO.BEB... +uncompressed= 45000262008500004006ce82c0a80002550d93d740070050c314f5defa37d29b80183c168b6100000101080a000542c810fc37e5474554202f382d4269742f4d53582e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..b.... at .......U...@..P.....7....<..a........B...7.GET /8-Bit/MSX.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 26 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010265009400004006ce70c0a80002550d93d740060050c3143614a11fa986801836e1f43c00000101080a000545b010fc38b7474554202f382d4269742f4d617474656c2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d3300942dbf512b744fcfbb79f7ced17b79440b192da452b58a1586913562eda0c93a02cf9d343076a8edfd9b460eb56cecc801be03070f18348e277f3e23c78d1c30f098b103a3865a2b6bd8a4b923a609132b6a77aac111bbead53b309e9089a3060f193568b4a28923750f8cd430e6d4919386cd1bfc234a44be33a7870c19a963248fc3074d1db87630c63023078e0c2c440a1e94e164c78c196caad498f1347409a94be4d8d9ad478f9e187de498710352a4542cb9ebc020723fce6e2b74f920e1a81da34a966c64bc2c32a20a1a866472cb8022f6b90dee2c758c2862504f521951742731e854868d1836464c31889021612647a6708f31638411ba08e9d791bbd8c89323469ec7a02195769c3868cc7ca5abd5099aab4bdfe641c3de2a561848e2843cc366bed63368d2bc018a46ad9a3e60a5fe4db371a356881229eae4f97368d19152a50600 ASCII:E...e.... at ..p....U...@..P..6.......6..<........E...8.GET /8-Bit/Mattel.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtm3..-.Q+tO..y...{yD..-.R.....5b...:...40v....F..l........4.'.>#...0......Z+k...#...+jw......;0.......5h...#u...0........#JD.3.....c$...M..v0.0#...,D....d...l....4t..K....G...}..q.R.T,... r?.n+t. ....J.ld.,2....dr.."....,u.(bPOR.Qt'1.T...6FL1..!a&G.p.1c...........#F...!.v.8h.|......K..A..*V.H..<.f..3h....F..>`..M.q.V..)...sh..R... +uncompressed= 45000265009400004006ce70c0a80002550d93d740060050c3143614a11fa986801836e1f43c00000101080a000545b010fc38b7474554202f382d4269742f4d617474656c2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..e.... at ..p....U...@..P..6.......6..<........E...8.GET /8-Bit/Mattel.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 27 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010263009900004006ce6dc0a80002550d93d740040050c313623f2189e66b801839a5739a00000101080a0005464c10fc38f3474554202f382d4269742f4f7269632e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b330095dfa4bd83668f4fc578f5eab13ca2858c1651a756bd0ac3c89ab076d0601d81e74e1a183bd2fa064e23475a3676e404df8183070c1ac895439f91e3460e1878ccd8815123ad95356cd2dc11d3848995b43cd5e0904dd5ea1d184fc8c45183878c1a3459d1c489ba0706631873eac849c3e64dfe112520df99d343860cc63194c7e18326e8768c31ccc88123030b1183086538d93163069b2a356638155d22ea12397678ebd1a327461f3966dc7c0c19158bee3a3088e08fc3db8a5c3e4838dac19872251b192e8b8ca882862119dd32a084856ea3fb4a1d238a1cd483544694dd490e36956123868d11530e2a642898c99129dd63cc186144aec2fa75e0b2912bc3c8932346a0c7a01135769c3868ccc48d93d5091aab4adde641d3beea551848e2803cc3867ed63368d2bc818b26ad9a3e5fa3f64db3716356881229e6d4d91328519151a30600 ASCII:E...c.... at ..m....U...@..P..b?!..k..9.s.........FL..8.GET /8-Bit/Oric.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+3......f.O.x...<....Q.V......v.`...N..;...N#GZ6v..........C...F..x...Q#..5l........<...M....O..Q....4Y......c.s..I..M..% ...C...1....&.v.1...#.....e8.1c..*5f8.]"..9vx...'F.9f.|.....:0......\>H8...r%........!..2...n..J.#....TF..I.6.a#...S.*d(...).c..aD...u...+...#F....5v.8h........J..A...U.H..<..~.3h....&..>_..M.qcV..)....(Q.Q... +uncompressed= 45000263009900004006ce6dc0a80002550d93d740040050c313623f2189e66b801839a5739a00000101080a0005464c10fc38f3474554202f382d4269742f4f7269632e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..c.... at ..m....U...@..P..b?!..k..9.s.........FL..8.GET /8-Bit/Oric.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 28 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010269009e00004006ce62c0a80002550d93d740060050c3143845a11fab60801840003c1c00000101080a000547d810fc38b7474554202f382d4269742f526164696f536861636b2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f330096316be6fcc6ed1d347b7a46f60b584fe7112d64b4b08a552b5718468ad6b183a6eb083c77d2c0d8e17678711a39dcb2b123c7f80e1c3c60d068febcfa8c1c3772c0c063c60e8c1a6e89b24973474c132656dcee5483e376d6ad77603c2113470d1e326ad0784513c7ea1e189361cca923270d9b37fd4794b87c674e0f193226c7781e870f9a3a74ed748c61460e1c195888307428c3c98e1933d854a93163eae9125697c8b1135c8f1e3d31fac831e3a6e449ab587ed78141847f9ce056f0f24112127cc79731d9c8a0596444153411c9fc9601c56c751be263ea1851a4a19ea732a2004fd2b0aa0c1b316c8c98d2f061c4c54c8e4c111f63c60823781fe6af6357685e234f8e18a91e838655dd71e2a03173378e572768b6469d9b074d7cad5c61208963f20c1bfc5ecfa049f3c62e1ab76afa90b55a380d48905e2b5ecc1874e8d1a44b515ab51a00 ASCII:E...i.... at ..b....U...@..P..8E...`.. at .<.........G...8.GET /8-Bit/RadioShack.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/3..1k.....4{zF..XO..-d...U+W.F.......#...0......Z+A........<...}5...O..Q....4\......c.s..I#4.......!C......AS....1...#.....e8.1c..*5fD.]...9vz...'F.9f.|.I...:0......]>H6r..r%..........2.e at ......:F.9.G..(...|*.F..#..T(.0.#S...1..]....eCW..'G.D.A...8q.......4Y.....=V.0...y..}.g..y#..Z5}.R..F.F..#N...'P.".R.. +uncompressed= 45000266009f00004006ce64c0a80002550d93d740050050c313903caf7b2f9580183d5ce4ef00000101080a0005481810fc3934474554202f382d4269742f5068696c6970732e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..f.... at ..d....U...@..P...<.{/...=\..........H...94GET /8-Bit/Philips.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 30 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 450001049b00ae00004006cc20c0a80002550d93d740050050c31396ceaf7b396e801840009ad400000101080a0005611010fc3d6b474554202f382d4269742f6d72776f6e672e67696620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d33009733bf617b07cd9e9f8ef7f6d5a379440b192da85ac5aa1586913564eda0d93a02cf9d343076b00d3e9c460eb66cecc821be03070f183496379f3e23c78d1c30f098b103a3065b2b6b92de11d3848915b63dd5e0a87d35eb1d184fc814c543460d1aae68e250dd0303328c3975e4a461f346ff881294efcce9214306e418cde3f0415347ae1d8c31ccc88123030b1183086538d93163069b2a3566442d5d82ea1239767eebd1a327461f3966dc801449154bef3a3088e48ff3db0a513e48387ac7a892251b192f8b8ca882862199de32a0909d6e033c4b1d238a1cd4a3544614df490e3e956123868d11530e2a644898c99129e063cc186184a8423578ead06563d7c8932346a6c7a04175769c3868ccd48dc3d5099aac4ce3e641f31eab561848e2843cc3a628d73368d2bca18b86ad9a3e62a9fe4db3712357881229eadce933e8d09154a92a417265848c1d307afec489074e198678e6108d31a7e8882557ae4c9111357903abdf7f7b052b96ec4f3868d51e7e1b77ae74198ef7f63d1a76ce52bf50cf4c9d7355b7ddb290634cae7cb9b4dec05f135b76c178c41d347b7e16eeabc732db16325a74cf7a07869135647bff0e3e7c075bdad3732c6f4e7c070e1ed37dcb993e23c78d1c30f07807cfd6ca1a3669ee8869c2c40adb9e6a70a8d60ae30999a278c8e4e78a260ed53d3020c33088900d43ae25204aa46818239f8d6cbc631c3a120b11ff6964a864c9e6e58ca8a54b505d220727579d3b7d06bd48158b52a6f99f72b542940f923a13ed600c39838d8c974546fc6548a63761b2d36d8067a96344913a72f428951105cd9d248a9fcab011c3c688298ad30c444398c99129e063cc18313bce683578eae8b66be4c91123d363246f003b0e1a33d2b93a41939569dc3c68d6df8181248e193967d814e57a064d9a3774d1b055d387cd1caa7fd36cdcc835618f853a63d07473510655aa0100 ASCII:E........ at .. ....U... at ..P.....{9n.. at ...........a...=kGET /8-Bit/mrwong.gif HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtm3..3.a{.........yD..-.Z.....5d...:...40v..>.F..l..!.....4.7.>#...0......[+k........=...}5...O...CF...h.P...2.9u..a.F.......!C......ASG...1...#.....e8.1c..*5fD-]...9v~...'F.9f...I.K.:0......Q>H8z...%../.....!..2...n..a#...S.*dH...).c..a..B5x..ec...#F...Auv.8h........L..A...V.H..<..(.3h.......>b..M.q#W..)...3...T.*Are...0z....N..x...1...%W.L..5y....{.+..O8h..~.w.t....=.v.R.P.L.sU....cL.|...._.[v.x..4{~....2..2Zt.z...5d{..>|.[..s,oN|....}..>#...0.x.....6i..i.....jp.......x....&..=0 .0...C.% J.h.#..l.c.:....id.d......KP]".'W.;}..H..R...r.B...:..`.9....EF.eH.7a..m.g.cD.:r.(.....$........)...DC...).c..1;.h5x...k...#.c$o.;..3..:A..i. Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Tue Aug 30 17:48:19 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Tue, 30 Aug 2016 17:48:19 +0000 Subject: [PATCH] openbsc[master]: SLHC (RFC1144 header compression) integration and unit-test In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/635 to look at the new patch set (#16). SLHC (RFC1144 header compression) integration and unit-test The previously pushed slhc implementation has been modified to compile and function outside of the kernel. Also debug log messages were added and datatypes ware matched. The implementation is now ready to be used Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 --- M openbsc/.gitignore M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/debug.h R openbsc/include/openbsc/slhc.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/sgsn_main.c M openbsc/src/gprs/slhc.c M openbsc/tests/Makefile.am M openbsc/tests/sgsn/Makefile.am A openbsc/tests/slhc/Makefile.am A openbsc/tests/slhc/slhc_test.c A openbsc/tests/slhc/slhc_test.ok M openbsc/tests/testsuite.at 14 files changed, 550 insertions(+), 91 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/35/635/16 diff --git a/openbsc/.gitignore b/openbsc/.gitignore index 8ce3b70..e75b9eb 100644 --- a/openbsc/.gitignore +++ b/openbsc/.gitignore @@ -83,6 +83,7 @@ tests/mm_auth/mm_auth_test tests/xid/xid_test tests/sndcp_xid/sndcp_xid_test +tests/slhc/slhc_test tests/atconfig tests/atlocal diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 9dc2f8d..cebabdc 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -232,6 +232,7 @@ tests/mm_auth/Makefile tests/xid/Makefile tests/sndcp_xid/Makefile + tests/slhc/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index a5ba3ef..9a093ab 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,7 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ - iu.h + iu.h slhc.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 43ebb19..90ddca5 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -29,6 +29,7 @@ DBSSGP, DLLC, DSNDCP, + DSLHC, DNAT, DCTRL, DSMPP, diff --git a/openbsc/include/openbsc/slhc_vj.h b/openbsc/include/openbsc/slhc.h similarity index 97% rename from openbsc/include/openbsc/slhc_vj.h rename to openbsc/include/openbsc/slhc.h index 8716d59..cd5a47c 100644 --- a/openbsc/include/openbsc/slhc_vj.h +++ b/openbsc/include/openbsc/slhc.h @@ -171,7 +171,8 @@ #define NULLSLCOMPR (struct slcompress *)0 /* In slhc.c: */ -struct slcompress *slhc_init(int rslots, int tslots); +struct slcompress *slhc_init(const void *ctx, int rslots, int tslots); + void slhc_free(struct slcompress *comp); int slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, @@ -180,4 +181,7 @@ int slhc_remember(struct slcompress *comp, unsigned char *icp, int isize); int slhc_toss(struct slcompress *comp); +void slhc_i_status(struct slcompress *comp); +void slhc_o_status(struct slcompress *comp); + #endif /* _SLHC_H */ diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index fa4a3dd..245636b 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -26,7 +26,8 @@ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ - oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c + oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ + slhc.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c index 52fc985..894ce84 100644 --- a/openbsc/src/gprs/sgsn_main.c +++ b/openbsc/src/gprs/sgsn_main.c @@ -292,6 +292,11 @@ .description = "SCCP User Adaptation (SUA)", .enabled = 1, .loglevel = LOGL_DEBUG, }, + [DSLHC] = { + .name = "DSLHC", + .description = "RFC1144 TCP/IP Header compression (SLHC)", + .enabled = 1, .loglevel = LOGL_DEBUG, + }, }; static const struct log_info gprs_log_info = { diff --git a/openbsc/src/gprs/slhc.c b/openbsc/src/gprs/slhc.c index 27ed252..cbdf8db 100644 --- a/openbsc/src/gprs/slhc.c +++ b/openbsc/src/gprs/slhc.c @@ -50,61 +50,77 @@ * driver code belonging close to PPP and SLIP */ -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#ifdef CONFIG_INET -/* Entire module is for IP only */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#define ERR_PTR(x) x + static unsigned char *encode(unsigned char *cp, unsigned short n); static long decode(unsigned char **cpp); static unsigned char * put16(unsigned char *cp, unsigned short x); static unsigned short pull16(unsigned char **cpp); +/* Replacement for kernel space function ip_fast_csum() */ +static uint16_t ip_fast_csum(uint8_t *iph, int ihl) +{ + int i; + uint16_t temp; + uint32_t accumulator = 0xFFFF; + + for(i=0;i0xFFFF) + { + accumulator++; + accumulator&=0xFFFF; + } + } + + return (uint16_t)(htons(~accumulator)&0xFFFF); +} + +/* Replacement for kernel space function put_unaligned() */ +static void put_unaligned(uint16_t val, void *ptr) +{ + memcpy(ptr,&val,sizeof(val)); +} + + /* Allocate compression data structure * slots must be in range 0 to 255 (zero meaning no compression) * Returns pointer to structure or ERR_PTR() on error. */ struct slcompress * -slhc_init(int rslots, int tslots) +slhc_init(const void *ctx, int rslots, int tslots) { register short i; register struct cstate *ts; struct slcompress *comp; if (rslots < 0 || rslots > 255 || tslots < 0 || tslots > 255) - return ERR_PTR(-EINVAL); + return NULL; - comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL); + comp = (struct slcompress *)talloc_zero_size(ctx,sizeof(struct slcompress)); if (! comp) goto out_fail; if (rslots > 0) { size_t rsize = rslots * sizeof(struct cstate); - comp->rstate = kzalloc(rsize, GFP_KERNEL); + comp->rstate = (struct cstate *) talloc_zero_size(ctx, rsize); if (! comp->rstate) goto out_free; comp->rslot_limit = rslots - 1; @@ -112,7 +128,7 @@ if (tslots > 0) { size_t tsize = tslots * sizeof(struct cstate); - comp->tstate = kzalloc(tsize, GFP_KERNEL); + comp->tstate = (struct cstate *) talloc_zero_size(ctx, tsize); if (! comp->tstate) goto out_free2; comp->tslot_limit = tslots - 1; @@ -141,11 +157,11 @@ return comp; out_free2: - kfree(comp->rstate); + talloc_free(comp->rstate); out_free: - kfree(comp); + talloc_free(comp); out_fail: - return ERR_PTR(-ENOMEM); + return NULL; } @@ -153,16 +169,18 @@ void slhc_free(struct slcompress *comp) { + DEBUGP(DSLHC, "slhc_free(): Freeing compression states...\n"); + if ( comp == NULLSLCOMPR ) return; if ( comp->tstate != NULLSLSTATE ) - kfree( comp->tstate ); + talloc_free(comp->tstate ); if ( comp->rstate != NULLSLSTATE ) - kfree( comp->rstate ); + talloc_free( comp->rstate ); - kfree( comp ); + talloc_free( comp ); } @@ -187,6 +205,8 @@ } else { *cp++ = n; } + + DEBUGP(DSLHC, "encode(): n=%04x\n",n); return cp; } @@ -256,6 +276,7 @@ comp->sls_o_nontcp++; else comp->sls_o_tcp++; + DEBUGP(DSLHC, "slhc_compress(): Not a TCP packat, will not touch...\n"); return isize; } /* Extract TCP header */ @@ -271,6 +292,7 @@ ! (th->ack)){ /* TCP connection stuff; send as regular IP */ comp->sls_o_tcp++; + DEBUGP(DSLHC, "slhc_compress(): Packet is part of a TCP connection, will not touch...\n"); return isize; } /* @@ -287,6 +309,9 @@ * states via linear search. If we don't find a state * for the datagram, the oldest state is (re-)used. */ + + DEBUGP(DSLHC, "slhc_compress(): Compressible packet detected!\n"); + for ( ; ; ) { if( ip->saddr == cs->cs_ip.saddr && ip->daddr == cs->cs_ip.daddr @@ -310,11 +335,14 @@ * state points to the newest and we only need to set * xmit_oldest to update the lru linkage. */ + + DEBUGP(DSLHC, "slhc_compress(): Header not yet seen, will memorize header for the next turn...\n"); comp->sls_o_misses++; comp->xmit_oldest = lcs->cs_this; goto uncompressed; found: + DEBUGP(DSLHC, "slhc_compress(): Header already seen, trying to compress...\n"); /* * Found it -- move to the front on the connection list. */ @@ -344,6 +372,39 @@ */ oth = &cs->cs_tcp; + /* Display a little more debug information about which of the + * header fields changed unexpectedly */ + if(ip->version != cs->cs_ip.version) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->version != cs->cs_ip.version\n"); + if(ip->ihl != cs->cs_ip.ihl) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->ihl != cs->cs_ip.ihl\n"); + if(ip->tos != cs->cs_ip.tos) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->tos != cs->cs_ip.tos\n"); + if((ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))\n"); + if(ip->ttl != cs->cs_ip.ttl) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->ttl != cs->cs_ip.ttl\n"); + if(th->doff != cs->cs_tcp.doff) + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: th->doff != cs->cs_tcp.doff\n"); + if(ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) { + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0)\n"); + DEBUGP(DSLHC, "slhc_compress(): ip->ihl = %i\n", ip->ihl); + DEBUGP(DSLHC, "slhc_compress(): ip+1 = %s\n", + osmo_hexdump_nospc((uint8_t*)(ip+1),((ip->ihl)-5)*4)); + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: cs->cs_ipopt = %s\n", + osmo_hexdump_nospc((uint8_t*)(cs->cs_ipopt),((ip->ihl)-5)*4)); + } + if(th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0) { + DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)\n"); + DEBUGP(DSLHC, "slhc_compress(): th->doff = %i\n", th->doff); + DEBUGP(DSLHC, "slhc_compress(): th+1 = %s\n", + osmo_hexdump_nospc((uint8_t*)(th+1),((th->doff)-5)*4)); + DEBUGP(DSLHC, "slhc_compress(): cs->cs_tcpopt = %s\n", + osmo_hexdump_nospc((uint8_t*)cs->cs_tcpopt, + ((th->doff)-5)*4)); + } + + if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl || ip->tos != cs->cs_ip.tos || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000)) @@ -351,6 +412,7 @@ || th->doff != cs->cs_tcp.doff || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){ + DEBUGP(DSLHC, "slhc_compress(): The header contains unexpected changes, can't compress...\n"); goto uncompressed; } @@ -362,6 +424,7 @@ */ if(th->urg){ deltaS = ntohs(th->urg_ptr); + DEBUGP(DSLHC, "slhc_compress(): flag: Urgent Pointer (U) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_U; } else if(th->urg_ptr != oth->urg_ptr){ @@ -369,21 +432,29 @@ * implementation should never do this but RFC793 * doesn't prohibit the change so we have to deal * with it. */ + DEBUGP(DSLHC, "slhc_compress(): URG not set but urp changed, can't compress...\n"); goto uncompressed; } if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){ + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Window (W) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_W; } if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){ - if(deltaA > 0x0000ffff) + if(deltaA > 0x0000ffff) { + DEBUGP(DSLHC, "slhc_compress(): (deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L, can't compress...\n"); goto uncompressed; + } + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Ack (A) = 1\n"); cp = encode(cp,deltaA); changes |= NEW_A; } if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){ - if(deltaS > 0x0000ffff) + if(deltaS > 0x0000ffff) { + DEBUGP(DSLHC, "slhc_compress(): (deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L, can't compress...\n"); goto uncompressed; + } + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_S; } @@ -399,17 +470,21 @@ if(ip->tot_len != cs->cs_ip.tot_len && ntohs(cs->cs_ip.tot_len) == hlen) break; + DEBUGP(DSLHC, "slhc_compress(): Retransmitted packet detected, can't compress...\n"); goto uncompressed; case SPECIAL_I: case SPECIAL_D: /* actual changes match one of our special case encodings -- * send packet uncompressed. */ + DEBUGP(DSLHC, "slhc_compress(): Special case detected, can't compress...\n"); goto uncompressed; case NEW_S|NEW_A: if(deltaS == deltaA && deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ /* special case for echoed terminal traffic */ + DEBUGP(DSLHC, "slhc_compress(): Special case for echoed terminal traffic detected...\n"); + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1, Delta Window (W) = 1, Urgent Pointer (U) = 1\n"); changes = SPECIAL_I; cp = new_seq; } @@ -417,6 +492,8 @@ case NEW_S: if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ /* special case for data xfer */ + DEBUGP(DSLHC, "slhc_compress(): Special case for data xfer detected...\n"); + DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1, Delta Ack (A) = 1, Delta Window (W) = 1, Urgent Pointer (U) = 1\n"); changes = SPECIAL_D; cp = new_seq; } @@ -424,11 +501,14 @@ } deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id); if(deltaS != 1){ + DEBUGP(DSLHC, "slhc_compress(): flag: Delta IP ID (I) = 1\n"); cp = encode(cp,deltaS); changes |= NEW_I; } - if(th->psh) + if(th->psh) { + DEBUGP(DSLHC, "slhc_compress(): flag: Push (P) = 1\n"); changes |= TCP_PUSH_BIT; + } /* Grab the cksum before we overwrite it below. Then update our * state with this packet's header. */ @@ -445,6 +525,7 @@ if(compress_cid == 0 || comp->xmit_current != cs->cs_this){ cp = ocp; *cpp = ocp; + DEBUGP(DSLHC, "slhc_compress(): flag: Connection number (C) = 1\n"); *cp++ = changes | NEW_C; *cp++ = cs->cs_this; comp->xmit_current = cs->cs_this; @@ -456,6 +537,10 @@ *(__sum16 *)cp = csum; cp += 2; /* deltaS is now the size of the change section of the compressed header */ + + DEBUGP(DSLHC, "slhc_compress(): Delta-list length (deltaS) = %li\n",deltaS); + DEBUGP(DSLHC, "slhc_compress(): Original header len (hlen) = %i\n",hlen); + memcpy(cp,new_seq,deltaS); /* Write list of deltas */ memcpy(cp+deltaS,icp+hlen,isize-hlen); comp->sls_o_compressed++; @@ -467,6 +552,7 @@ * to use on future compressed packets in the protocol field). */ uncompressed: + DEBUGP(DSLHC, "slhc_compress(): Packet will be sent uncompressed...\n"); memcpy(&cs->cs_ip,ip,20); memcpy(&cs->cs_tcp,th,20); if (ip->ihl > 5) @@ -538,6 +624,8 @@ switch(changes & SPECIALS_MASK){ case SPECIAL_I: /* Echoed terminal traffic */ + DEBUGP(DSLHC, "slhc_uncompress(): Echoed terminal traffic detected\n"); + { register short i; i = ntohs(ip->tot_len) - hdrlen; @@ -547,11 +635,13 @@ break; case SPECIAL_D: /* Unidirectional data */ + DEBUGP(DSLHC, "slhc_uncompress(): Unidirectional data detected\n"); thp->seq = htonl( ntohl(thp->seq) + ntohs(ip->tot_len) - hdrlen); break; default: + DEBUGP(DSLHC, "slhc_uncompress(): default packet type detected\n"); if(changes & NEW_U){ thp->urg = 1; if((x = decode(&cp)) == -1) { @@ -601,6 +691,7 @@ ip->tot_len = htons(len); ip->check = 0; + DEBUGP(DSLHC, "slhc_uncompress(): making space for the reconstructed header...\n"); memmove(icp + hdrlen, cp, len - hdrlen); cp = icp; @@ -625,6 +716,7 @@ return len; bad: + DEBUGP(DSLHC, "slhc_uncompress(): bad packet detected!\n"); comp->sls_i_error++; return slhc_toss( comp ); } @@ -641,6 +733,7 @@ if(isize < 20) { /* The packet is shorter than a legal IP header */ comp->sls_i_runt++; + DEBUGP(DSLHC, "slhc_remember(): The packet is shorter than a legal IP header ==> slhc_toss()\n"); return slhc_toss( comp ); } /* Peek at the IP header's IHL field to find its length */ @@ -648,6 +741,7 @@ if(ihl < 20 / 4){ /* The IP header length field is too small */ comp->sls_i_runt++; + DEBUGP(DSLHC, "slhc_remember(): The IP header length field is too small ==> slhc_toss()\n"); return slhc_toss( comp ); } index = icp[9]; @@ -656,10 +750,12 @@ if (ip_fast_csum(icp, ihl)) { /* Bad IP header checksum; discard */ comp->sls_i_badcheck++; + DEBUGP(DSLHC, "slhc_remember(): Bad IP header checksum; discard ==> slhc_toss()\n"); return slhc_toss( comp ); } if(index > comp->rslot_limit) { comp->sls_i_error++; + DEBUGP(DSLHC, "slhc_remember(): index > comp->rslot_limit ==> slhc_toss()\n"); return slhc_toss(comp); } @@ -683,6 +779,7 @@ int slhc_toss(struct slcompress *comp) { + DEBUGP(DSLHC, "slhc_toss(): Reset compression state...\n"); if ( comp == NULLSLCOMPR ) return 0; @@ -690,55 +787,27 @@ return 0; } -#else /* CONFIG_INET */ - -int -slhc_toss(struct slcompress *comp) +void slhc_i_status(struct slcompress *comp) { - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss"); - return -EINVAL; -} -int -slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress"); - return -EINVAL; -} -int -slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, - unsigned char *ocp, unsigned char **cpp, int compress_cid) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress"); - return -EINVAL; + if (comp != NULLSLCOMPR) { + DEBUGP(DSLHC, "slhc_i_status(): %d Cmp, %d Uncmp, %d Bad, %d Tossed\n", + comp->sls_i_compressed, + comp->sls_i_uncompressed, + comp->sls_i_error, + comp->sls_i_tossed); + } } -int -slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +void slhc_o_status(struct slcompress *comp) { - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember"); - return -EINVAL; + if (comp != NULLSLCOMPR) { + DEBUGP(DSLHC, "slhc_o_status(): %d Cmp, %d Uncmp, %d AsIs, %d NotTCP %d Searches, %d Misses\n", + comp->sls_o_compressed, + comp->sls_o_uncompressed, + comp->sls_o_tcp, + comp->sls_o_nontcp, + comp->sls_o_searches, + comp->sls_o_misses); + } } -void -slhc_free(struct slcompress *comp) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free"); -} -struct slcompress * -slhc_init(int rslots, int tslots) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init"); - return NULL; -} - -#endif /* CONFIG_INET */ - -/* VJ header compression */ -EXPORT_SYMBOL(slhc_init); -EXPORT_SYMBOL(slhc_free); -EXPORT_SYMBOL(slhc_remember); -EXPORT_SYMBOL(slhc_compress); -EXPORT_SYMBOL(slhc_uncompress); -EXPORT_SYMBOL(slhc_toss); - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index 1debb2d..d5aa356 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid slhc if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 45d1780..3e66978 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -32,6 +32,7 @@ $(top_builddir)/src/gprs/oap_messages.o \ $(top_builddir)/src/gprs/gprs_llc_xid.o \ $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ + $(top_builddir)/src/gprs/slhc.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ diff --git a/openbsc/tests/slhc/Makefile.am b/openbsc/tests/slhc/Makefile.am new file mode 100644 index 0000000..d21990f --- /dev/null +++ b/openbsc/tests/slhc/Makefile.am @@ -0,0 +1,21 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) + +EXTRA_DIST = slhc_test.ok + +noinst_PROGRAMS = slhc_test + +slhc_test_SOURCES = slhc_test.c + +slhc_test_LDADD = \ + $(top_builddir)/src/gprs/slhc.o \ + $(top_builddir)/src/libcommon/libcommon.a \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOGB_LIBS) \ + $(LIBCARES_LIBS) \ + $(LIBCRYPTO_LIBS) \ + -lgtp -lrt -lm + + diff --git a/openbsc/tests/slhc/slhc_test.c b/openbsc/tests/slhc/slhc_test.c new file mode 100644 index 0000000..59a5425 --- /dev/null +++ b/openbsc/tests/slhc/slhc_test.c @@ -0,0 +1,298 @@ +/* Test SLHC/RFC1144 TCP/IP Header compression/decompression */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include +#include + +#include + +#include +#include +#include + +/* Number of compression slots (S0-1) */ +#define SLOTS 8 + +/* Maximum packet bytes to display */ +#define DISP_MAX_BYTES 100 + +/* Sample packets to test with */ +#define PACKETS_LEN 6 +char *packets[] = { + "4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27", + "4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0", + "4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01", + "4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01", + "4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a", + "4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20" +}; + +/* Compress a packet using Van Jacobson RFC1144 header compression */ +static int compress(uint8_t *data_o, uint8_t *data_i, int len, + struct slcompress *comp) +{ + uint8_t *comp_ptr; /* Not used */ + int compr_len; + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Run compressor */ + compr_len = slhc_compress(comp, data_i, len, data_o, &comp_ptr, 0); + return compr_len; +} + +/* Expand a packet using Van Jacobson RFC1144 header compression */ +static int expand(uint8_t *data_o, uint8_t *data_i, int len, + struct slcompress *comp) +{ + int data_decompressed_len; + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Handle an uncompressed packet (learn header information */ + if ((data_i[0] & SL_TYPE_UNCOMPRESSED_TCP) == SL_TYPE_UNCOMPRESSED_TCP) { + data_o[0] &= 0x4F; + data_decompressed_len = slhc_remember(comp, data_o, len); + return data_decompressed_len; + } + + /* Uncompress compressed packets */ + else if (data_o[0] & SL_TYPE_COMPRESSED_TCP) { + data_decompressed_len = slhc_uncompress(comp, data_o, len); + return data_decompressed_len; + } + + /* Regular or unknown packets will not be touched */ + return len; +} + +/* Calculate IP Header checksum */ +static uint16_t calc_ip_csum(uint8_t *data, int len) +{ + int i; + uint32_t accumulator = 0; + uint16_t *pointer = (uint16_t *) data; + + for (i = len; i > 1; i -= 2) { + accumulator += *pointer; + pointer++; + } + + if (len % 2) + accumulator += *pointer; + + accumulator = (accumulator & 0xffff) + ((accumulator >> 16) & 0xffff); + accumulator += (accumulator >> 16) & 0xffff; + return (~accumulator); +} + +/* Calculate TCP/IP checksum */ +static uint16_t calc_tcpip_csum(const void *ctx, uint8_t *packet, int len) +{ + uint8_t *buf; + uint16_t csum; + + buf = talloc_zero_size(ctx, len); + memset(buf, 0, len); + memcpy(buf, packet + 12, 8); + buf[9] = packet[9]; + buf[11] = (len - 20) & 0xFF; + buf[10] = (len - 20) >> 8 & 0xFF; + memcpy(buf + 12, packet + 20, len - 20); + csum = calc_ip_csum(buf, len - 20 + 12); + talloc_free(buf); + return csum; +} + +/* Check TCP/IP packet */ +static void check_packet(const void *ctx, uint8_t *packet, int len) +{ + /* Check IP header */ + OSMO_ASSERT(len > 20); + OSMO_ASSERT(calc_ip_csum(packet, 20) == 0); + + /* Check TCP packet */ + if (packet[9] != 0x06) + return; + OSMO_ASSERT(len > 40); + OSMO_ASSERT(calc_tcpip_csum(ctx, packet, len) == 0); +} + +/* Strip TCP options from TCP/IP packet */ +static int strip_tcp_options(const void *ctx, uint8_t *packet, int len) +{ + uint8_t doff; + uint16_t csum; + + /* Check if the packet can be handled here */ + if (len < 37) + return len; + if (packet[9] != 0x06) + return len; + + /* Strip TCP/IP options from packet */ + doff = ((packet[32] >> 4) & 0x0F) * 4; + memmove(packet + 40, packet + doff + 20, len - 40 - (doff - 20)); + len = len - (doff - 20); + + /* Repair data offset (TCP header length) */ + packet[32] &= 0x0F; + packet[32] |= 0x50; + + /* Repair checksum */ + packet[36] = 0; + packet[37] = 0; + csum = calc_tcpip_csum(ctx, packet, len); + packet[36] = csum & 0xFF; + packet[37] = csum >> 8 & 0xFF; + + /* Repair total length */ + packet[3] = len & 0xFF; + packet[2] = len >> 8 & 0xFF; + + /* Repair IP header checksum */ + packet[10] = 0; + packet[11] = 0; + csum = calc_ip_csum(packet, 20); + packet[10] = csum & 0xFF; + packet[11] = csum >> 8 & 0xFF; + printf("csum=%04x\n", csum); + + return len; +} + +/* Compress / Decompress packets */ +static void test_slhc(const void *ctx) +{ + char packet_ascii[2048]; + int i; + + struct slcompress *comp; + uint8_t packet[1024]; + int packet_len; + uint8_t packet_compr[1024]; + int packet_compr_len; + uint8_t packet_decompr[1024]; + int packet_decompr_len; + + printf("Allocating compression state...\n"); + comp = slhc_init(ctx, SLOTS, SLOTS); + OSMO_ASSERT(comp); + + for(i=0;i DISP_MAX_BYTES) + packet_compr_len = DISP_MAX_BYTES; + if (packet_len > DISP_MAX_BYTES) + packet_len = DISP_MAX_BYTES; + if (packet_decompr_len > DISP_MAX_BYTES) + packet_decompr_len = DISP_MAX_BYTES; + printf("Original Packet: (%i bytes) %s\n", packet_len, + osmo_hexdump_nospc(packet, packet_len)); + printf("DecompressedPacket: (%i bytes) %s\n", + packet_decompr_len, osmo_hexdump_nospc(packet_decompr, + packet_decompr_len)); + printf("CompressedPacket: (%i bytes) %s\n", packet_compr_len, + osmo_hexdump_nospc(packet_compr, packet_compr_len)); + slhc_o_status(comp); + slhc_o_status(comp); + + printf("\n"); + } + + printf("Freeing compression state...\n"); + slhc_free(comp); + printf("\n"); +} + +static struct log_info_cat gprs_categories[] = { + [DSNDCP] = { + .name = "DSNDCP", + .description = + "GPRS Sub-Network Dependent Control Protocol (SNDCP)", + .enabled = 1,.loglevel = LOGL_DEBUG, + }, + [DSLHC] = { + .name = "DSLHC", + .description = + "Van Jacobson RFC1144 TCP/IP header compression (SLHC)", + .enabled = 1,.loglevel = LOGL_DEBUG, + } +}; + +static struct log_info info = { + .cat = gprs_categories, + .num_cat = ARRAY_SIZE(gprs_categories), +}; + +int main(int argc, char **argv) +{ + void *ctx; + + osmo_init_logging(&info); + + ctx = talloc_named_const(NULL, 0, "slhc_ctx"); + + test_slhc(ctx); + + printf("Done\n"); + + talloc_report_full(ctx, stderr); + OSMO_ASSERT(talloc_total_blocks(ctx) == 1); + return 0; +} + +/* stubs */ +struct osmo_prim_hdr; +int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) +{ + abort(); +} diff --git a/openbsc/tests/slhc/slhc_test.ok b/openbsc/tests/slhc/slhc_test.ok new file mode 100644 index 0000000..636241d --- /dev/null +++ b/openbsc/tests/slhc/slhc_test.ok @@ -0,0 +1,52 @@ +Allocating compression state... +csum=b3a9 +Compressing... +Decompressing... +Results: +Original Packet: (52 bytes) 4510003446dd40004006a9b3c0a8646ec0a864640017ad8b81980100f3ac984d501800e371410000fffd18fffd20fffd23fffd27 +DecompressedPacket: (52 bytes) 4510003446dd40004006a9b3c0a8646ec0a864640017ad8b81980100f3ac984d501800e371410000fffd18fffd20fffd23fffd27 +CompressedPacket: (52 bytes) 7510003446dd40004000a9b3c0a8646ec0a864640017ad8b81980100f3ac984d501800e371410000fffd18fffd20fffd23fffd27 + +csum=97a9 +Compressing... +Decompressing... +Results: +Original Packet: (79 bytes) 4510004f46de40004006a997c0a8646ec0a864640017ad8b8198010cf3ac984d501800e3cda40000fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 +DecompressedPacket: (79 bytes) 4510004f46de40004006a997c0a8646ec0a864640017ad8b8198010cf3ac984d501800e3cda40000fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 +CompressedPacket: (43 bytes) df00cda4fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 + +csum=baa9 +Compressing... +Decompressing... +Results: +Original Packet: (43 bytes) 4510002b46df40004006a9bac0a8646ec0a864640017ad8b81980133f3ac989f501800e3a70a0000fffd01 +DecompressedPacket: (43 bytes) 4510002b46df40004006a9bac0a8646ec0a864640017ad8b81980133f3ac989f501800e3a70a0000fffd01 +CompressedPacket: (9 bytes) dc00a70a5227fffd01 + +csum=b9a9 +Compressing... +Decompressing... +Results: +Original Packet: (43 bytes) 4510002b46e040004006a9b9c0a8646ec0a864640017ad8b81980136f3ac98a2501800e3a7060000fffb01 +DecompressedPacket: (43 bytes) 4510002b46e040004006a9b9c0a8646ec0a864640017ad8b81980136f3ac98a2501800e3a7060000fffb01 +CompressedPacket: (7 bytes) db00a706fffb01 + +csum=7ba9 +Compressing... +Decompressing... +Results: +Original Packet: (100 bytes) 4510006846e140004006a97bc0a8646ec0a864640017ad8b81980139f3ac98a5501800e3c2d000000d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d +DecompressedPacket: (100 bytes) 4510006846e140004006a97bc0a8646ec0a864640017ad8b81980139f3ac98a5501800e3c2d000000d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d +CompressedPacket: (68 bytes) db00c2d00d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a + +csum=aca9 +Compressing... +Decompressing... +Results: +Original Packet: (54 bytes) 4510003646e240004006a9acc0a8646ec0a864640017ad8b81980179f3ac98a5501800e321fb0000706f6c6c7578206c6f67696e3a20 +DecompressedPacket: (54 bytes) 4510003646e240004006a9acc0a8646ec0a864640017ad8b81980179f3ac98a5501800e321fb0000706f6c6c7578206c6f67696e3a20 +CompressedPacket: (18 bytes) df0021fb706f6c6c7578206c6f67696e3a20 + +Freeing compression state... + +Done diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index 85a81d6..5f37b8e 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -136,3 +136,8 @@ AT_CHECK([$abs_top_builddir/tests/sndcp_xid/sndcp_xid_test], [], [expout], [ignore]) AT_CLEANUP +AT_SETUP([slhc]) +AT_KEYWORDS([slhc]) +cat $abs_srcdir/slhc/slhc_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/slhc/slhc_test], [], [expout], [ignore]) +AT_CLEANUP -- To view, visit https://gerrit.osmocom.org/635 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 Gerrit-PatchSet: 16 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Wed Aug 31 06:08:39 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Wed, 31 Aug 2016 06:08:39 +0000 Subject: [PATCH] libosmocore[master]: libosmocodedc link fix on MacOSX Message-ID: Review at https://gerrit.osmocom.org/802 libosmocodedc link fix on MacOSX Fixes the following bug: CCLD libosmocodec.la Undefined symbols for architecture x86_64: "_bitvec_get_bit_pos", referenced from: _osmo_fr_check_sid in gsm610.o "_bitvec_get_uint", referenced from: _osmo_hr_check_sid in gsm620.o ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation) make[2]: *** [libosmocodec.la] Error 1 Change-Id: Id7358b94e274b529a8da38a0b2ef8c892b6dd7a5 --- M src/codec/Makefile.am 1 file changed, 1 insertion(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/02/802/1 diff --git a/src/codec/Makefile.am b/src/codec/Makefile.am index 619897f..5c69c28 100644 --- a/src/codec/Makefile.am +++ b/src/codec/Makefile.am @@ -9,3 +9,4 @@ libosmocodec_la_SOURCES = gsm610.c gsm620.c gsm660.c gsm690.c libosmocodec_la_LDFLAGS = -version-info $(LIBVERSION) -no-undefined +libosmocodec_la_LIBADD = $(top_builddir)/src/libosmocore.la -- To view, visit https://gerrit.osmocom.org/802 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Id7358b94e274b529a8da38a0b2ef8c892b6dd7a5 Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Harald Welte From gerrit-no-reply at lists.osmocom.org Wed Aug 31 08:14:22 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 31 Aug 2016 08:14:22 +0000 Subject: libosmocore[master]: libosmocodedc link fix on MacOSX In-Reply-To: References: Message-ID: Patch Set 1: (1 comment) https://gerrit.osmocom.org/#/c/802/1//COMMIT_MSG Commit Message: Line 7: libosmocodedc link fix on MacOSX ('codec' typo) -- To view, visit https://gerrit.osmocom.org/802 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Id7358b94e274b529a8da38a0b2ef8c892b6dd7a5 Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Wed Aug 31 08:18:16 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Wed, 31 Aug 2016 08:18:16 +0000 Subject: [PATCH] openbsc[master]: V.42bis integration and unit test In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/644 to look at the new patch set (#33). V.42bis integration and unit test The previously committed V.42bis implementation has been edited to function outside IAXmodem. Debug printf statements were changed into DEBUGP statements. Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d --- M openbsc/.gitignore M openbsc/configure.ac M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/debug.h M openbsc/include/openbsc/v42bis.h M openbsc/include/openbsc/v42bis_private.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/sgsn_main.c M openbsc/src/gprs/v42bis.c M openbsc/tests/Makefile.am M openbsc/tests/testsuite.at A openbsc/tests/v42bis/Makefile.am A openbsc/tests/v42bis/v42bis_test.c A openbsc/tests/v42bis/v42bis_test.ok 14 files changed, 1,026 insertions(+), 29 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/44/644/33 diff --git a/openbsc/.gitignore b/openbsc/.gitignore index e75b9eb..6fbd463 100644 --- a/openbsc/.gitignore +++ b/openbsc/.gitignore @@ -84,6 +84,7 @@ tests/xid/xid_test tests/sndcp_xid/sndcp_xid_test tests/slhc/slhc_test +tests/v42bis/v42bis_test tests/atconfig tests/atlocal diff --git a/openbsc/configure.ac b/openbsc/configure.ac index cebabdc..173c6c8 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -233,6 +233,7 @@ tests/xid/Makefile tests/sndcp_xid/Makefile tests/slhc/Makefile + tests/v42bis/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 850eb42..9bea689 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,8 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ - iu.h slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h + iu.h slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h v42bis.h \ + v42bis_private.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 90ddca5..ca3d4ad 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -37,6 +37,7 @@ DGTPHUB, DRANAP, DSUA, + DV42BIS, Debug_LastEntry, }; diff --git a/openbsc/include/openbsc/v42bis.h b/openbsc/include/openbsc/v42bis.h index b947a61..607a58e 100644 --- a/openbsc/include/openbsc/v42bis.h +++ b/openbsc/include/openbsc/v42bis.h @@ -31,8 +31,12 @@ \section v42bis_page_sec_2 How does it work? */ +#include + #if !defined(_SPANDSP_V42BIS_H_) #define _SPANDSP_V42BIS_H_ + +#define SPAN_DECLARE(x) x #define V42BIS_MIN_STRING_SIZE 6 #define V42BIS_MAX_STRING_SIZE 250 @@ -55,6 +59,8 @@ V42BIS_COMPRESSION_MODE_ALWAYS, V42BIS_COMPRESSION_MODE_NEVER }; + +typedef void (*put_msg_func_t)(void *user_data, const uint8_t *msg, int len); /*! V.42bis compression/decompression descriptor. This defines the working state for a @@ -111,7 +117,8 @@ \param decode_user_data An opaque pointer passed to the decode callback handler. \param max_decode_len The maximum length that should be passed to the decode handler. \return The V.42bis context. */ -SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, +SPAN_DECLARE(v42bis_state_t *) v42bis_init(const void *ctx, + v42bis_state_t *s, int negotiated_p0, int negotiated_p1, int negotiated_p2, diff --git a/openbsc/include/openbsc/v42bis_private.h b/openbsc/include/openbsc/v42bis_private.h index 2c801eb..daa5ea3 100644 --- a/openbsc/include/openbsc/v42bis_private.h +++ b/openbsc/include/openbsc/v42bis_private.h @@ -120,7 +120,6 @@ v42bis_comp_state_t decompress; /*! \brief Error and flow logging control */ - logging_state_t logging; }; #endif diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 2910c02..f479d56 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -27,7 +27,7 @@ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ - slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c + slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c v42bis.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c index 894ce84..f01798b 100644 --- a/openbsc/src/gprs/sgsn_main.c +++ b/openbsc/src/gprs/sgsn_main.c @@ -297,6 +297,11 @@ .description = "RFC1144 TCP/IP Header compression (SLHC)", .enabled = 1, .loglevel = LOGL_DEBUG, }, + [DV42BIS] = { + .name = "DV42BIS", + .description = "V.42bis data compression (SNDCP)", + .enabled = 1, .loglevel = LOGL_DEBUG, + } }; static const struct log_info gprs_log_info = { diff --git a/openbsc/src/gprs/v42bis.c b/openbsc/src/gprs/v42bis.c index d025ea9..74c6db9 100644 --- a/openbsc/src/gprs/v42bis.c +++ b/openbsc/src/gprs/v42bis.c @@ -29,10 +29,6 @@ /*! \file */ -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - #include #include #include @@ -42,14 +38,13 @@ #include #include -#include "spandsp/telephony.h" -#include "spandsp/logging.h" -#include "spandsp/bit_operations.h" -#include "spandsp/async.h" -#include "spandsp/v42bis.h" +#include +#include +#include +#include -#include "spandsp/private/logging.h" -#include "spandsp/private/v42bis.h" +#define FALSE 0 +#define TRUE 1 /* Fixed parameters from the spec. */ /* Character size (bits) */ @@ -321,7 +316,7 @@ s = &ss->compress; if (!s->transparent) return; - span_log(&ss->logging, SPAN_LOG_FLOW, "Changing to compressed mode\n"); + DEBUGP(DV42BIS,"Changing to compressed mode\n"); /* Switch out of transparent now, between codes. We need to send the octet which did not match, just before switching. */ if (s->last_matched) @@ -344,7 +339,7 @@ s = &ss->compress; if (s->transparent) return; - span_log(&ss->logging, SPAN_LOG_FLOW, "Changing to transparent mode\n"); + DEBUGP(DV42BIS,"Changing to transparent mode\n"); /* Switch into transparent now, between codes, and the unmatched octet should go out in transparent mode, just below */ if (s->last_matched) @@ -543,7 +538,7 @@ { case V42BIS_ECM: /* Enter compressed mode */ - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_ECM\n"); + DEBUGP(DV42BIS,"Hit V42BIS_ECM\n"); send_string(s); s->transparent = FALSE; s->update_at = s->last_matched; @@ -552,20 +547,20 @@ continue; case V42BIS_EID: /* Escape symbol */ - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_EID\n"); + DEBUGP(DV42BIS,"Hit V42BIS_EID\n"); in = s->escape_code; s->escape_code += V42BIS_ESC_STEP; break; case V42BIS_RESET: /* Reset dictionary */ - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_RESET\n"); + DEBUGP(DV42BIS,"Hit V42BIS_RESET\n"); /* TODO: */ send_string(s); dictionary_init(s); i++; continue; default: - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_???? - %" PRIu32 "\n", in); + DEBUGP(DV42BIS,"Hit V42BIS_???? - %" PRIu32 "\n", in); return -1; } } @@ -634,7 +629,7 @@ { case V42BIS_ETM: /* Enter transparent mode */ - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_ETM\n"); + DEBUGP(DV42BIS,"Hit V42BIS_ETM\n"); s->bit_count = 0; s->transparent = TRUE; s->last_matched = 0; @@ -642,12 +637,12 @@ break; case V42BIS_FLUSH: /* Flush signal */ - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_FLUSH\n"); + DEBUGP(DV42BIS,"Hit V42BIS_FLUSH\n"); s->bit_count = 0; break; case V42BIS_STEPUP: /* Increase code word size */ - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_STEPUP\n"); + DEBUGP(DV42BIS,"Hit V42BIS_STEPUP\n"); s->v42bis_parm_c2++; s->v42bis_parm_c3 <<= 1; if (s->v42bis_parm_c2 > (s->v42bis_parm_n2 >> 3)) @@ -708,7 +703,8 @@ } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, +SPAN_DECLARE(v42bis_state_t *) v42bis_init(const void *ctx, + v42bis_state_t *s, int negotiated_p0, int negotiated_p1, int negotiated_p2, @@ -727,12 +723,10 @@ return NULL; if (s == NULL) { - if ((s = (v42bis_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (v42bis_state_t *) talloc_zero_size(ctx,sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); - span_log_init(&s->logging, SPAN_LOG_NONE, NULL); - span_log_set_protocol(&s->logging, "V.42bis"); if ((ret = v42bis_comp_init(&s->compress, negotiated_p1, negotiated_p2, encode_handler, encode_user_data, max_encode_len))) return NULL; @@ -758,6 +752,7 @@ { comp_exit(&s->compress); comp_exit(&s->decompress); + talloc_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index d5aa356..7acebc0 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid slhc +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr mm_auth xid sndcp_xid slhc v42bis if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index 5f37b8e..f18b734 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -141,3 +141,9 @@ cat $abs_srcdir/slhc/slhc_test.ok > expout AT_CHECK([$abs_top_builddir/tests/slhc/slhc_test], [], [expout], [ignore]) AT_CLEANUP + +AT_SETUP([v42bis]) +AT_KEYWORDS([v42bis]) +cat $abs_srcdir/v42bis/v42bis_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/v42bis/v42bis_test], [], [expout], [ignore]) +AT_CLEANUP diff --git a/openbsc/tests/v42bis/Makefile.am b/openbsc/tests/v42bis/Makefile.am new file mode 100644 index 0000000..9001c0f --- /dev/null +++ b/openbsc/tests/v42bis/Makefile.am @@ -0,0 +1,21 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) + +EXTRA_DIST = v42bis_test.ok + +noinst_PROGRAMS = v42bis_test + +v42bis_test_SOURCES = v42bis_test.c + +v42bis_test_LDADD = \ + $(top_builddir)/src/gprs/v42bis.o \ + $(top_builddir)/src/libcommon/libcommon.a \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOGB_LIBS) \ + $(LIBCARES_LIBS) \ + $(LIBCRYPTO_LIBS) \ + -lgtp -lrt -lm + + diff --git a/openbsc/tests/v42bis/v42bis_test.c b/openbsc/tests/v42bis/v42bis_test.c new file mode 100644 index 0000000..cbe13d5 --- /dev/null +++ b/openbsc/tests/v42bis/v42bis_test.c @@ -0,0 +1,424 @@ +/* Test v42bis Compression/Decompression */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#define P0 3 +#define P1 512 +#define P2 20 + +#define BLOCK_SIZE 1024 +#define MAX_BLOCK_SIZE 1024 + +/* Compressed sample packets, sniffed from real communication */ +#define COMPR_PACKETS_LEN 31 +char *compr_packets[] = { + "4500010268000700004006cefac0a80002550d93d740000050462c7ba7e4d1753a80184000aad500000101080a0001a670084dafb4474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992becf8918d0c9145465441939fcc6a1950a206b7e1fca38e1145eaebc129230aeb24f57bcab011c3c68829f5efe7bfcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0085a3a4e1c3466c6c649ea048d519d5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622e7fa7dac30ac602f9af40a9ef0236a54268247cd7f923946d0a8d1c3c68d1e35788c5002e54ad0a00100", + "4500010268000900004006cef8c0a80002550d93d740000050462c7ba7e4d1753a801840007e7f00000101080a0001d1cc084db0ae474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992becf8918d0c9145465441939fcc6a1950a206b7e1fca38e1145eaebc129230aeb24f57bcab011c3c68829f5efe7bfcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0085a3a4e1c3466c6c649ea048d519d5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622e7fa7dac30ac602f9af40a9ef0236a54268247cd7f923946d0a8d1c3c68d1e35788c5002e54ad0a00100", + "4500010268000b00004006cef6c0a80002550d93d740000050462c7ba7e4d1753b80193fff131c00000101080a00022884084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992be4e8918d8c9045465441939fcc6a1950a206b7e1dca38e1145eaebb929230aeb24f579cab011c3c68829f5efe7afcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0084a3a4e1c3466c6c649ea048dd19c5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622c7fa7dac30ac5c2f9af40a1ef0236a502682478dff913946d0a8d1c3c68d1e35788c5002e54ad0a00100", + "4500010268000c00004006cef5c0a80002550d93d740000050462c7ba7e4d1753b80193fff65ab00000101080a0002d5f4084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992be4e8918d8c9045465441939fcc6a1950a206b7e1dca38e1145eaebb929230aeb24f579cab011c3c68829f5efe7afcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0084a3a4e1c3466c6c649ea048dd19c5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622c7fa7dac30ac5c2f9af40a1ef0236a502682478dff913946d0a8d1c3c68d1e35788c5002e54ad0a00100", + "450001022d000f00004006ac5ec0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00", + "450001022d001000004006ac5dc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00", + "450001022d001100004006ac5cc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00", + "450001022d001200004006ac5bc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00", + "4500010268001300004006ceeec0a80002550d93d740000050462c7ba7e4d1753b80193fff7b4a00000101080a0003c054084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005bbb7e0d3b964dd9b369d7b6ddb3e60e9c372ef614beeb15ac58b2660513368cf8cdd63b68f65045ab96ed9cb58947b490d1422851a34861185923d50e9aa423f0dc490363c756d8b269e4d8cac68e9cd93b70f0804143376fe13372dcc801038f193b306a6cb5b2864d9a3b629a30b1b2b5081b353848173d7a07c6133271d4e021a3068d52347184ee81c119c69c3a72d2b079c37e4489c177e6f4902183730cde71f8a0a913d6cec21866e4c091818548fdfb329cec9831834d951a337e4e2e2174891c3baef5e8d113a38f1c336e2656148a85751d1844d6c7716da52c1f240f9b2fecf8918d0c9145465441a39f0c6b1950a40ab7f1fca38e1145ecebc129234aeb24f67bcab011c3c68829f6f1ebb7cbe4c894e731668c3052163ffa3a63d9949561e4c91123c263d0105a3a4e1c3466c8c651ea04cd519d60f3a0016f14290c2471289e61735ee9193469de8c45b3554d1fa84299c88622e73afeac30ac6037aaf40a9ef0236a54268247cd7f923946d0a8d1c3c68d1e35788c5002e58a50a10100", + "450001022d001400004006ac59c0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00", + "450001022d001500004006ac58c0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00", + "4500010239000500004006ac5cc0a800020a0901ab40001f90c286afa741a348cb801840007fcb0000050a41a348dc41a34a440000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d69786564330057b36eedfa954dd8b165cfa6ddb3e60e9c372ef6049eab95ab57b062fd02164cf8cdd53b68f640256b16ed9cb38547b490d1e22791a043efc030b2c6a91d344547e0b99306c68eabad5fd3c871958d1d39b077e0e00183c6eddcbf67e4b89103061e337660d4b86a650d9b3477c4346162e56a11366a7080164d14c6133271d4e021a3068d5134717eee818119c69c3a72d2b079837e4489bf77e6f4902103738cdc71f8a0a9d3d58ec11866e4c091818548fcf9329cec9831834d951a33783e2ef173891c3bab69cc88c1a3674f1d347a6cdcf8134bea3a30889c8fb3da4a583e48162a37a891231b19208b8ca882c63e99d432a038fd6d8339471d238ac8d793534614d549e40b956123868d1153e4d3b77f97c99129cc63cc1861242c7df275beb2092bc3c89323467ef7fc693a4e1c3466c0c631ea04cdd09d5cf3a0e96e66e81d1848e2403cc366bcd13368d2bcf98ae6aa9a3e4c7ffe0c00", + "450001025b000a00004006ac35c0a800020a0901ab40011f90c293b0a8af5e58be5018400072a60000474554202f72656470686f6e652e706e6720485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c33005cbd82154b368e59b46ad9ee597307ce1b177b066fedfa35ec583665010b266cf8cdd63b68f6543d9b76ed1cb58747b490d16268d1a34961185933d50e1aa523f0dc490363c7d6d7b169e4d8cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a6cb5b2864d9a3b629a30b1b2b5081b3538461b457a07c6133238f190518366299a3843f7c0d80c634e1d3969d8bc513fa244e03b737ac890b139c6ee387cd0d4096b07610c3372e0c8c042647e7d194e76cc98c1a64a8d1940259718ba448e9dd63466c4e01134a80e1a3d38721c8a65751d1844d2c7696d65261f240d9923dcd8918d0c9045465441839fcc6a1950a606b7e1bca38e1145e8ebd929230aeb24f485cab011c3c68829f4ede3d7cbe4c814e731668c3032d3be1a3c75c6b2296be4c91123c1830e451d270e1a3364e32c758206694fb079d07c3f9a1406923812cfb0c1b9f40c9a346fc6a2d9aaa64fd4a175d33064b894bfff812b5bc2a421b3e60c8e32860e0d00", + "4500010267001200004006ac21c0a800020a0901ab40011f90c293b0a8af5e58be80184000ee770000050aaf5e6437af5e8c230000474554202f72656470686f6e652e706e6720485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d33006fc8de41b3c72b5cb974e7cc853ca2858c164c9d42950ac3c81aae76d04c1d81e74e1a183bc8e2d64d2307593676e4ecde8183070c1ac2892b9f91e3460e1878ccd8815183ac95356cd2dc11d3848915b245d8a8c1c1fa69d43b309e90098a878c1a3454d1c461ba0706691873eac849c3e6cdfc112514df99d343860cd23188c7e183a68e5a3b126398910347061622fcfdcb70b263c60c36556acc48bab904d32572ecd8a63123060fa54a75d0e861d224532cb4ebc020223f8e6d2b3cf920b1585d62c9936c64a82c32a20a9a826468cb80c255b98deb27758c28d25f4f5119516a27e9df54868d1836464ce9ffbf20612647a65c8f316384119effd5e0a9c3968d5b234f8e1851ae94a9ec3871d098691b87aa1334518fa6cd83063d54a93090c4d978864d50aa67d0a479c3160d59357db432fd9ba66245aa0a193aac7953278d9e3f679894c1946900", + "4500010236003000004006cf03c0a80002550d93d740020050c30e84a9441d06ac80184000c2f400000101080a00052df410fc31bd474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005cbd82154b968d59b46ad9baddb3e60e9c372ef618c6fb35ecd8b26707173e9cf80dd73b68f6544dbbb6ed1cb68a47b490d16268d1a34961185933d50e1aa523f0dc49036307d7d8b369e4e0cac68e1cda3b70f080416377efe13372dcc801038f193b306a70b5b2864d9a3b629a30b1c2b5081b35384a1b457a07c6133271d4e021a306cd52347186ee81d119c69c3a72d2b079d37e4409c277e6f49021a3738cde71f8a0a923d60ec31866e4c0918185887dfc329cec9831834d951a3380522e3174891c3baff5e8d113a38f1c336e285a1c8aa5751d1844d8c7796dc52c1f24109d33f408928d8c9145465441b39f4c6b1950a60eb7011da48e1145eeebc929238aeb24f77dcab011c3c68829f7f3efbfcbe4c814e831668c3062367ffa3a64d9989561e4c91123c363d0186a3a4e1c3466cac659ea040dd29d61f3a0097f34290c24712a9e61837ee9193469de9045c3554d9fa843870600", + "4500010260004500004006cec4c0a80002550d93d740030050c3134faac89c8b2980184000578d00000101080a000535c010fc34c8474554202f6e697276616e612e63737320485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d33006fcede41b3072c5dbb78e7dcad3ca2858c164ea14aa50ac3c81aaf76d0541d81e74e1a183bcef2f64d23c7593676e4fcde8183070c1ac6913b9f91e3460e187884c2a871d6ca1a3669ee8869c2c4cad9226cd4e0801d75ea1d184f7caac143460d1aab68e238dd0303358c3975e4a461f3c6fe88128fefcce9214306ea18c8e3f04153a7edd0b841e5c0918185c87f83329cec9831834d951a33967e2ee174891c3bbaf5e8d113a38f1c336e3ac2718a05771d1844eac7d16d252e1f241985563489928d8c954546544193900c6e1950bc3ab7a11da58e11450aea292a234aee240595cab011c3c68829050f2624cce4c814ed31668c3012f7a0fc3a6fd9c49561e4c91123ce63d0702a3b4e1c3466e0c6b1ea04cdd4a36cf3a0592f952a0c2471ccc839c3268e1aab67d0a479f316cd59357db83af59b062346ab0d1f46b47933e7ce9e329c3a0d00", + "4500010264004600004006cebfc0a80002550d93d740040050c3135bab2189da61801840008f2d00000101080a000535c410fc34dc474554202f382d4269742f4c6162656c2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d3300952fbf517b07cd1e9f77f3ee9da317f38816325a48a56a152b0c236bc4da419375049e3b6960ec50fb3b388d1c6ad9d891237c070e1e3068245f1e7d468e1b3960e0316307460db556d6b04973474c132656d4f254836376d5ab7760008da3060f193568b4a28923750f8cd530e6d4919386cd9bfc234a48be33a7870c19ab632c8fc3074d1db87630c63023078e0c2c440c2294e164c78c196caad498f1547409a94be4d8e9ad478f9e187de498710352a4542cbbebc020823f4e6f2b74f920e1c81da34a966c64bc2c32a20a1a866476cb802236ba0def2c758c2872500f521951782739d854868d1836464c39a89061612647a6788f31638411ba0aebd791cb86ae0c234f8e18891e838654da71e2a03133378e562768ae2a7d9b078d7bab5861208913f20c1bfa5acfa049f3462e1ab56afa80950a38cdc68d5a214aa4a873e74fa144474a951a00", + "4500010264005800004006ceadc0a80002550d93d740050050c31389acaf7b26538018400075c900000101080a000537d010fc354a474554202f382d4269742f41636f726e2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d3300942dbf497b07cd1e9f76f1ea9d93f7f28816325a48a56af50e0c236bc2da418375049e3b6960ec48eb1b388d1c69d9d891137c070e1e306820570e7d468e1b3960e0316307468db456d6b04973474c132656d2f2548343b699aa57613c2113470d1e326ad064451347ea1e18aa61cca923270d9b37f94794887c674e0f193254c7501e870f9a3a6fed608c11148e0c2c440c2294e164c78c196caad498f1347409a94be4d8e1ad478f9e187de4987103520e1ca95874d78141047f1cde56e6f241c2713bc6942bd9c87059644415340cc9e89601252c741bdd57ea1851e4a09ea432a2ec4e72d0a90c1b316c8c9872502143c34c8e4ce91e63c608237315d6af1397cd5c19469e1c31023d060da9b4e3c44163466e9cac4ed0585dea360f9af6efefc0401227e81936f4b39e4193e64d5c3469d5f4f92a15709a8d1bb342944831a7ce9e42898a942a3500", + "4500010266007600004006ce8dc0a80002550d93d740060050c31431ada11fa06780184000f08e00000101080a00053b3c10fc35ef474554202f382d4269742f416d73747261642e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d33009733bf597b07cd9e9e78f5f2d5a379440b192da656bd9a1586913563eda0d13a02cf9d343076ac052e9c468eb56cecc819be03070f18349433973e23c78d1c30f098b103a3c65a2b6bd8a4b923a609132b6b77aac141db2ad63b309e9089a3060f193568b6a28933750f0cc830e6d4919386cd9bfd234a50be33a7870c199063308fc3074d9db87636c63023078e0c2c44103294e164c78c196caad49801957489a94be404ddaa478f9e187de4987133b2e4542cbcebc020a23f8e6f2b75f920f9d87d63cb976c64c82c32a20a9a876478cb803256ba8def2f758c28a2500f5319517a27512855868d1836464c51d8f061622647a67c8f31638491ba0defd799cba6ae0c234f8e18911e83c6d4db71e2a0314337ce562768b03a859b07cdfbab5961208943f20c1bfb5bcfa049f3662e9ab56afa849d3a388d478f5b2756bcf813e850a3484d4e9d1a00", + "4500010264007700004006ce8ec0a80002550d93d740040050c3135ddb2189e0108018400060d600000101080a00053b4010fc35e7474554202f382d4269742f41746172692e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d3300932bbf497b07cd1e9f76f1ea9d93d7f28816325a48a56a152b0c236b84da419375049e3b6960ec48dbfb378d1c69d9d891037c070e1e30681c4ffe7c468e1b3960e0316307468db456d6b04973474c132656d2f254832376d5ab77603c2113470d1e326ad068451347ea1e18a961cca923270d9b37f84794807c674e0f193252c7481e870f9aa1da2fc63023078e0c2c440a1e94e164c78c196caad498f1147409a94be4d8d9ad478f9e187de49871e311a4542cb9ebc020723fce6e2b73f920d968e7224a956c64b42c32a20a9a856472cb8022f4b90dee2a758c286250cf511951742731c854868d1836464c31887061612647a6708f31638491b908e9d789cb66ae0c234f8e18791e8386d4d971e2a03123378e562768ae26759b070d7bab58612089f3f10c9bf95acfa049f3262e9ab46afa8095fa378d468d5a1f469c8833e7ce9f41434a951a00", + "4500010264007c00004006ce89c0a80002550d93d740070050c314f3aefa37ceb18018400009f900000101080a00053e3410fc369e474554202f382d4269742f4170706c652e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d3300942dbf517b07cd1e9f76f1ea9d93f7f28816325a48a56a152b0c236bc4da419375049e3b6960ec50dbfb378d1c6ad9d891037c070e1e30681c4ffe7c468e1b3960e0316307460db556d6b04973474c132656d4f254832376d5ab77603c2113470d1e326ad068451347ea1e18a961cca923270d9ba15a4b44be33a7870c19a963248fc3074d9db7762cc63023078e0c2c400da691e164c78c196caad498f1147409a94be4d8d9ad478f9e187de49871e311a4542cb9ebc020723fce6e2b73f920d1a8dd224a956c64b42c32a20a9aa16472cb8022f6b90dee2a758c2862504f521951742731e854868d1836464c29a910cd602647a6708f31638491b908e9d789cb66ae0c234f8e18791e8386d4d971e2a03123378e562768ae2e7dc3260f1af656b1c24012e7e31936f3b59e4193e64d5c346ad5f4012bd56f9a8c19b53a84281167ce9d3f8b86942a3500", + "4500010265007d00004006ce87c0a80002550d93d740050050c3138bdcaf7b296780183cec0de600000101080a00053e3410fc368e474554202f382d4269742f447261676f6e2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d33009631bf597b07cd1e9f8df5f2d59379440b192da656bd9a1586913563eda0d13a02cf9d343076ac052e9c468eb56cecc819be03070f18349433973e23c78d1c30f098b103a3c65a2b6bd8a4b923a609132b6b79aac141db2ad63b309e9089a3068f50345bd1c499ba07c6631873eac849c3e68dfe112526df99d343868cc73198c7e183a64e5c3b1963989103470616220715ca70b263c60c36556acc804abac4d42572ecf8d6a3474f8c3e72ccb80939722a16de75601051c3dfb715a27c9074ec9e71654b363260161951054d4332bc6540192bddc6f7963a461441a847a98c28bd93208ce3d3460c1b23a6205cd89030932353bec79831c208d185f7ebcc6553d7c8932346a4c7a03175769c3868ccd08db3d5091aac4ce1e641f3fe6a561848e2883cc3c6fed63368d2bc998b66ad9a3e61a7fe4dc391e3d688132beeec0974a8519253a70600", + "4500010269008000004006ce80c0a80002550d93d740060050c3143301dfa11fa3de80183c892b5d00000101080a0005412c10fc3761474554202f382d4269742f456e74657270726973652e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f6600952f67defcc66dd03d3df7f6fd3bc72fe7112d64b4b08a552b571846d6983dda75049e3b6960ec701b7c388d1c6e8dca21be03070f183496db694e63468e1b3960e0316307460db756d6b04973474c132656dcee5483c376d6ad77603c2113470d1e326ad0784513c7ea1e18ae6110959386cd1bfe234a58be33a7870c19ae63548fc347285d3b1b63989103470616220ad3c870b263c60c36556acc986aba84d52572ecfcd6a3474f8c3e72ccb81149d22a96a3756010d91fe7b715bc7c90d4f9b891a54b36326216195105cd4332476540312bdd0678973a4614a923478f531951d0dc49d299aa0c1b316c8c98d2b9e143c64c8e4c011f63c60823781be2af63970d5e19469e1c31223d060dabbce3c44163e66e1caf4ed06c853a370f1af85ab9c2401267e41936f7bd9e4193e68d5d346ed5f4216bd5701aa142bd4eac78d1e7cfa1489596b46a3500", + "4500010268008100004006ce80c0a80002550d93d740040050c313600b2189e30280183d0e896b00000101080a000541d810fc379d474554202f382d4269742f436f6d6d6f646f72652e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f3300952f67defcc6ed1d347b7ceeedfb778e5fce235ac8686115ab56ae308cac316b074dd71178eea481b1c3edf0e23472b86563478ef11d3878c0a0d1fc79f519396ee48081c78c1d1835dc5a59c326cd1d314d985871cb530d8edb59b7de81f1844c1c3578c8a841e3154d1cab7b60bc8631a78e9c346cdef81f51c2f29d393d64c8781de3791c3e68ead0b5d3318699a032b01061e85086931d3366b0a95263c654d325ac2e916327b81e3d7a62f49163c64dc9a056b1fcae038348ff38c1ade0e5832424f88e2e61b29131b3c8882a682292f92d038ad9ea36c4c3d431a248433d4c6544019ea46154193662d81831a5e1c38889991c99223ec68c1146f03ed45fc72e1bbc328c3c3962a47a0c1a5671c78983c6ccdd385e9da0d9ea746e1e34f2b5728581248ec9336cf27b3d8326cd1bbb68dcaae943d62ae13420417aad78312350a1448d228523c3aad500", + "4500010263008200004006ce84c0a80002550d93d740050050c3138e0daf7b2cf180183962cb2f00000101080a000542b410fc3822474554202f382d4269742f454143412e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b330096dfa4bd83668f4fbb78f5cec97b79440b192da24ead7a1586913561eda0c13a02cf9d343076a4f50d9c468eb46cecc809be03070f1834902b873e23c78d1c30f098b103a3465a2b6bd8a4b923a609132b6979aac1219baad53b309e9089a3060f193568b2a28913750f0cd530e6d4919386cd9bfc234a44be33a7870c19aa63288fc3074d9db77630c63023078e0c2c440c2294e164c78c196caad498e1347489a84be4d8e1ad478f9e187de49871035264542cbaebc020823f0e6f2b73f920e1b81da34a966c64bc2c32a20a1a866474cb801216ba8dee2c758c287250cf511951762739c854868d1836464c39a89021612647a6748f31638491b90aebd789cb66ae0c234f8e18811e8346d4d971e2a03123374e562768ac26759b074dfbaa5761208913f20c1bfa59cfa049f3262e9ab46afa7c8dfa37cdc68d59214aa4a873e7cfa04347468d1a00", + "4500010262008500004006ce82c0a80002550d93d740070050c314f5defa37d29b80183c168b6100000101080a000542c810fc37e5474554202f382d4269742f4d53582e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b330095dfa0bd83668fcfba77f3cec16b79440b192da04aa56a1586913560eda0b93a02cf9d343076a0edfd9b460eb46cecc801be03070f18348e277f3e23c78d1c30f098b103a3065a2b6bd8a4b923a609132b6879aac1117b6ad53b309e9089a3060f193568b0a28903750f8cd430e6d4919386cd1bfc234a40be33a7870c19a963248fc3074d1db7762ec63023078e0c2c440a1e94e164c78c196caad498d1147409a84be4d8d9ad478f9e187de49871f33124542cb9ebc020723fce6e2b72f920d9a8fd62ca956c64b82c32a20a9a856472cb8002f6b90dee2b758c2862508f511951742731b854868d1836464c318870e1602647a6708f31638411b908e9d781cb46ae0c234f8e18791e830654d971e2a03113370e562768aa226d9b070d7baa5661208903f20c9bf958cfa049f3062e1ab46afa7885ea378d468d581f469c9853674fa0424542851a00", + "4500010265009400004006ce70c0a80002550d93d740060050c3143614a11fa986801836e1f43c00000101080a000545b010fc38b7474554202f382d4269742f4d617474656c2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d3300942dbf512b744fcfbb79f7ced17b79440b192da452b58a1586913562eda0c93a02cf9d343076a8edfd9b460eb56cecc801be03070f18348e277f3e23c78d1c30f098b103a3865a2b6bd8a4b923a609132b6a77aac111bbead53b309e9089a3060f193568b4a28923750f8cd430e6d4919386cd1bfc234a44be33a7870c19a963248fc3074d1db87630c63023078e0c2c440a1e94e164c78c196caad498f1347409a94be4d8d9ad478f9e187de498710352a4542cb9ebc020723fce6e2b74f920e1a81da34a966c64bc2c32a20a1a866472cb8022f6b90dee2c758c2862504f521951742731e854868d1836464c31889021612647a6708f31638411ba08e9d791bbd8c89323469ec7a02195769c3868cc7ca5abd5099aab4bdfe641c3de2a561848e2843cc366bed63368d2bc018a46ad9a3e60a5fe4db371a356881229eae4f97368d19152a50600", + "4500010263009900004006ce6dc0a80002550d93d740040050c313623f2189e66b801839a5739a00000101080a0005464c10fc38f3474554202f382d4269742f4f7269632e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b330095dfa4bd83668f4fc578f5eab13ca2858c1651a756bd0ac3c89ab076d0601d81e74e1a183bd2fa064e23475a3676e404df8183070c1ac895439f91e3460e1878ccd8815123ad95356cd2dc11d3848995b43cd5e0904dd5ea1d184fc8c45183878c1a3459d1c489ba0706631873eac849c3e64dfe112520df99d343860cc63194c7e18326e8768c31ccc88123030b1183086538d93163069b2a356638155d22ea12397678ebd1a327461f3966dc7c0c19158bee3a3088e08fc3db8a5c3e4838dac19872251b192e8b8ca882862119dd32a084856ea3fb4a1d238a1cd483544694dd490e36956123868d11530e2a642898c99129dd63cc186144aec2fa75e0b2912bc3c8932346a0c7a01135769c3868ccc48d93d5091aab4adde641d3beea551848e2803cc3867ed63368d2bc818b26ad9a3e5fa3f64db3716356881229e6d4d91328519151a30600", + "4500010269009e00004006ce62c0a80002550d93d740060050c3143845a11fab60801840003c1c00000101080a000547d810fc38b7474554202f382d4269742f526164696f536861636b2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f330096316be6fcc6ed1d347b7a46f60b584fe7112d64b4b08a552b5718468ad6b183a6eb083c77d2c0d8e17678711a39dcb2b123c7f80e1c3c60d068febcfa8c1c3772c0c063c60e8c1a6e89b24973474c132656dcee5483e376d6ad77603c2113470d1e326ad0784513c7ea1e189361cca923270d9b37fd4794b87c674e0f193226c7781e870f9a3a74ed748c61460e1c195888307428c3c98e1933d854a93163eae9125697c8b1135c8f1e3d31fac831e3a6e449ab587ed78141847f9ce056f0f24112127cc79731d9c8a0596444153411c9fc9601c56c751be263ea1851a4a19ea732a2004fd2b0aa0c1b316c8c98d2f061c4c54c8e4c111f63c60823781fe6af6357685e234f8e18a91e838655dd71e2a03173378e572768b6469d9b074d7cad5c61208963f20c1bfc5ecfa049f3c62e1ab76afa90b55a380d48905e2b5ecc1874e8d1a44b515ab51a00", + "4500010266009f00004006ce64c0a80002550d93d740050050c313903caf7b2f9580183d5ce4ef00000101080a0005481810fc3934474554202f382d4269742f5068696c6970732e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d3300952fbf597b07cd1e9f8cf5f2d58379440b192da85ac5aa1586913563eda0d93a02cf9d343076acfd1d9c468eb56cecc811be03070f1834922f8f3e23c78d1c30f098b103a3c65a2b41d3dc11d3848995b53cd5e0987d35eb1d184fc8c45183878c1a345cd1c4a1ba0786631873eac8492334ff881292efcce9214386e318cbe3f0415307b19d8b31ccc88123030b1183086538d93163069b2a3566441d5d82ea1239767aebd1a327461f3966dc7c0c4915cbee3a3088e08fd3db0a5d3e483672bf9872251b192e8b8ca882e60d1a32bb6540191bdd86f7953a461439a847a98c28bc931c7c2ac3460c1b23a61c5428f830932353bcc79831c2085d85f5ebc8654357869127478c448f4183eaed3871d098991b87ab133459990ecd83a63d56ad3090c40179860d7dae67d0a4792317cd5a357d8852059c46a346ae0f234ecca9b32750a322a9520d00", + "450001049b00ae00004006cc20c0a80002550d93d740050050c31396ceaf7b396e801840009ad400000101080a0005611010fc3d6b474554202f382d4269742f6d72776f6e672e67696620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d33009733bf617b07cd9e9f8ef7f6d5a379440b192da85ac5aa1586913564eda0d93a02cf9d343076b00d3e9c460eb66cecc821be03070f183496379f3e23c78d1c30f098b103a3065b2b6b92de11d3848915b63dd5e0a87d35eb1d184fc814c543460d1aae68e250dd0303328c3975e4a461f346ff881294efcce9214306e418cde3f0415347ae1d8c31ccc88123030b1183086538d93163069b2a3566442d5d82ea1239767eebd1a327461f3966dc801449154bef3a3088e48ff3db0a513e48387ac7a892251b192f8b8ca882862199de32a0909d6e033c4b1d238a1cd4a3544614df490e3e956123868d11530e2a644898c99129e063cc186184a8423578ead06563d7c8932346a6c7a04175769c3868ccd48dc3d5099aac4ce3e641f31eab561848e2843cc3a628d73368d2bca18b86ad9a3e62a9fe4db3712357881229eadce933e8d09154a92a417265848c1d307afec489074e198678e6108d31a7e8882557ae4c9111357903abdf7f7b052b96ec4f3868d51e7e1b77ae74198ef7f63d1a76ce52bf50cf4c9d7355b7ddb290634cae7cb9b4dec05f135b76c178c41d347b7e16eeabc732db16325a74cf7a07869135647bff0e3e7c075bdad3732c6f4e7c070e1ed37dcb993e23c78d1c30f07807cfd6ca1a3669ee8869c2c40adb9e6a70a8d60ae30999a278c8e4e78a260ed53d3020c33088900d43ae25204aa46818239f8d6cbc631c3a120b11ff6964a864c9e6e58ca8a54b505d220727579d3b7d06bd48158b52a6f99f72b542940f923a13ed600c39838d8c974546fc6548a63761b2d36d8067a96344913a72f428951105cd9d248a9fcab011c3c688298ad30c444398c99129e063cc18313bce683578eae8b66be4c91123d363246f003b0e1a33d2b93a41939569dc3c68d6df8181248e193967d814e57a064d9a3774d1b055d387cd1caa7fd36cdcc835618f853a63d07473510655aa0100", +}; + +/* Uncompressed sample packets, sniffed from real communication */ +#define UNCOMPR_PACKETS_LEN 8 +char *uncompr_packets[] = { + "45000236000700004006cf2cc0a80002550d93d7400000501e200da7c0c95a70801840002e3700000101080a000174140853d489474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a", + "4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27", + "4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0", + "4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01", + "4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01", + "4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a", + "4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20", + "450001a0b41140004006b8e80a0901abc0a800021f904002d5b860b5bab240ae501900ed861d0000485454502f312e3020323030204f4b0d0a5365727665723a2053696d706c65485454502f302e3620507974686f6e2f322e372e360d0a446174653a205475652c2033302041756720323031362030393a34333a303720474d540d0a436f6e74656e742d747970653a20746578742f68746d6c3b20636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a203232320d0a0d0a3c21444f43545950452068746d6c205055424c494320222d2f2f5733432f2f4454442048544d4c20332e322046696e616c2f2f454e223e3c68746d6c3e0a3c7469746c653e4469726563746f7279206c697374696e6720666f72202f3c2f7469746c653e0a3c626f64793e0a3c68323e4469726563746f7279206c697374696e6720666f72202f3c2f68323e0a3c68723e0a3c756c3e0a3c6c693e3c6120687265663d2272656470686f6e652e706e67223e72656470686f6e652e706e673c2f613e0a3c2f756c3e0a3c68723e0a3c2f626f64793e0a3c2f68746d6c3e0a", +}; + +/* Calculate IP Header checksum */ +static uint16_t calc_ip_csum(uint8_t *data, int len) +{ + int i; + uint32_t accumulator = 0; + uint16_t *pointer = (uint16_t *) data; + + for (i = len; i > 1; i -= 2) { + accumulator += *pointer; + pointer++; + } + + if (len % 2) + accumulator += *pointer; + + accumulator = (accumulator & 0xffff) + ((accumulator >> 16) & 0xffff); + accumulator += (accumulator >> 16) & 0xffff; + return (~accumulator); +} + +/* Calculate TCP/IP checksum */ +static uint16_t calc_tcpip_csum(const void *ctx, uint8_t *packet, int len) +{ + uint8_t *buf; + uint16_t csum; + + buf = talloc_zero_size(ctx, len); + memset(buf, 0, len); + memcpy(buf, packet + 12, 8); + buf[9] = packet[9]; + buf[11] = (len - 20) & 0xFF; + buf[10] = (len - 20) >> 8 & 0xFF; + memcpy(buf + 12, packet + 20, len - 20); + csum = calc_ip_csum(buf, len - 20 + 12); + talloc_free(buf); + return csum; +} + +/* A simple function to show the ascii content of a packet */ +void show_packet(uint8_t *packet, int len) +{ + int i; + char c; + for (i = 0; i < len; i++) { + c = packet[i]; + if (c >= 0x20 && c <= 0x7E) + printf("%c", c); + else + printf("."); + } + printf("\n"); +} + +/* A struct to capture the output data of compressor and decompressor */ +struct v42bis_output_buffer { + uint8_t *buf; + uint8_t *buf_pointer; + int len; +}; + +/* A simple testpattern generator */ +static void gen_test_pattern(uint8_t *data, int len) +{ + int i; + for (i = 0; i < len; i++) + data[i] = i & 0xF0; +} + +/* Handler to capture the output data from the compressor */ +void tx_v42bis_frame_handler(void *user_data, const uint8_t *pkt, int len) +{ + struct v42bis_output_buffer *output_buffer = + (struct v42bis_output_buffer *)user_data; + memcpy(output_buffer->buf_pointer, pkt, len); + output_buffer->buf_pointer += len; + output_buffer->len += len; + return; +} + +/* Handler to capture the output data from the decompressor */ +void tx_v42bis_data_handler(void *user_data, const uint8_t *buf, int len) +{ + /* stub, never used */ + OSMO_ASSERT(false); + return; +} + +/* Handler to capture the output data from the compressor */ +void rx_v42bis_frame_handler(void *user_data, const uint8_t *pkt, int len) +{ + /* stub, never used */ + OSMO_ASSERT(false); + return; +} + +/* Handler to capture the output data from the decompressor */ +void rx_v42bis_data_handler(void *user_data, const uint8_t *buf, int len) +{ + struct v42bis_output_buffer *output_buffer = + (struct v42bis_output_buffer *)user_data; + memcpy(output_buffer->buf_pointer, buf, len); + output_buffer->buf_pointer += len; + output_buffer->len += len; + return; +} + +/* Test V.42bis compression and decompression */ +static void v42bis(const void *ctx, int mode, uint8_t *testvec, int len) +{ + v42bis_state_t *tx_state; + v42bis_state_t *rx_state; + uint8_t *uncompressed_original; + uint8_t *compressed; + uint8_t *uncompressed; + + uncompressed_original = talloc_zero_size(ctx, len); + uncompressed = talloc_zero_size(ctx, len); + + /* Note: We allocate double the size for the compressed buffer, + * because in some cases the compression may increase the amount. + * of data. */ + compressed = talloc_zero_size(ctx, len * 2); + + int rc; + int rc_sum = 0; + struct v42bis_output_buffer compressed_data; + struct v42bis_output_buffer uncompressed_data; + + /* Initalize */ + tx_state = + v42bis_init(ctx, NULL, P0, P1, P2, + &tx_v42bis_frame_handler, NULL, MAX_BLOCK_SIZE, + &tx_v42bis_data_handler, NULL, MAX_BLOCK_SIZE); + OSMO_ASSERT(tx_state); + rx_state = + v42bis_init(ctx, NULL, P0, P1, P2, + &rx_v42bis_frame_handler, NULL, MAX_BLOCK_SIZE, + &rx_v42bis_data_handler, NULL, MAX_BLOCK_SIZE); + OSMO_ASSERT(rx_state); + v42bis_compression_control(tx_state, mode); + + /* Setup input data */ + memcpy(uncompressed_original, testvec, len); + + /* Run compressor */ + compressed_data.buf = compressed; + compressed_data.buf_pointer = compressed; + compressed_data.len = 0; + tx_state->compress.user_data = (&compressed_data); + rc = v42bis_compress(tx_state, uncompressed_original, len); + printf("v42bis_compress() rc=%d\n", rc); + OSMO_ASSERT(rc == 0); + rc = v42bis_compress_flush(tx_state); + printf("v42bis_compress_flush() rc=%d\n", rc); + OSMO_ASSERT(rc == 0); + + /* Decompress again */ + uncompressed_data.buf = uncompressed; + uncompressed_data.buf_pointer = uncompressed; + uncompressed_data.len = 0; + rx_state->decompress.user_data = (&uncompressed_data); + rc = v42bis_decompress(rx_state, compressed_data.buf, + compressed_data.len); + printf("v42bis_decompress() rc=%d\n", rc); + rc = v42bis_decompress_flush(rx_state); + rc_sum += rc; + printf("v42bis_decompress_flush() rc=%d\n", rc); + rc_sum += rc; + + /* Check results */ + printf("Mode: %i\n", mode); + + printf("uncompressed_original= %s ASCII:", + osmo_hexdump_nospc(uncompressed_original, len)); + show_packet(uncompressed_original, len); + printf("uncompressed= %s ASCII:", + osmo_hexdump_nospc(uncompressed_data.buf, + uncompressed_data.len)); + show_packet(uncompressed_data.buf, uncompressed_data.len); + printf("compressed= %s ASCII:", + osmo_hexdump_nospc(compressed_data.buf, compressed_data.len)); + show_packet(compressed_data.buf, compressed_data.len); + + rc = memcmp(uncompressed, uncompressed_original, len); + printf("memcmp() rc=%d\n", rc); + rc_sum += rc; + OSMO_ASSERT(rc_sum == 0); + + /* Free buffers and exit */ + v42bis_free(tx_state); + v42bis_free(rx_state); + talloc_free(uncompressed_original); + talloc_free(compressed); + talloc_free(uncompressed); + printf("\n"); +} + +/* Test V.42bis compression and decompression with generated data*/ +static void test_v42bis(const void *ctx) +{ + printf("Testing compression/decompression with generated data:\n"); + uint8_t testvec[BLOCK_SIZE]; + int len = sizeof(testvec); + gen_test_pattern(testvec, len); + v42bis(ctx, V42BIS_COMPRESSION_MODE_DYNAMIC, testvec, len); + v42bis(ctx, V42BIS_COMPRESSION_MODE_ALWAYS, testvec, len); + v42bis(ctx, V42BIS_COMPRESSION_MODE_NEVER, testvec, len); +} + +/* Test V.42bis compression and decompression with some TCP/IP packets */ +static void test_v42bis_tcpip(const void *ctx, int packet_id) +{ + uint8_t *testvec; + int len; + printf + ("Testing compression/decompression with realistic TCP/IP packets:\n"); + printf("Packet No.: %i\n", packet_id); + len = strlen(uncompr_packets[packet_id]); + testvec = talloc_zero_size(ctx, len); + len = osmo_hexparse(uncompr_packets[packet_id], testvec, len); + v42bis(ctx, V42BIS_COMPRESSION_MODE_DYNAMIC, testvec, len); + v42bis(ctx, V42BIS_COMPRESSION_MODE_ALWAYS, testvec, len); + v42bis(ctx, V42BIS_COMPRESSION_MODE_NEVER, testvec, len); + talloc_free(testvec); +} + +/* Test V.42bis decompression with real, sniffed packets */ +static void test_v42bis_tcpip_decompress(const void *ctx, int packet_id) +{ + uint8_t *compressed; + int compressed_len; + uint8_t *uncompressed; + v42bis_state_t *rx_state; + int rc; + int rc_sum = 0; + int len; + struct v42bis_output_buffer uncompressed_data; + + printf + ("Testing decompression with sniffed compressed TCP/IP packets:\n"); + printf("Packet No.: %i\n", packet_id); + len = strlen(compr_packets[packet_id]); + + uncompressed = talloc_zero_size(ctx, len); + compressed = talloc_zero_size(ctx, len); + + /* Initalize */ + rx_state = + v42bis_init(ctx, NULL, P0, P1, P2, + &rx_v42bis_frame_handler, NULL, MAX_BLOCK_SIZE, + &rx_v42bis_data_handler, NULL, MAX_BLOCK_SIZE); + OSMO_ASSERT(rx_state); + + /* Setup input data */ + compressed_len = + osmo_hexparse(compr_packets[packet_id], compressed, len); + + /* Decompress */ + uncompressed_data.buf = uncompressed; + uncompressed_data.buf_pointer = uncompressed; + uncompressed_data.len = 0; + rx_state->decompress.user_data = (&uncompressed_data); + rc = v42bis_decompress_flush(rx_state); + printf("v42bis_decompress_flush() rc=%d\n", rc); + rc_sum += rc; + rc = v42bis_decompress(rx_state, compressed, compressed_len); + printf("v42bis_decompress() rc=%d\n", rc); + rc_sum += rc; + rc = v42bis_decompress_flush(rx_state); + printf("v42bis_decompress_flush() rc=%d\n", rc); + rc_sum += rc; + + /* Check results */ + printf("compressed= %s ASCII:", + osmo_hexdump_nospc(compressed, compressed_len)); + show_packet(compressed, compressed_len); + printf("uncompressed= %s ASCII:", + osmo_hexdump_nospc(uncompressed_data.buf, + uncompressed_data.len)); + show_packet(uncompressed_data.buf, uncompressed_data.len); + + OSMO_ASSERT(calc_ip_csum(uncompressed_data.buf, 20) == 0); + OSMO_ASSERT(calc_tcpip_csum(ctx, uncompressed_data.buf, + uncompressed_data.len) == 0); + + /* Free buffers and exit */ + v42bis_free(rx_state); + talloc_free(uncompressed); + talloc_free(compressed); + printf("\n"); +} + +static struct log_info_cat gprs_categories[] = { + [DV42BIS] = { + .name = "DV42BIS", + .description = "V.42bis data compression (SNDCP)", + .enabled = 1,.loglevel = LOGL_DEBUG, + } +}; + +static struct log_info info = { + .cat = gprs_categories, + .num_cat = ARRAY_SIZE(gprs_categories), +}; + +int main(int argc, char **argv) +{ + void *v42bis_ctx; + int i; + + osmo_init_logging(&info); + + v42bis_ctx = talloc_named_const(NULL, 0, "v42bis_ctx"); + + test_v42bis(v42bis_ctx); + + for (i = 0; i < UNCOMPR_PACKETS_LEN; i++) + test_v42bis_tcpip(v42bis_ctx, i); + + for (i = 0; i < COMPR_PACKETS_LEN; i++) + test_v42bis_tcpip_decompress(v42bis_ctx, i); + + printf("Done\n"); + talloc_report_full(v42bis_ctx, stderr); + OSMO_ASSERT(talloc_total_blocks(v42bis_ctx) == 1); + return 0; +} + +/* stubs */ +struct osmo_prim_hdr; +int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) +{ + abort(); +} diff --git a/openbsc/tests/v42bis/v42bis_test.ok b/openbsc/tests/v42bis/v42bis_test.ok new file mode 100644 index 0000000..3615a76 --- /dev/null +++ b/openbsc/tests/v42bis/v42bis_test.ok @@ -0,0 +1,536 @@ +Testing compression/decompression with generated data: +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 0 +uncompressed_original= 00000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0 ASCII:................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................ +uncompressed= 00000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0 ASCII:................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................ +compressed= 000100000000000000003300040b4e9870f020428409478c58b89021c38633663c7c081162c42143264ea448b1e29429172f62c49871cc988d1b3972ec3867cec78f2041861c3468e44892244b4e9a74f2244a9429478d5ab99225cb96b366bd7c091366cc61c366cea449b3e6b469376fe2c49973dcb89d3b79f2ec396fdecf9f4081062d587028c184098d226cd83029c388119942ac58f129c58c19a562ecd8b12ac79021b1822c59722bc99429bda26cd9322ccb9831c9c2ac59f32ccd9c39d5e2ecd9b32dcfa041e102254ad4e0d1a348952a5ddab4a953a850a34e9d4ad5aad5ab59b36ae5cab5ebd7af60c58a1d5bb6ac59b468d3ae5dcbd6addbb771e3ca9d3b7740ddba07efde5d9837efc3bd7b27f6ed7bf1efdf8d81037f1c3c7864e1c2270f1f5e9938f1cbc58b67366e7cf3f1e39d9123ff0c00 ASCII:..........3...N.p. B..G.X..!..3f<|..b.!C&N.H...)./b..q....9r.8g... A..4h.H.$KN.t.$J.)G.Z..%...f.|..f.a.f..I...i7o...s...;y..9o... at ..-Xp(...."l.0)....B.X.)....b...*..!..,Yr+..)..l.2,..1...Y.,..9.....-..A..%J....H.*]...S.P.N.J....Y.j......`...[..Y.h..].....q...;w at .....].7...{'..{..........wb.......8....G..|.......\.xf..7.?..9... +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 2 +uncompressed_original= 00000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0 ASCII:................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................ +uncompressed= 00000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0 ASCII:................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................ +compressed= 0001000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0 ASCII:................................. 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................ +memcmp() rc=0 + +Testing compression/decompression with realistic TCP/IP packets: +Packet No.: 0 +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 0 +uncompressed_original= 45000236000700004006cf2cc0a80002550d93d7400000501e200da7c0c95a70801840002e3700000101080a000174140853d489474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..6.... at ..,....U... at ..P. ....Zp.. at ..7........t..S..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... +uncompressed= 45000236000700004006cf2cc0a80002550d93d7400000501e200da7c0c95a70801840002e3700000101080a000174140853d489474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..6.... at ..,....U... at ..P. ....Zp.. at ..7........t..S..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... +compressed= 4500010236000700004006cf2cc0a80002550d93d7400000501e200da7c0c95a70801840002e3700000101080a000174140853d489474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c6963330062d990358b562ddb3d6beec079e3620f61bb5dbf861d5b36f0e0c287df68bd8366cfd4b369d7ce518b78440b192d820e2d7a1486913551eda0413a02cf9d343076687d1d9b460ead6cecc891bd03070f183472ef0e3e23c78d1c30f098b103a386562b6bd8a4b923a609132b5a8bb05183633451a377603c2113470d1e326ad024451327e81e189b61cca923270d9b37eb4794107c674e0f193236c7d81d870f9a3a60ed288c61460e1c195888d0b72fc3c98e1933d854a931c3a7e4124197c8b1d35a8f1e3d31fac831e34622c5a05856d78141447d9cd656c8f241e290b9c28e1fd9c8105964441534f9c9ac9601256a701bce3fea1851a4be1e9c32a2b04e52bfa70c1b316c8c9852ff7efebb4c8e4c711e63c6082364ef9faf23960d5919469e1c31123c068da0a5e3c44163666c9ca44ed018d5f9350f9aef458fc2401267e21936e6939e4193e68d58345ad5f4791a346800 ASCII:E...6.... at ..,....U... at ..P. ....Zp.. at ..7........t..S..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, applic3.b..5.V-.=k..y.b.a.]...[6.....h..f...i..Q.xD..-..-z...5Q..A:...40vh}..F..l........4r..>#...0......V+k...#...+Z..Q.c4Q.w`r...H1(..u`.Q.....|.8d...G62D..Q.M~2.e at ......:F......(....).F..#.......#S...1.......eCV..'G...A#h.8q....'..4Fu~...{..0...x....g..y#..V5}..... +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 2 +uncompressed_original= 45000236000700004006cf2cc0a80002550d93d7400000501e200da7c0c95a70801840002e3700000101080a000174140853d489474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..6.... at ..,....U... at ..P. ....Zp.. at ..7........t..S..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... +uncompressed= 45000236000700004006cf2cc0a80002550d93d7400000501e200da7c0c95a70801840002e3700000101080a000174140853d489474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..6.... at ..,....U... at ..P. ....Zp.. at ..7........t..S..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... +compressed= 4500010236000700004006cf2cc0a80002550d93d7400000501e200da7c0c95a70801840002e3700000101080a000174140853d489474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d3133012d323030372042726f777365722f4e657446726f6e742f332e332050726f6601696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E...6.... at ..,....U... at ..P. ....Zp.. at ..7........t..S..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13.-2007 Browser/NetFront/3.3 Prof.ile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... +memcmp() rc=0 + +Testing compression/decompression with realistic TCP/IP packets: +Packet No.: 1 +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 0 +uncompressed_original= 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E.. at F.@. at .....dn..dd...........M....*.........G....^..... ..#..' +uncompressed= 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E.. at F.@. at .....dn..dd...........M....*.........G....^..... ..#..' +compressed= 451000014046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E... at F.@. at .....dn..dd...........M....*.........G....^..... ..#..' +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 1 +uncompressed_original= 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E.. at F.@. at .....dn..dd...........M....*.........G....^..... ..#..' +uncompressed= 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E.. at F.@. at .....dn..dd...........M....*.........G....^..... ..#..' +compressed= 45000013060c49026e48c104ac540d5b75268ec33367066880e588d0260203ecbdda0465d08601e65a641830800081050d062450122e013561610402dc5073444d1335550400 ASCII:E.....I.nH...T.[u&..3g.h....&......e....Zd.0......$P...5aa...PsDM.5U.. +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 2 +uncompressed_original= 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E.. at F.@. at .....dn..dd...........M....*.........G....^..... ..#..' +uncompressed= 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E.. at F.@. at .....dn..dd...........M....*.........G....^..... ..#..' +compressed= 451000014046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E... at F.@. at .....dn..dd...........M....*.........G....^..... ..#..' +memcmp() rc=0 + +Testing compression/decompression with realistic TCP/IP packets: +Packet No.: 2 +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 0 +uncompressed_original= 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E..[F. at .@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... +uncompressed= 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E..[F. at .@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... +compressed= 451000015b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E...[F. at .@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 1 +uncompressed_original= 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E..[F. at .@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... +uncompressed= 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E..[F. at .@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... +compressed= 45000013067849126ec880210958391ab6ea4c9c8767ce0cd000cb11a14d041ed87bb509caa00d03cc25c233600001020b1a0c48a0445c026ac2c808f467402040113949080c58c2260281fd461010386fa809a348fba9583a74c3d200 ASCII:E....xI.n..!.X9...L..g.......M...{.......%.3`......H.D\.j....g@ @.9I..X.&...F..8o...H..X:t... +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 2 +uncompressed_original= 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E..[F. at .@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... +uncompressed= 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E..[F. at .@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... +compressed= 451000015b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E...[F. at .@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... +memcmp() rc=0 + +Testing compression/decompression with realistic TCP/IP packets: +Packet No.: 3 +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 0 +uncompressed_original= 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E..7F. at .@.....dn..dd.......3........_.........G....c... +uncompressed= 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E..7F. at .@.....dn..dd.......3........_.........G....c... +compressed= 451000013746df40004006a9aec0a8646ec0a864640017ad8b8198013301f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E...7F. at .@.....dn..dd.......3........._.........G....c... +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 1 +uncompressed_original= 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E..7F. at .@.....dn..dd.......3........_.........G....c... +uncompressed= 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E..7F. at .@.....dn..dd.......3........_.........G....c... +compressed= 4500001306e848226ec880210958c51ab6ea4c9c8767ce0cd000cb11a14d046cd87bb549d4a00d03cc89d136600001020b1a0c48a0845c026ac2cc0804482000 ASCII:E.....H"n..!.X....L..g.......M.l.{.I.......6`......H..\.j....H . +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 2 +uncompressed_original= 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E..7F. at .@.....dn..dd.......3........_.........G....c... +uncompressed= 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E..7F. at .@.....dn..dd.......3........_.........G....c... +compressed= 451000013746df40004006a9aec0a8646ec0a864640017ad8b8198013301f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E...7F. at .@.....dn..dd.......3........._.........G....c... +memcmp() rc=0 + +Testing compression/decompression with realistic TCP/IP packets: +Packet No.: 4 +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 0 +uncompressed_original= 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E..7F. at .@.....dn..dd.......6........_.........G....d... +uncompressed= 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E..7F. at .@.....dn..dd.......6........_.........G....d... +compressed= 451000013746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E...7F. at .@.....dn..dd.......6........_.........G....d... +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 1 +uncompressed_original= 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E..7F. at .@.....dn..dd.......6........_.........G....d... +uncompressed= 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E..7F. at .@.....dn..dd.......6........_.........G....d... +compressed= 4500001306e848326ec880210958c11ab6ea4c9c8767ce0cd000cb11a14d0472d87bb5a9d4a00d03cc89a936600001020b1a0c48a0845c026ac2ce08f4472000 ASCII:E.....H2n..!.X....L..g.......M.r.{.........6`......H..\.j....G . +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 2 +uncompressed_original= 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E..7F. at .@.....dn..dd.......6........_.........G....d... +uncompressed= 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E..7F. at .@.....dn..dd.......6........_.........G....d... +compressed= 451000013746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E...7F. at .@.....dn..dd.......6........_.........G....d... +memcmp() rc=0 + +Testing compression/decompression with realistic TCP/IP packets: +Packet No.: 5 +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 0 +uncompressed_original= 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E..tF. at .@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... +uncompressed= 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E..tF. at .@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... +compressed= 451000017446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d3300386d6a41f3e68d193970d08cb82367c41c3940f1ecb1b97327549e0d6c0600 ASCII:E...tF. at .@..o..dn..dd.......9........{.........G....d..----------------3.8mjA....9p...#g..9 at ....s'T..l.. +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 1 +uncompressed_original= 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E..tF. at .@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... +uncompressed= 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E..tF. at .@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... +compressed= 4500001306dc49426ec880210958c919b6ea4c9c8767ce0cd000cb11a14d0478d87bb509d5a00d03ccf9f134600001020b1a0c48a0a45c026ac2ce40680003064e9c3973eac469530b9a376fccc8818366c41d3923e6c8018a678fcd9d3ba1f26c603300 ASCII:E.....IBn..!.X....L..g.......M.x.{.........4`......H..\.j.. at h...N.9s..iS..7o....f..9#....g...;..l`3. +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 2 +uncompressed_original= 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E..tF. at .@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... +uncompressed= 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E..tF. at .@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... +compressed= 451000017446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E...tF. at .@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... +memcmp() rc=0 + +Testing compression/decompression with realistic TCP/IP packets: +Packet No.: 6 +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 0 +uncompressed_original= 4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20 ASCII:E..BF. at .@.....dn..dd.......y..................G....opollux login: +uncompressed= 4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20 ASCII:E..BF. at .@.....dn..dd.......y..................G....opollux login: +compressed= 451000014246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20 ASCII:E...BF. at .@.....dn..dd.......y..................G....opollux login: +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 1 +uncompressed_original= 4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20 ASCII:E..BF. at .@.....dn..dd.......y..................G....opollux login: +uncompressed= 4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20 ASCII:E..BF. at .@.....dn..dd.......y..................G....opollux login: +compressed= 45000013061449526ec8802109588d1ab6ea4c9c8767ce0cd000cb11a14d04f8d87bb509d5a00d03cc759b35600001020b1a0c48a0e45d026ac2e4cc91f3e60d9e3d23dec851c3264e8f110100 ASCII:E.....IRn..!.X....L..g.......M...{.......u.5`......H..].j........=#..Q.&N.... +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 2 +uncompressed_original= 4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20 ASCII:E..BF. at .@.....dn..dd.......y..................G....opollux login: +uncompressed= 4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20 ASCII:E..BF. at .@.....dn..dd.......y..................G....opollux login: +compressed= 451000014246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20 ASCII:E...BF. at .@.....dn..dd.......y..................G....opollux login: +memcmp() rc=0 + +Testing compression/decompression with realistic TCP/IP packets: +Packet No.: 7 +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 0 +uncompressed_original= 450001a0b41140004006b8e80a0901abc0a800021f904002d5b860b5bab240ae501900ed861d0000485454502f312e3020323030204f4b0d0a5365727665723a2053696d706c65485454502f302e3620507974686f6e2f322e372e360d0a446174653a205475652c2033302041756720323031362030393a34333a303720474d540d0a436f6e74656e742d747970653a20746578742f68746d6c3b20636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a203232320d0a0d0a3c21444f43545950452068746d6c205055424c494320222d2f2f5733432f2f4454442048544d4c20332e322046696e616c2f2f454e223e3c68746d6c3e0a3c7469746c653e4469726563746f7279206c697374696e6720666f72202f3c2f7469746c653e0a3c626f64793e0a3c68323e4469726563746f7279206c697374696e6720666f72202f3c2f68323e0a3c68723e0a3c756c3e0a3c6c693e3c6120687265663d2272656470686f6e652e706e67223e72656470686f6e652e706e673c2f613e0a3c2f756c3e0a3c68723e0a3c2f626f64793e0a3c2f68746d6c3e0a ASCII:E..... at .@............. at ...`... at .P.......HTTP/1.0 200 OK..Server: SimpleHTTP/0.6 Python/2.7.6..Date: Tue, 30 Aug 2016 09:43:07 GMT..Content-type: text/html; charset=UTF-8..Content-Length: 222.....Directory listing for /..

Directory listing for /

.
..
... +uncompressed= 450001a0b41140004006b8e80a0901abc0a800021f904002d5b860b5bab240ae501900ed861d0000485454502f312e3020323030204f4b0d0a5365727665723a2053696d706c65485454502f302e3620507974686f6e2f322e372e360d0a446174653a205475652c2033302041756720323031362030393a34333a303720474d540d0a436f6e74656e742d747970653a20746578742f68746d6c3b20636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a203232320d0a0d0a3c21444f43545950452068746d6c205055424c494320222d2f2f5733432f2f4454442048544d4c20332e322046696e616c2f2f454e223e3c68746d6c3e0a3c7469746c653e4469726563746f7279206c697374696e6720666f72202f3c2f7469746c653e0a3c626f64793e0a3c68323e4469726563746f7279206c697374696e6720666f72202f3c2f68323e0a3c68723e0a3c756c3e0a3c6c693e3c6120687265663d2272656470686f6e652e706e67223e72656470686f6e652e706e673c2f613e0a3c2f756c3e0a3c68723e0a3c2f626f64793e0a3c2f68746d6c3e0a ASCII:E..... at .@............. at ...`... at .P.......HTTP/1.0 200 OK..Server: SimpleHTTP/0.6 Python/2.7.6..Date: Tue, 30 Aug 2016 09:43:07 GMT..Content-type: text/html; charset=UTF-8..Content-Length: 222.....Directory listing for /..

Directory listing for /

.
..
... +compressed= 45000101a0b41140004006b8e80a0901abc0a800021f904002d5b860b5bab240ae501900ed861d0000485454502f312e3020323030204f4b0d0a5365727665723a2053696d706c65485454502f302e3620507974686f6e2f322e372e360d0a446174653a205475652c203301302041756720323031362030393a34333a303720474d540d0a436f6e74656e742d747970653a20746578742f68746d6c3b20636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a206600356ad4c899f3078923528c5ce13205c908c58c9d6229f2848991112560c890a1050033432f2f4454442048544d4c20332e322046696e616c2f2f454e223e3c68746d6c3e0a3c7469746c653e4469726563746f7279206c697374696e672066016f72202f3c2f7469746c990068bcff2823e70c9fff6b6a943f9f7e7dfbf7f1e7d7bf9f3fb1c2ef6beafcc7d3fd3b7ced6468a34f03a404fa3373a4c64113630efdec27534e7509538d7e32ff657044a8f1bb0c82067f72f71e00 ASCII:E...... at .@............. at ...`... at .P.......HTTP/1.0 200 OK..Server: SimpleHTTP/0.6 Python/2.7.6..Date: Tue, 3.0 Aug 2016 09:43:07 GMT..Content-type: text/html; charset=UTF-8..Content-Length: f.5j......#R.\.2......b).....%`.....3C//DTD HTML 3.2 Final//EN">.Directory listing f.or /</titl..h..(#....kj.?.~}.......?...k.....;|.dh.O....3s..A.c...'SNu.S.~2.epD.......r... +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 1 +uncompressed_original= 450001a0b41140004006b8e80a0901abc0a800021f904002d5b860b5bab240ae501900ed861d0000485454502f312e3020323030204f4b0d0a5365727665723a2053696d706c65485454502f302e3620507974686f6e2f322e372e360d0a446174653a205475652c2033302041756720323031362030393a34333a303720474d540d0a436f6e74656e742d747970653a20746578742f68746d6c3b20636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a203232320d0a0d0a3c21444f43545950452068746d6c205055424c494320222d2f2f5733432f2f4454442048544d4c20332e322046696e616c2f2f454e223e3c68746d6c3e0a3c7469746c653e4469726563746f7279206c697374696e6720666f72202f3c2f7469746c653e0a3c626f64793e0a3c68323e4469726563746f7279206c697374696e6720666f72202f3c2f68323e0a3c68723e0a3c756c3e0a3c6c693e3c6120687265663d2272656470686f6e652e706e67223e72656470686f6e652e706e673c2f613e0a3c2f756c3e0a3c68723e0a3c2f626f64793e0a3c2f68746d6c3e0a ASCII:E..... at .@............. at ...`... at .P.......HTTP/1.0 200 OK..Server: SimpleHTTP/0.6 Python/2.7.6..Date: Tue, 30 Aug 2016 09:43:07 GMT..Content-type: text/html; charset=UTF-8..Content-Length: 222....<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><html>.<title>Directory listing for /..

Directory listing for /

.
..
... +uncompressed= 450001a0b41140004006b8e80a0901abc0a800021f904002d5b860b5bab240ae501900ed861d0000485454502f312e3020323030204f4b0d0a5365727665723a2053696d706c65485454502f302e3620507974686f6e2f322e372e360d0a446174653a205475652c2033302041756720323031362030393a34333a303720474d540d0a436f6e74656e742d747970653a20746578742f68746d6c3b20636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a203232320d0a0d0a3c21444f43545950452068746d6c205055424c494320222d2f2f5733432f2f4454442048544d4c20332e322046696e616c2f2f454e223e3c68746d6c3e0a3c7469746c653e4469726563746f7279206c697374696e6720666f72202f3c2f7469746c653e0a3c626f64793e0a3c68323e4469726563746f7279206c697374696e6720666f72202f3c2f68323e0a3c68723e0a3c756c3e0a3c6c693e3c6120687265663d2272656470686f6e652e706e67223e72656470686f6e652e706e673c2f613e0a3c2f756c3e0a3c68723e0a3c2f626f64793e0a3c2f68746d6c3e0a ASCII:E..... at .@............. at ...`... at .P.......HTTP/1.0 200 OK..Server: SimpleHTTP/0.6 Python/2.7.6..Date: Tue, 30 Aug 2016 09:43:07 GMT..Content-type: text/html; charset=UTF-8..Content-Length: 222.....Directory listing for /..

Directory listing for /

.
..
... +compressed= 45000003088cba4561c880210976ad6bc08080ab61ab061410316948016cbbc6e0ea556b48ac291c06c04b0462c0802557ae4c914123c68c113566c894e20442032b68eae4e1d96384153670e6bc41b3b2a58c1931728c98c2e7ce1a397164d488a18369ce2364eea0017a050f9a17236cc8248247cdcc19349acee0d1e3868d1e33748c5002e54a4e2353bbc6b903e30e9f395e4774dd7347c69a3b70def81861660d993a76d0dc0182e54a12183bf4f245e317c693cf6aa202ad51a346ce9c3f481c9162e40a972948462866ec144b91274c8c8c280143860c2d368c003f72e5c88895509e908d516344123671c8bc018e244a89203f6abf09d2e0c71d36778c0639c2a60e1a3377e4d4e133e20d1b3be1e3a44dc37e848c1f32c28f47e3fd47193967f8fc5f53a3fcf9f4ebdbbf8f3fbffefdfc89157e5f53e73f9eeedfe16b27431b7d1a2025d09f9923350e9a1873e8673f9972aa4b986af493f92f8323428ddf651034f893bbf700 ASCII:E......Ea..!.v.k....a....1iH.l....UkH.)...K.b..%W.L.A#...5f....B.+h....c..6p..A.....1r......9qd....i.#d...z....#l.$.G...4........3t.P..JN#S.......9^Gt.sG..;p...af..:v.....J..;..E.....j...Q.F..?H..b...)HF(f..K.'L..(.C..-6..?r....P...QcD.6q....$J. ?j......6w..9....3w...3...;...M.~...2..G..G.9g.._S........?......~_S.?....k'C.}. %...#5...s.g?.r.K.j.../.#B..e.4..... +memcmp() rc=0 + +v42bis_compress() rc=0 +v42bis_compress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +Mode: 2 +uncompressed_original= 450001a0b41140004006b8e80a0901abc0a800021f904002d5b860b5bab240ae501900ed861d0000485454502f312e3020323030204f4b0d0a5365727665723a2053696d706c65485454502f302e3620507974686f6e2f322e372e360d0a446174653a205475652c2033302041756720323031362030393a34333a303720474d540d0a436f6e74656e742d747970653a20746578742f68746d6c3b20636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a203232320d0a0d0a3c21444f43545950452068746d6c205055424c494320222d2f2f5733432f2f4454442048544d4c20332e322046696e616c2f2f454e223e3c68746d6c3e0a3c7469746c653e4469726563746f7279206c697374696e6720666f72202f3c2f7469746c653e0a3c626f64793e0a3c68323e4469726563746f7279206c697374696e6720666f72202f3c2f68323e0a3c68723e0a3c756c3e0a3c6c693e3c6120687265663d2272656470686f6e652e706e67223e72656470686f6e652e706e673c2f613e0a3c2f756c3e0a3c68723e0a3c2f626f64793e0a3c2f68746d6c3e0a ASCII:E..... at .@............. at ...`... at .P.......HTTP/1.0 200 OK..Server: SimpleHTTP/0.6 Python/2.7.6..Date: Tue, 30 Aug 2016 09:43:07 GMT..Content-type: text/html; charset=UTF-8..Content-Length: 222.....Directory listing for /..

Directory listing for /

.
..
... +uncompressed= 450001a0b41140004006b8e80a0901abc0a800021f904002d5b860b5bab240ae501900ed861d0000485454502f312e3020323030204f4b0d0a5365727665723a2053696d706c65485454502f302e3620507974686f6e2f322e372e360d0a446174653a205475652c2033302041756720323031362030393a34333a303720474d540d0a436f6e74656e742d747970653a20746578742f68746d6c3b20636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a203232320d0a0d0a3c21444f43545950452068746d6c205055424c494320222d2f2f5733432f2f4454442048544d4c20332e322046696e616c2f2f454e223e3c68746d6c3e0a3c7469746c653e4469726563746f7279206c697374696e6720666f72202f3c2f7469746c653e0a3c626f64793e0a3c68323e4469726563746f7279206c697374696e6720666f72202f3c2f68323e0a3c68723e0a3c756c3e0a3c6c693e3c6120687265663d2272656470686f6e652e706e67223e72656470686f6e652e706e673c2f613e0a3c2f756c3e0a3c68723e0a3c2f626f64793e0a3c2f68746d6c3e0a ASCII:E..... at .@............. at ...`... at .P.......HTTP/1.0 200 OK..Server: SimpleHTTP/0.6 Python/2.7.6..Date: Tue, 30 Aug 2016 09:43:07 GMT..Content-type: text/html; charset=UTF-8..Content-Length: 222.....Directory listing for /..

Directory listing for /

.
..
... +compressed= 45000101a0b41140004006b8e80a0901abc0a800021f904002d5b860b5bab240ae501900ed861d0000485454502f312e3020323030204f4b0d0a5365727665723a2053696d706c65485454502f302e3620507974686f6e2f322e372e360d0a446174653a205475652c203301302041756720323031362030393a34333a303720474d540d0a436f6e74656e742d747970653a20746578742f68746d6c3b20636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a203232320d0a0d0a3c21444f43545950452068746d6c205055424c494320222d2f2f5733432f2f4454442048544d4c20332e322046696e616c2f2f454e223e3c68746d6c3e0a3c7469746c653e4469726563746f7279206c697374696e672066016f72202f3c2f7469746c653e0a3c626f64793e0a3c68323e4469726563746f7279206c697374696e6720666f72202f3c2f68323e0a3c68723e0a3c756c3e0a3c6c693e3c6120687265663d2272656470686f6e652e706e67223e72656470686f6e652e706e673c2f613e0a3c2f756c3e0a3c68723e0a3c2f626f64793e0a3c2f68746d6c3e0a ASCII:E...... at .@............. at ...`... at .P.......HTTP/1.0 200 OK..Server: SimpleHTTP/0.6 Python/2.7.6..Date: Tue, 3.0 Aug 2016 09:43:07 GMT..Content-type: text/html; charset=UTF-8..Content-Length: 222.....Directory listing f.or /..

Directory listing for /

.
..
... +memcmp() rc=0 + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 0 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010268000700004006cefac0a80002550d93d740000050462c7ba7e4d1753a80184000aad500000101080a0001a670084dafb4474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992becf8918d0c9145465441939fcc6a1950a206b7e1fca38e1145eaebc129230aeb24f57bcab011c3c68829f5efe7bfcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0085a3a4e1c3466c6c649ea048d519d5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622e7fa7dac30ac602f9af40a9ef0236a54268247cd7f923946d0a8d1c3c68d1e35788c5002e54ad0a00100 ASCII:E...h.... at .......U...@..PF,{...u:.. at ............p.M..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed3.Z.z.+..Y.h.......7......k..e...|...;h.L=.v....G..."...Ga.Y.....#..I.c....i.......;p..A#...3r......;0jh...M.;b.0.....58F.5z...2q..!..MR4q.......:r..y.~D..w...!cs..q........f......}.2...1.M..3|J..t..;........3n$R..eu..D..im.,.$..+......EFTA...j.P........E...)#..$.{......).........1f.0B...:b...a...#.c..Z:N.4f..I...Q._...^.(.$q&.ac>..4i..E.UM..A..."..}.0.`/.....#jT&.G...9F.......5x.P..J.... +uncompressed= 45000268000700004006cefac0a80002550d93d740000050462c7ba7e4d1753a80184000aad500000101080a0001a670084dafb4474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a49662d4d6f6469666965642d53696e63653a205475652c2032332041756720323031362031323a33343a323920474d540d0a0d0a ASCII:E..h.... at .......U...@..PF,{...u:.. at ............p.M..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..If-Modified-Since: Tue, 23 Aug 2016 12:34:29 GMT.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 1 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010268000900004006cef8c0a80002550d93d740000050462c7ba7e4d1753a801840007e7f00000101080a0001d1cc084db0ae474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992becf8918d0c9145465441939fcc6a1950a206b7e1fca38e1145eaebc129230aeb24f57bcab011c3c68829f5efe7bfcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0085a3a4e1c3466c6c649ea048d519d5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622e7fa7dac30ac602f9af40a9ef0236a54268247cd7f923946d0a8d1c3c68d1e35788c5002e54ad0a00100 ASCII:E...h.... at .......U...@..PF,{...u:.. at .~............M..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed3.Z.z.+..Y.h.......7......k..e...|...;h.L=.v....G..."...Ga.Y.....#..I.c....i.......;p..A#...3r......;0jh...M.;b.0.....58F.5z...2q..!..MR4q.......:r..y.~D..w...!cs..q........f......}.2...1.M..3|J..t..;........3n$R..eu..D..im.,.$..+......EFTA...j.P........E...)#..$.{......).........1f.0B...:b...a...#.c..Z:N.4f..I...Q._...^.(.$q&.ac>..4i..E.UM..A..."..}.0.`/.....#jT&.G...9F.......5x.P..J.... +uncompressed= 45000268000900004006cef8c0a80002550d93d740000050462c7ba7e4d1753a801840007e7f00000101080a0001d1cc084db0ae474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a49662d4d6f6469666965642d53696e63653a205475652c2032332041756720323031362031323a33343a323920474d540d0a0d0a ASCII:E..h.... at .......U...@..PF,{...u:.. at .~............M..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..If-Modified-Since: Tue, 23 Aug 2016 12:34:29 GMT.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 2 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010268000b00004006cef6c0a80002550d93d740000050462c7ba7e4d1753b80193fff131c00000101080a00022884084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992be4e8918d8c9045465441939fcc6a1950a206b7e1dca38e1145eaebb929230aeb24f579cab011c3c68829f5efe7afcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0084a3a4e1c3466c6c649ea048dd19c5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622c7fa7dac30ac5c2f9af40a1ef0236a502682478dff913946d0a8d1c3c68d1e35788c5002e54ad0a00100 ASCII:E...h.... at .......U...@..PF,{...u;..?...........(..M.XGET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed3.Z.z.+..Y.h.......7......k..e...|...;h.L=.v....G..."...Ga.Y.....#..I.c....i.......;p..A#...3r......;0jh...M.;b.0.....58F.5z...2q..!..MR4q.......:r..y.~D..w...!cs..q........f......}.2...1.M..3|J..t..;........3n$R..eu..D..im.,.$..+......EFTA...j.P........E...)#..$.y......).........1f.0B...:b...a...#.c..J:N.4f..I....._...^.(.$q&.ac>..4i..E.UM..A..."..}.0.\/.....#jP&.G...9F.......5x.P..J.... +uncompressed= 45000268000b00004006cef6c0a80002550d93d740000050462c7ba7e4d1753b80193fff131c00000101080a00022884084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a49662d4d6f6469666965642d53696e63653a205475652c2032332041756720323031362031323a33343a323920474d540d0a0d0a ASCII:E..h.... at .......U...@..PF,{...u;..?...........(..M.XGET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..If-Modified-Since: Tue, 23 Aug 2016 12:34:29 GMT.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 3 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010268000c00004006cef5c0a80002550d93d740000050462c7ba7e4d1753b80193fff65ab00000101080a0002d5f4084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992be4e8918d8c9045465441939fcc6a1950a206b7e1dca38e1145eaebb929230aeb24f579cab011c3c68829f5efe7afcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0084a3a4e1c3466c6c649ea048dd19c5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622c7fa7dac30ac5c2f9af40a1ef0236a502682478dff913946d0a8d1c3c68d1e35788c5002e54ad0a00100 ASCII:E...h.... at .......U...@..PF,{...u;..?.e............M.XGET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed3.Z.z.+..Y.h.......7......k..e...|...;h.L=.v....G..."...Ga.Y.....#..I.c....i.......;p..A#...3r......;0jh...M.;b.0.....58F.5z...2q..!..MR4q.......:r..y.~D..w...!cs..q........f......}.2...1.M..3|J..t..;........3n$R..eu..D..im.,.$..+......EFTA...j.P........E...)#..$.y......).........1f.0B...:b...a...#.c..J:N.4f..I....._...^.(.$q&.ac>..4i..E.UM..A..."..}.0.\/.....#jP&.G...9F.......5x.P..J.... +uncompressed= 45000268000c00004006cef5c0a80002550d93d740000050462c7ba7e4d1753b80193fff65ab00000101080a0002d5f4084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a49662d4d6f6469666965642d53696e63653a205475652c2032332041756720323031362031323a33343a323920474d540d0a0d0a ASCII:E..h.... at .......U...@..PF,{...u;..?.e............M.XGET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..If-Modified-Since: Tue, 23 Aug 2016 12:34:29 GMT.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 4 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 450001022d000f00004006ac5ec0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00 ASCII:E...-.... at ..^........ at ..@F.......P. at ..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application3.\....g..8o\...vj..Y........w..I..k.9`..h!....;{.0....4>G........O......9.w........g......3v`..je..4w.4ab.j.6jpd.....'d...CF...h....#2.9u..a.&...x...!CF.....AS....1...#.....e8.1c..*5f.D\...9vF....G..:h..H.&..u`...g...|...._"E62...Q..{2.e at 9z..q.:F.Y....(....).F..#..o..-.#S...1......`e.U..'G...y.s.8h.d......1..AS}gO.H. <....3h.......>Eo... +uncompressed= 4500022d000f00004006ac5ec0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a2031302e392e312e3137313a383030300d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..-.... at ..^........ at ..@F.......P. at ..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: 10.9.1.171:8000..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 5 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 450001022d001000004006ac5dc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00 ASCII:E...-.... at ..]........ at ..@F.......P. at ..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application3.\....g..8o\...vj..Y........w..I..k.9`..h!....;{.0....4>G........O......9.w........g......3v`..je..4w.4ab.j.6jpd.....'d...CF...h....#2.9u..a.&...x...!CF.....AS....1...#.....e8.1c..*5f.D\...9vF....G..:h..H.&..u`...g...|...._"E62...Q..{2.e at 9z..q.:F.Y....(....).F..#..o..-.#S...1......`e.U..'G...y.s.8h.d......1..AS}gO.H. <....3h.......>Eo... +uncompressed= 4500022d001000004006ac5dc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a2031302e392e312e3137313a383030300d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..-.... at ..]........ at ..@F.......P. at ..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: 10.9.1.171:8000..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 6 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 450001022d001100004006ac5cc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00 ASCII:E...-.... at ..\........ at ..@F.......P. at ..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application3.\....g..8o\...vj..Y........w..I..k.9`..h!....;{.0....4>G........O......9.w........g......3v`..je..4w.4ab.j.6jpd.....'d...CF...h....#2.9u..a.&...x...!CF.....AS....1...#.....e8.1c..*5f.D\...9vF....G..:h..H.&..u`...g...|...._"E62...Q..{2.e at 9z..q.:F.Y....(....).F..#..o..-.#S...1......`e.U..'G...y.s.8h.d......1..AS}gO.H. <....3h.......>Eo... +uncompressed= 4500022d001100004006ac5cc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a2031302e392e312e3137313a383030300d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..-.... at ..\........ at ..@F.......P. at ..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: 10.9.1.171:8000..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 7 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 450001022d001200004006ac5bc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00 ASCII:E...-.... at ..[........ at ..@F.......P. at ..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application3.\....g..8o\...vj..Y........w..I..k.9`..h!....;{.0....4>G........O......9.w........g......3v`..je..4w.4ab.j.6jpd.....'d...CF...h....#2.9u..a.&...x...!CF.....AS....1...#.....e8.1c..*5f.D\...9vF....G..:h..H.&..u`...g...|...._"E62...Q..{2.e at 9z..q.:F.Y....(....).F..#..o..-.#S...1......`e.U..'G...y.s.8h.d......1..AS}gO.H. <....3h.......>Eo... +uncompressed= 4500022d001200004006ac5bc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a2031302e392e312e3137313a383030300d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..-.... at ..[........ at ..@F.......P. at ..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: 10.9.1.171:8000..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 8 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010268001300004006ceeec0a80002550d93d740000050462c7ba7e4d1753b80193fff7b4a00000101080a0003c054084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005bbb7e0d3b964dd9b369d7b6ddb3e60e9c372ef614beeb15ac58b2660513368cf8cdd63b68f65045ab96ed9cb58947b490d1422851a34861185923d50e9aa423f0dc490363c756d8b269e4d8cac68e9cd93b70f0804143376fe13372dcc801038f193b306a6cb5b2864d9a3b629a30b1b2b5081b353848173d7a07c6133271d4e021a3068d52347184ee81c119c69c3a72d2b079c37e4489c177e6f4902183730cde71f8a0a913d6cec21866e4c091818548fdfb329cec9831834d951a337e4e2e2174891c3baef5e8d113a38f1c336e2656148a85751d1844d6c7716da52c1f240f9b2fecf8918d0c9145465441a39f0c6b1950a40ab7f1fca38e1145ecebc129234aeb24f67bcab011c3c68829f6f1ebb7cbe4c894e731668c3052163ffa3a63d9949561e4c91123c263d0105a3a4e1c3466c8c651ea04cd519d60f3a0016f14290c2471289e61735ee9193469de8c45b3554d1fa84299c88622e73afeac30ac6037aaf40a9ef0236a54268247cd7f923946d0a8d1c3c68d1e35788c5002e58a50a10100 ASCII:E...h.... at .......U...@..PF,{...u;..?.{J.........T.M.XGET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed3.[.~.;.M..i.......7.......X.f..6....;h.PE......G...B(Q.Ha.Y#....#..I.c.V..i.......;p..AC7o.3r......;0jl...M.;b.0.....58H.=z...2q..!...R4q.......:r..y.~D..w...!.s..q........f.....H..2...1.M..3~N.!t..;........3n&V...u..D..qm.,.$../......EFTA...k.P........E...)#J.$.{......).........1f.0R.?.:c...a...#.c..Z:N.4f..Q...Q.`...o.).$q(.as^..4i..E.UM..B...".:..0.`7.....#jT&.G...9F.......5x.P...P... +uncompressed= 45000268001300004006ceeec0a80002550d93d740000050462c7ba7e4d1753b80193fff7b4a00000101080a0003c054084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a49662d4d6f6469666965642d53696e63653a205475652c2032332041756720323031362031323a33343a323920474d540d0a0d0a ASCII:E..h.... at .......U...@..PF,{...u;..?.{J.........T.M.XGET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..If-Modified-Since: Tue, 23 Aug 2016 12:34:29 GMT.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 9 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 450001022d001400004006ac59c0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00 ASCII:E...-.... at ..Y........@.. at F.......P.@..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application3.\....g..8o\...vj..Y........w..I..k.9`..h!....;{.0....4>G........O......9.w........g......3v`..je..4w.4ab.j.6jpd.....'d...CF...h....#2.9u..a.&...x...!CF.....AS....1...#.....e8.1c..*5f.D\...9vF....G..:h..H.&..u`...g...|...._"E62...Q..{2.e at 9z..q.:F.Y....(....).F..#..o..-.#S...1......`e.U..'G...y.s.8h.d......1..AS}gO.H. <....3h.......>Eo... +uncompressed= 4500022d001400004006ac59c0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a2031302e392e312e3137313a383030300d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..-.... at ..Y........@.. at F.......P.@..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: 10.9.1.171:8000..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 10 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 450001022d001500004006ac58c0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00 ASCII:E...-.... at ..X........@.. at F.......P.@..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application3.\....g..8o\...vj..Y........w..I..k.9`..h!....;{.0....4>G........O......9.w........g......3v`..je..4w.4ab.j.6jpd.....'d...CF...h....#2.9u..a.&...x...!CF.....AS....1...#.....e8.1c..*5f.D\...9vF....G..:h..H.&..u`...g...|...._"E62...Q..{2.e at 9z..q.:F.Y....(....).F..#..o..-.#S...1......`e.U..'G...y.s.8h.d......1..AS}gO.H. <....3h.......>Eo... +uncompressed= 4500022d001500004006ac58c0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a2031302e392e312e3137313a383030300d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..-.... at ..X........@.. at F.......P.@..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: 10.9.1.171:8000..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 11 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010239000500004006ac5cc0a800020a0901ab40001f90c286afa741a348cb801840007fcb0000050a41a348dc41a34a440000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d69786564330057b36eedfa954dd8b165cfa6ddb3e60e9c372ef6049eab95ab57b062fd02164cf8cdd53b68f640256b16ed9cb38547b490d1e22791a043efc030b2c6a91d344547e0b99306c68eabad5fd3c871958d1d39b077e0e00183c6eddcbf67e4b89103061e337660d4b86a650d9b3477c4346162e56a11366a7080164d14c6133271d4e021a3068d5134717eee818119c69c3a72d2b079837e4489bf77e6f4902103738cdc71f8a0a9d3d58ec11866e4c091818548fcf9329cec9831834d951a33783e2ef173891c3bab69cc88c1a3674f1d347a6cdcf8134bea3a30889c8fb3da4a583e48162a37a891231b19208b8ca882c63e99d432a038fd6d8339471d238ac8d793534614d549e40b956123868d1153e4d3b77f97c99129cc63cc1861242c7df275beb2092bc3c89323467ef7fc693a4e1c3466c0c631ea04cdd09d5cf3a0e96e66e81d1848e2403cc366bcd13368d2bcf98ae6aa9a3e4c7ffe0c00 ASCII:E...9.... at ..\........ at .......A.H...@.......A.H.A.JD..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed3.W.n...M..e.......7.......W.b...L...;h.@%k.....G....'..C..0....4EG........_..q...9.w........g......3v`..je..4w.4ab.j.6jp..M...2q..!...Q4q~......:r..y.~D..w...!.s..q........f.....H..2...1.M..3x>..s..;.i....gO.4zl...K.:0.....JX>H.*7..#.. .....>..2.8.m.9G.#....SF..I...a#...S.......).c..a$,}.u...+...#F~..i:N.4f..1.....\...nf...H.@<.f..3h.......>L.... +uncompressed= 45000239000500004006ac5cc0a800020a0901ab40001f90c286afa741a348cb801840007fcb0000050a41a348dc41a34a440000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a2031302e392e312e3137313a383038300d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..9.... at ..\........ at .......A.H...@.......A.H.A.JD..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: 10.9.1.171:8080..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 12 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 450001025b000a00004006ac35c0a800020a0901ab40011f90c293b0a8af5e58be5018400072a60000474554202f72656470686f6e652e706e6720485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c33005cbd82154b368e59b46ad9ee597307ce1b177b066fedfa35ec583665010b266cf8cdd63b68f6543d9b76ed1cb58747b490d16268d1a34961185933d50e1aa523f0dc490363c7d6d7b169e4d8cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a6cb5b2864d9a3b629a30b1b2b5081b3538461b457a07c6133238f190518366299a3843f7c0d80c634e1d3969d8bc513fa244e03b737ac890b139c6ee387cd0d4096b07610c3372e0c8c042647e7d194e76cc98c1a64a8d1940259718ba448e9dd63466c4e01134a80e1a3d38721c8a65751d1844d2c7696d65261f240d9923dcd8918d0c9045465441839fcc6a1950a606b7e1bca38e1145e8ebd929230aeb24f485cab011c3c68829f4ede3d7cbe4c814e731668c3032d3be1a3c75c6b2296be4c91123c1830e451d270e1a3364e32c758206694fb079d07c3f9a1406923812cfb0c1b9f40c9a346fc6a2d9aaa64fd4a175d33064b894bfff812b5bc2a421b3e60c8e32860e0d00 ASCII:E...[.... at ..5........@........^X.P. at .r...GET /redphone.png HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed,3.\...K6.Y.j..Ys....{.o..5.X6e..&l...;h.T=.v....G...bh..Ia.Y3....#..I.c....i.......;p..A#...3r......;0jl...M.;b.0.....58F.Ez...28..Q.f).8C....cN.9i..Q?.D.;sz...9..8|...k.a.3r...Bd~}.Nv....J..@%...D...4f...4...=8r..eu..D..ime&.$..#......EFTA...j.P........E...)#..$........).........1f.02.......;h.TM......G...bh..Ia.Y3....#..I.c....i.......;p..Acw..3r......;0jp...M.;b.0.....58J.Ez...2q..!...R4q.......:r..y.~D..w...!.s..q...#....f......}.2...1.M..3.R.1t..;........3n(Z...u..D..ym.,.$..3......EFTA..Lk.P........E...)#..$.}......).........1f.0b6..:d...a...#.c..j:N.4f..Y.....a....4).$q*.a.~..4i..E.UM..C... +uncompressed= 45000236003000004006cf03c0a80002550d93d740020050c30e84a9441d06ac80184000c2f400000101080a00052df410fc31bd474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..6.0.. at .......U...@..P....D..... at ...........-...1.GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 15 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010260004500004006cec4c0a80002550d93d740030050c3134faac89c8b2980184000578d00000101080a000535c010fc34c8474554202f6e697276616e612e63737320485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d33006fcede41b3072c5dbb78e7dcad3ca2858c164ea14aa50ac3c81aaf76d0541d81e74e1a183bcef2f64d23c7593676e4fcde8183070c1ac6913b9f91e3460e187884c2a871d6ca1a3669ee8869c2c4cad9226cd4e0801d75ea1d184f7caac143460d1aab68e238dd0303358c3975e4a461f3c6fe88128fefcce9214306ea18c8e3f04153a7edd0b841e5c0918185c87f83329cec9831834d951a33967e2ee174891c3bbaf5e8d113a38f1c336e3ac2718a05771d1844eac7d16d252e1f241985563489928d8c954546544193900c6e1950bc3ab7a11da58e11450aea292a234aee240595cab011c3c68829050f2624cce4c814ed31668c3012f7a0fc3a6fd9c49561e4c91123ce63d0702a3b4e1c3466e0c6b1ea04cdd4a36cf3a0592f952a0c2471ccc839c3268e1aab67d0a479f316cd59357db83af59b062346ab0d1f46b47933e7ce9e329c3a0d00 ASCII:E...`.E.. at .......U...@..P..O....).. at .W.........5...4.GET /nirvana.css HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xm3.o..A..,].x...<....N.J......v.T...N..;...M#.Y6v..........;...F..x...q...6i..i...."l....u...O|..CF...h.8...5.9u..a.........!C......AS....A........2...1.M..3.~..t..;........3n:.q..w..D...m%..$..V4.....EFTA...n.P.:......E..)*#J.$........)..&$.....1f.0....:o...a...#.c.p*;N.4f........l..Y/.*.$q..9.&...g..y...Y5}.:...#F...F.y3...2.:.. +uncompressed= 45000260004500004006cec4c0a80002550d93d740030050c3134faac89c8b2980184000578d00000101080a000535c010fc34c8474554202f6e697276616e612e63737320485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..`.E.. at .......U...@..P..O....).. at .W.........5...4.GET /nirvana.css HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 16 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010264004600004006cebfc0a80002550d93d740040050c3135bab2189da61801840008f2d00000101080a000535c410fc34dc474554202f382d4269742f4c6162656c2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d3300952fbf517b07cd1e9f77f3ee9da317f38816325a48a56a152b0c236bc4da419375049e3b6960ec50fb3b388d1c6ad9d891237c070e1e3068245f1e7d468e1b3960e0316307460db556d6b04973474c132656d4f254836376d5ab7760008da3060f193568b4a28923750f8cd530e6d4919386cd9bfc234a48be33a7870c19ab632c8fc3074d1db87630c63023078e0c2c440c2294e164c78c196caad498f1547409a94be4d8e9ad478f9e187de498710352a4542cbbebc020823f4e6f2b74f920e1c81da34a966c64bc2c32a20a1a866476cb802236ba0def2c758c2872500f521951782739d854868d1836464c39a89061612647a6788f31638411ba0aebd791cb86ae0c234f8e18891e838654da71e2a03133378e562768ae2a7d9b078d7bab5861208913f20c1bfa5acfa049f3462e1ab56afa80950a38cdc68d5a214aa4a873e74fa144474a951a00 ASCII:E...d.F.. at .......U...@..P..[.!..a.. at ..-........5...4.GET /8-Bit/Label.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtm3../.Q{....w........2ZH.j.+.#k..A.u..;i`.P.;8..j...#|...0h$_.}F..9`.1c.F..V..IsGL.&V..T.cv..w`......5h...#u...0........#JH.3.....c,...M..v0.0#...,D."..d...l....Tt..K....G...}..q.R.T,... .?No+t. ....J.ld.,2....dv.."6...,u.(rP.R.Qx'9.T...6FL9..aa&G.x.1c...........#O......T.q..137.V'h.*}...{.Xa ......Z..I.F...j....8...Z!J..s.O.DGJ... +uncompressed= 45000264004600004006cebfc0a80002550d93d740040050c3135bab2189da61801840008f2d00000101080a000535c410fc34dc474554202f382d4269742f4c6162656c2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..d.F.. at .......U...@..P..[.!..a.. at ..-........5...4.GET /8-Bit/Label.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 17 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010264005800004006ceadc0a80002550d93d740050050c31389acaf7b26538018400075c900000101080a000537d010fc354a474554202f382d4269742f41636f726e2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d3300942dbf497b07cd1e9f76f1ea9d93f7f28816325a48a56af50e0c236bc2da418375049e3b6960ec48eb1b388d1c69d9d891137c070e1e306820570e7d468e1b3960e0316307468db456d6b04973474c132656d2f2548343b699aa57613c2113470d1e326ad064451347ea1e18aa61cca923270d9b37f94794887c674e0f193254c7501e870f9a3a6fed608c11148e0c2c440c2294e164c78c196caad498f1347409a94be4d8e1ad478f9e187de4987103520e1ca95874d78141047f1cde56e6f241c2713bc6942bd9c87059644415340cc9e89601252c741bdd57ea1851e4a09ea432a2ec4e72d0a90c1b316c8c9872502143c34c8e4ce91e63c608237315d6af1397cd5c19469e1c31023d060da9b4e3c44163466e9cac4ed0585dea360f9af6efefc0401227e81936f4b39e4193e64d5c3469d5f4f92a15709a8d1bb342944831a7ce9e42898a942a3500 ASCII:E...d.X.. at .......U...@..P.....{&S.. at .u.........7...5JGET /8-Bit/Acorn.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtm3..-.I{....v........2ZH.j...#k..A.u..;i`.H..8..i....|...0h W.}F..9`.1c.F..V..IsGL.&V..T.C...Wa#...0......Z+k...#...+kw..A.*.;0.......5h...3u...0........#JP.3.....c0...M..v6.0#...,D.2..d...l.....t..K....G...}..q3..T,... .?.o+u. ..}c..ld.,2....dx..2V.../u.(.P.S.Qz'Q(U...6FLQ..ab&G.|.1c...........#O........q..1C7.V'h.:......Ya .C....[..I.f...j...:8.G.['V....P.HMN... +uncompressed= 45000266007600004006ce8dc0a80002550d93d740060050c31431ada11fa06780184000f08e00000101080a00053b3c10fc35ef474554202f382d4269742f416d73747261642e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..f.v.. at .......U...@..P..1....g.. at ...........;<..5.GET /8-Bit/Amstrad.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 19 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010264007700004006ce8ec0a80002550d93d740040050c3135ddb2189e0108018400060d600000101080a00053b4010fc35e7474554202f382d4269742f41746172692e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d3300932bbf497b07cd1e9f76f1ea9d93d7f28816325a48a56a152b0c236b84da419375049e3b6960ec48dbfb378d1c69d9d891037c070e1e30681c4ffe7c468e1b3960e0316307468db456d6b04973474c132656d2f254832376d5ab77603c2113470d1e326ad068451347ea1e18a961cca923270d9b37f84794807c674e0f193252c7481e870f9aa1da2fc63023078e0c2c440a1e94e164c78c196caad498f1147409a94be4d8d9ad478f9e187de49871e311a4542cb9ebc020723fce6e2b73f920d968e7224a956c64b42c32a20a9a856472cb8022f4b90dee2a758c286250cf511951742731c854868d1836464c31887061612647a6708f31638491b908e9d789cb66ae0c234f8e18791e8386d4d971e2a03123378e562768ae26759b070d7bab58612089f3f10c9bf95acfa049f3262e9ab46afa8095fa378d468d5a1f469c8833e7ce9f41434a951a00 ASCII:E...d.w.. at .......U...@..P..].!..... at .`.........;@..5.GET /8-Bit/Atari.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtm3..+.I{....v........2ZH.j.+.#k..A.u..;i`.H..7..i....|...0h.O.|F..9`.1c.F..V..IsGL.&V..T.#v..w`4..6.GET /8-Bit/Apple.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtm3..-.Q{....v........2ZH.j.+.#k..A.u..;i`.P..7..j....|...0h.O.|F..9`.1c.F..V..IsGL.&V..T.#v..w`4..6.GET /8-Bit/Apple.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 21 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010265007d00004006ce87c0a80002550d93d740050050c3138bdcaf7b296780183cec0de600000101080a00053e3410fc368e474554202f382d4269742f447261676f6e2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d33009631bf597b07cd1e9f8df5f2d59379440b192da656bd9a1586913563eda0d13a02cf9d343076ac052e9c468eb56cecc819be03070f18349433973e23c78d1c30f098b103a3c65a2b6bd8a4b923a609132b6b79aac141db2ad63b309e9089a3068f50345bd1c499ba07c6631873eac849c3e68dfe112526df99d343868cc73198c7e183a64e5c3b1963989103470616220715ca70b263c60c36556acc804abac4d42572ecf8d6a3474f8c3e72ccb80939722a16de75601051c3dfb715a27c9074ec9e71654b363260161951054d4332bc6540192bddc6f7963a461441a847a98c28bd93208ce3d3460c1b23a6205cd89030932353bec79831c208d185f7ebcc6553d7c8932346a4c7a03175769c3868ccd08db3d5091aac4ce1e641f3fe6a561848e2883cc3c6fed63368d2bc998b66ad9a3e61a7fe4dc391e3d688132beeec0974a8519253a70600 ASCII:E...e.}.. at .......U...@..P.....{)g..<...........>4..6.GET /8-Bit/Dragon.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtm3..1.Y{.........yD..-.V.....5c...:...40v....F..l........4.3.>#...0......Z+k...#...+ky..A.*.;0......P4[......c.s..I.....%&...C...1.....N\;.c...G.."...p.c..6Uj..J...%r....GO.>r...9r*..u`.Q.....|.t..qeK62`..Q.MC2.e at .+....:F.A.G..(.. ...F..#. \..0.#S...1.......eS...#F...1uv.8h........L..A..jV.H..<....3h....f..>a..M......+...t.Q.S... +uncompressed= 45000265007d00004006ce87c0a80002550d93d740050050c3138bdcaf7b296780183cec0de600000101080a00053e3410fc368e474554202f382d4269742f447261676f6e2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..e.}.. at .......U...@..P.....{)g..<...........>4..6.GET /8-Bit/Dragon.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 22 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010269008000004006ce80c0a80002550d93d740060050c3143301dfa11fa3de80183c892b5d00000101080a0005412c10fc3761474554202f382d4269742f456e74657270726973652e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f6600952f67defcc66dd03d3df7f6fd3bc72fe7112d64b4b08a552b571846d6983dda75049e3b6960ec701b7c388d1c6e8dca21be03070f183496db694e63468e1b3960e0316307460db756d6b04973474c132656dcee5483c376d6ad77603c2113470d1e326ad0784513c7ea1e18ae6110959386cd1bfe234a58be33a7870c19ae63548fc347285d3b1b63989103470616220ad3c870b263c60c36556acc986aba84d52572ecfcd6a3474f8c3e72ccb81149d22a96a3756010d91fe7b715bc7c90d4f9b891a54b36326216195105cd4332476540312bdd0678973a4614a923478f531951d0dc49d299aa0c1b316c8c98d2b9e143c64c8e4c011f63c60823781be2af63970d5e19469e1c31223d060dabbce3c44163e66e1caf4ed06c853a370f1af85ab9c2401267e41936f7bd9e4193e68d5d346ed5f4216bd5701aa142bd4eac78d1e7cfa1489596b46a3500 ASCII:E...i.... at .......U...@..P..3........<.+]........A,..7aGET /8-Bit/Enterprise.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/f../g...m.==...;./..-d...U+W.F..=.u..;i`.p.|8..n..!.....4..iNcF..9`.1c.F..V..IsGL.&V..T..v..w`r...I.*..u`.......|......K62b..Q..C2Ge at 1+..x.:F..#G.S.Q..I.....1l.....C.L.L..c..#x...c..^.F..1"=......Ac.n..N.l.:7...Z.. at .g..6...A...]4n..!k.p..B.N.x....H...j5. +uncompressed= 45000269008000004006ce80c0a80002550d93d740060050c31433dfa11fa3de80183c892b5d00000101080a0005412c10fc3761474554202f382d4269742f456e74657270726973652e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..i.... at .......U...@..P..3.......<.+]........A,..7aGET /8-Bit/Enterprise.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 23 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010268008100004006ce80c0a80002550d93d740040050c313600b2189e30280183d0e896b00000101080a000541d810fc379d474554202f382d4269742f436f6d6d6f646f72652e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f3300952f67defcc6ed1d347b7ceeedfb778e5fce235ac8686115ab56ae308cac316b074dd71178eea481b1c3edf0e23472b86563478ef11d3878c0a0d1fc79f519396ee48081c78c1d1835dc5a59c326cd1d314d985871cb530d8edb59b7de81f1844c1c3578c8a841e3154d1cab7b60bc8631a78e9c346cdef81f51c2f29d393d64c8781de3791c3e68ead0b5d3318699a032b01061e85086931d3366b0a95263c654d325ac2e916327b81e3d7a62f49163c64dc9a056b1fcae038348ff38c1ade0e5832424f88e2e61b29131b3c8882a682292f92d038ad9ea36c4c3d431a248433d4c6544019ea46154193662d81831a5e1c38889991c99223ec68c1146f03ed45fc72e1bbc328c3c3962a47a0c1a5671c78983c6ccdd385e9da0d9ea746e1e34f2b5728581248ec9336cf27b3d8326cd1bbb68dcaae943d62ae13420417aad78312350a1448d228523c3aad500 ASCII:E...h.... at .......U...@..P..`.!.....=..k........A...7.GET /8-Bit/Commodore.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/3../g.....4{|...w._.#Z.ha..V.0..1k.M..x........4r.ecG...8x....y..9n.......5.ZY.&..1M.Xq.S...Y.....L.5x..A..M..{`..1...4l...Q...9=d.x..y.>h....1...2..a.P...3f..Rc.T.%...c'..=zb..c.M..V.....H.8.....$$...a..1...*h"..-....6...1.HC=LeD...aT.6b..1........">...F.>._....2.<9b.z..Vq......8^....tn.4..r..$..3l.{=.&...h...C.*.4 Az.x1#P.D.".#.... +uncompressed= 45000268008100004006ce80c0a80002550d93d740040050c313600b2189e30280183d0e896b00000101080a000541d810fc379d474554202f382d4269742f436f6d6d6f646f72652e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..h.... at .......U...@..P..`.!.....=..k........A...7.GET /8-Bit/Commodore.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 24 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010263008200004006ce84c0a80002550d93d740050050c3138e0daf7b2cf180183962cb2f00000101080a000542b410fc3822474554202f382d4269742f454143412e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b330096dfa4bd83668f4fbb78f5cec97b79440b192da24ead7a1586913561eda0c13a02cf9d343076a4f50d9c468eb46cecc809be03070f1834902b873e23c78d1c30f098b103a3465a2b6bd8a4b923a609132b6979aac1219baad53b309e9089a3060f193568b2a28913750f0cd530e6d4919386cd9bfc234a44be33a7870c19aa63288fc3074d9db77630c63023078e0c2c440c2294e164c78c196caad498e1347489a84be4d8e1ad478f9e187de49871035264542cbaebc020823f0e6f2b73f920e1b81da34a966c64bc2c32a20a1a866474cb801216ba8dee2c758c287250cf511951762739c854868d1836464c39a89021612647a6748f31638491b90aebd789cb66ae0c234f8e18811e8346d4d971e2a03123374e562768ac26759b074dfbaa5761208913f20c1bfa59cfa049f3262e9ab46afa7c8dfa37cdc68d59214aa4a873e7cfa04347468d1a00 ASCII:E...c.... at .......U...@..P.....{,...9b./........B...8"GET /8-Bit/EACA.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+3......f.O.x...{yD..-.N.z...5a...:...40v....F..l........4.+.>#...0.....FZ+k...#...+iy..!...;0.......5h....u...0........#JD.3.....c(...M..v0.0#...,D."..d...l....4t..K....G...}..q.RdT,... .?.o+s. ....J.ld.,2....dt.......,u.(rP.Q.Qv'9.T...6FL9..!a&G.t.1c........f..#O.....F..q..1#7NV'h.&u..M..Wa ......Y..I.&...j.|..7...Y!J..s...CGF... +uncompressed= 45000263008200004006ce84c0a80002550d93d740050050c3138e0daf7b2cf180183962cb2f00000101080a000542b410fc3822474554202f382d4269742f454143412e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..c.... at .......U...@..P.....{,...9b./........B...8"GET /8-Bit/EACA.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 25 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010262008500004006ce82c0a80002550d93d740070050c314f5defa37d29b80183c168b6100000101080a000542c810fc37e5474554202f382d4269742f4d53582e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b330095dfa0bd83668fcfba77f3cec16b79440b192da04aa56a1586913560eda0b93a02cf9d343076a0edfd9b460eb46cecc801be03070f18348e277f3e23c78d1c30f098b103a3065a2b6bd8a4b923a609132b6879aac1117b6ad53b309e9089a3060f193568b0a28903750f8cd430e6d4919386cd1bfc234a40be33a7870c19a963248fc3074d1db7762ec63023078e0c2c440a1e94e164c78c196caad498d1147409a84be4d8d9ad478f9e187de49871f33124542cb9ebc020723fce6e2b72f920d9a8fd62ca956c64b82c32a20a9a856472cb8002f6b90dee2b758c2862508f511951742731b854868d1836464c318870e1602647a6708f31638411b908e9d781cb46ae0c234f8e18791e830654d971e2a03113370e562768aa226d9b070d7baa5661208903f20c9bf958cfa049f3062e1ab46afa7885ea378d468d581f469c9853674fa0424542851a00 ASCII:E...b.... at .......U...@..P.....7....<..a........B...7.GET /8-Bit/MSX.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+3......f...w...kyD..-.J.j...5`...:...40v....F..l........4.'.>#...0......Z+k...#...+hy...{j.;0.......5h....u...0........#J at .3.....c$...M..v..0#...,D....d...l.....t..K....G...}..q.1$T,... r?.n+r. ...b..ld.,2....dr.......+u.(bP.Q.Qt'1.T...6FL1.p.`&G.p.1c........F..#O..y...T.q..1.7.V'h."m...{.Va ......X..I.....j.x..7.F.X.F..SgO.BEB... +uncompressed= 45000262008500004006ce82c0a80002550d93d740070050c314f5defa37d29b80183c168b6100000101080a000542c810fc37e5474554202f382d4269742f4d53582e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..b.... at .......U...@..P.....7....<..a........B...7.GET /8-Bit/MSX.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 26 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010265009400004006ce70c0a80002550d93d740060050c3143614a11fa986801836e1f43c00000101080a000545b010fc38b7474554202f382d4269742f4d617474656c2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d3300942dbf512b744fcfbb79f7ced17b79440b192da452b58a1586913562eda0c93a02cf9d343076a8edfd9b460eb56cecc801be03070f18348e277f3e23c78d1c30f098b103a3865a2b6bd8a4b923a609132b6a77aac111bbead53b309e9089a3060f193568b4a28923750f8cd430e6d4919386cd1bfc234a44be33a7870c19a963248fc3074d1db87630c63023078e0c2c440a1e94e164c78c196caad498f1347409a94be4d8d9ad478f9e187de498710352a4542cb9ebc020723fce6e2b74f920e1a81da34a966c64bc2c32a20a1a866472cb8022f6b90dee2c758c2862504f521951742731e854868d1836464c31889021612647a6708f31638411ba08e9d791bbd8c89323469ec7a02195769c3868cc7ca5abd5099aab4bdfe641c3de2a561848e2843cc366bed63368d2bc018a46ad9a3e60a5fe4db371a356881229eae4f97368d19152a50600 ASCII:E...e.... at ..p....U...@..P..6.......6..<........E...8.GET /8-Bit/Mattel.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtm3..-.Q+tO..y...{yD..-.R.....5b...:...40v....F..l........4.'.>#...0......Z+k...#...+jw......;0.......5h...#u...0........#JD.3.....c$...M..v0.0#...,D....d...l....4t..K....G...}..q.R.T,... r?.n+t. ....J.ld.,2....dr.."....,u.(bPOR.Qt'1.T...6FL1..!a&G.p.1c...........#F...!.v.8h.|......K..A..*V.H..<.f..3h....F..>`..M.q.V..)...sh..R... +uncompressed= 45000265009400004006ce70c0a80002550d93d740060050c3143614a11fa986801836e1f43c00000101080a000545b010fc38b7474554202f382d4269742f4d617474656c2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..e.... at ..p....U...@..P..6.......6..<........E...8.GET /8-Bit/Mattel.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 27 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010263009900004006ce6dc0a80002550d93d740040050c313623f2189e66b801839a5739a00000101080a0005464c10fc38f3474554202f382d4269742f4f7269632e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b330095dfa4bd83668f4fc578f5eab13ca2858c1651a756bd0ac3c89ab076d0601d81e74e1a183bd2fa064e23475a3676e404df8183070c1ac895439f91e3460e1878ccd8815123ad95356cd2dc11d3848995b43cd5e0904dd5ea1d184fc8c45183878c1a3459d1c489ba0706631873eac849c3e64dfe112520df99d343860cc63194c7e18326e8768c31ccc88123030b1183086538d93163069b2a356638155d22ea12397678ebd1a327461f3966dc7c0c19158bee3a3088e08fc3db8a5c3e4838dac19872251b192e8b8ca882862119dd32a084856ea3fb4a1d238a1cd483544694dd490e36956123868d11530e2a642898c99129dd63cc186144aec2fa75e0b2912bc3c8932346a0c7a01135769c3868ccc48d93d5091aab4adde641d3beea551848e2803cc3867ed63368d2bc818b26ad9a3e5fa3f64db3716356881229e6d4d91328519151a30600 ASCII:E...c.... at ..m....U...@..P..b?!..k..9.s.........FL..8.GET /8-Bit/Oric.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+3......f.O.x...<....Q.V......v.`...N..;...N#GZ6v..........C...F..x...Q#..5l........<...M....O..Q....4Y......c.s..I..M..% ...C...1....&.v.1...#.....e8.1c..*5f8.]"..9vx...'F.9f.|.....:0......\>H8...r%........!..2...n..J.#....TF..I.6.a#...S.*d(...).c..aD...u...+...#F....5v.8h........J..A...U.H..<..~.3h....&..>_..M.qcV..)....(Q.Q... +uncompressed= 45000263009900004006ce6dc0a80002550d93d740040050c313623f2189e66b801839a5739a00000101080a0005464c10fc38f3474554202f382d4269742f4f7269632e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..c.... at ..m....U...@..P..b?!..k..9.s.........FL..8.GET /8-Bit/Oric.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 28 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 4500010269009e00004006ce62c0a80002550d93d740060050c3143845a11fab60801840003c1c00000101080a000547d810fc38b7474554202f382d4269742f526164696f536861636b2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f330096316be6fcc6ed1d347b7a46f60b584fe7112d64b4b08a552b5718468ad6b183a6eb083c77d2c0d8e17678711a39dcb2b123c7f80e1c3c60d068febcfa8c1c3772c0c063c60e8c1a6e89b24973474c132656dcee5483e376d6ad77603c2113470d1e326ad0784513c7ea1e189361cca923270d9b37fd4794b87c674e0f193226c7781e870f9a3a74ed748c61460e1c195888307428c3c98e1933d854a93163eae9125697c8b1135c8f1e3d31fac831e3a6e449ab587ed78141847f9ce056f0f24112127cc79731d9c8a0596444153411c9fc9601c56c751be263ea1851a4a19ea732a2004fd2b0aa0c1b316c8c98d2f061c4c54c8e4c111f63c60823781fe6af6357685e234f8e18a91e838655dd71e2a03173378e572768b6469d9b074d7cad5c61208963f20c1bfc5ecfa049f3c62e1ab76afa90b55a380d48905e2b5ecc1874e8d1a44b515ab51a00 ASCII:E...i.... at ..b....U...@..P..8E...`.. at .<.........G...8.GET /8-Bit/RadioShack.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/3..1k.....4{zF..XO..-d...U+W.F.......#...0......Z+A........<...}5...O..Q....4\......c.s..I#4.......!C......AS....1...#.....e8.1c..*5fD.]...9vz...'F.9f.|.I...:0......]>H6r..r%..........2.e at ......:F.9.G..(...|*.F..#..T(.0.#S...1..]....eCW..'G.D.A...8q.......4Y.....=V.0...y..}.g..y#..Z5}.R..F.F..#N...'P.".R.. +uncompressed= 45000266009f00004006ce64c0a80002550d93d740050050c313903caf7b2f9580183d5ce4ef00000101080a0005481810fc3934474554202f382d4269742f5068696c6970732e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..f.... at ..d....U...@..P...<.{/...=\..........H...94GET /8-Bit/Philips.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... + +Testing decompression with sniffed compressed TCP/IP packets: +Packet No.: 30 +v42bis_decompress_flush() rc=0 +v42bis_decompress() rc=0 +v42bis_decompress_flush() rc=0 +compressed= 450001049b00ae00004006cc20c0a80002550d93d740050050c31396ceaf7b396e801840009ad400000101080a0005611010fc3d6b474554202f382d4269742f6d72776f6e672e67696620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d33009733bf617b07cd9e9f8ef7f6d5a379440b192da85ac5aa1586913564eda0d93a02cf9d343076b00d3e9c460eb66cecc821be03070f183496379f3e23c78d1c30f098b103a3065b2b6b92de11d3848915b63dd5e0a87d35eb1d184fc814c543460d1aae68e250dd0303328c3975e4a461f346ff881294efcce9214306e418cde3f0415347ae1d8c31ccc88123030b1183086538d93163069b2a3566442d5d82ea1239767eebd1a327461f3966dc801449154bef3a3088e48ff3db0a513e48387ac7a892251b192f8b8ca882862199de32a0909d6e033c4b1d238a1cd4a3544614df490e3e956123868d11530e2a644898c99129e063cc186184a8423578ead06563d7c8932346a6c7a04175769c3868ccd48dc3d5099aac4ce3e641f31eab561848e2843cc3a628d73368d2bca18b86ad9a3e62a9fe4db3712357881229eadce933e8d09154a92a417265848c1d307afec489074e198678e6108d31a7e8882557ae4c9111357903abdf7f7b052b96ec4f3868d51e7e1b77ae74198ef7f63d1a76ce52bf50cf4c9d7355b7ddb290634cae7cb9b4dec05f135b76c178c41d347b7e16eeabc732db16325a74cf7a07869135647bff0e3e7c075bdad3732c6f4e7c070e1ed37dcb993e23c78d1c30f07807cfd6ca1a3669ee8869c2c40adb9e6a70a8d60ae30999a278c8e4e78a260ed53d3020c33088900d43ae25204aa46818239f8d6cbc631c3a120b11ff6964a864c9e6e58ca8a54b505d220727579d3b7d06bd48158b52a6f99f72b542940f923a13ed600c39838d8c974546fc6548a63761b2d36d8067a96344913a72f428951105cd9d248a9fcab011c3c688298ad30c444398c99129e063cc18313bce683578eae8b66be4c91123d363246f003b0e1a33d2b93a41939569dc3c68d6df8181248e193967d814e57a064d9a3774d1b055d387cd1caa7fd36cdcc835618f853a63d07473510655aa0100 ASCII:E........ at .. ....U... at ..P.....{9n.. at ...........a...=kGET /8-Bit/mrwong.gif HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtm3..3.a{.........yD..-.Z.....5d...:...40v..>.F..l..!.....4.7.>#...0......[+k........=...}5...O...CF...h.P...2.9u..a.F.......!C......ASG...1...#.....e8.1c..*5fD-]...9v~...'F.9f...I.K.:0......Q>H8z...%../.....!..2...n..a#...S.*dH...).c..a..B5x..ec...#F...Auv.8h........L..A...V.H..<..(.3h.......>b..M.q#W..)...3...T.*Are...0z....N..x...1...%W.L..5y....{.+..O8h..~.w.t....=.v.R.P.L.sU....cL.|...._.[v.x..4{~....2..2Zt.z...5d{..>|.[..s,oN|....}..>#...0.x.....6i..i.....jp.......x....&..=0 .0...C.% J.h.#..l.c.:....id.d......KP]".'W.;}..H..R...r.B...:..`.9....EF.eH.7a..m.g.cD.:r.(.....$........)...DC...).c..1;.h5x...k...#.c$o.;..3..:A..i. Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Wed Aug 31 08:18:34 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 31 Aug 2016 08:18:34 +0000 Subject: [PATCH] libosmocore[master]: libosmocodec link fix on MacOSX In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/802 to look at the new patch set (#2). libosmocodec link fix on MacOSX Fixes the following bug: CCLD libosmocodec.la Undefined symbols for architecture x86_64: "_bitvec_get_bit_pos", referenced from: _osmo_fr_check_sid in gsm610.o "_bitvec_get_uint", referenced from: _osmo_hr_check_sid in gsm620.o ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation) make[2]: *** [libosmocodec.la] Error 1 Change-Id: Id7358b94e274b529a8da38a0b2ef8c892b6dd7a5 --- M src/codec/Makefile.am 1 file changed, 1 insertion(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/02/802/2 diff --git a/src/codec/Makefile.am b/src/codec/Makefile.am index 619897f..5c69c28 100644 --- a/src/codec/Makefile.am +++ b/src/codec/Makefile.am @@ -9,3 +9,4 @@ libosmocodec_la_SOURCES = gsm610.c gsm620.c gsm660.c gsm690.c libosmocodec_la_LDFLAGS = -version-info $(LIBVERSION) -no-undefined +libosmocodec_la_LIBADD = $(top_builddir)/src/libosmocore.la -- To view, visit https://gerrit.osmocom.org/802 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Id7358b94e274b529a8da38a0b2ef8c892b6dd7a5 Gerrit-PatchSet: 2 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Wed Aug 31 09:26:21 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 31 Aug 2016 09:26:21 +0000 Subject: osmo-pcu[master]: EGPRS: EPDAN decoding: add test case to show no ack_nack len... In-Reply-To: References: Message-ID: Patch Set 8: (2 comments) https://gerrit.osmocom.org/#/c/765/8/tests/rlcmac/RLCMACTest.cpp File tests/rlcmac/RLCMACTest.cpp: Line 224: memset(urbb->URBB, -1, sizeof(urbb->URBB)); since you are now setting the memory to non-random values... Line 233: "7f ff ff ee 00 00 00 00 00 00 00 00 00 " ... then also expect the exact bytes that are produced URBB. Or am I still missing something here? -- To view, visit https://gerrit.osmocom.org/765 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I8da84794748f2e81722c3eca69b46ccc3a21552e Gerrit-PatchSet: 8 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: arvind.sirsikar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Wed Aug 31 09:33:22 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 31 Aug 2016 09:33:22 +0000 Subject: openbsc[master]: gprs/gprs_llc: fix null pointer deref in gprs_llc_rcvmsg In-Reply-To: References: Message-ID: Patch Set 1: To me it would make more sense to have 800 and 801 in one commit. In 800 there are (presumably) no callers that could pass NULL yet, and 801 introduces such caller; while 801 makes no sense without 800. But whatever... -- To view, visit https://gerrit.osmocom.org/801 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I1f7e1d524042134c93a4f3de599c54d442447512 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 31 09:35:47 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 31 Aug 2016 09:35:47 +0000 Subject: openbsc[master]: gprs/gsm0408_gprs_force_reattach_oldmsg: check llme before use In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/800 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I9385655872c4dcf46aa1d18bcc47b84aba2f34f7 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 31 09:35:54 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 31 Aug 2016 09:35:54 +0000 Subject: openbsc[master]: gprs/gprs_llc: fix null pointer deref in gprs_llc_rcvmsg In-Reply-To: References: Message-ID: Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/801 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I1f7e1d524042134c93a4f3de599c54d442447512 Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: lynxis lazus Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 31 10:22:31 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 31 Aug 2016 10:22:31 +0000 Subject: libosmocore[master]: libosmocodec link fix on MacOSX In-Reply-To: References: Message-ID: Patch Set 2: > http://jenkins.osmocom.org/jenkins/job/libosmocore-gerrit/158/ : > FAILURE timer test failed on freebsd, retriggering -- To view, visit https://gerrit.osmocom.org/802 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Id7358b94e274b529a8da38a0b2ef8c892b6dd7a5 Gerrit-PatchSet: 2 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 31 10:29:22 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 31 Aug 2016 10:29:22 +0000 Subject: libosmocore[master]: libosmocodec link fix on MacOSX In-Reply-To: References: Message-ID: Patch Set 2: Code-Review+1 works for me on linux, but an OSX user should test as well. -- To view, visit https://gerrit.osmocom.org/802 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Id7358b94e274b529a8da38a0b2ef8c892b6dd7a5 Gerrit-PatchSet: 2 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 31 10:30:02 2016 From: gerrit-no-reply at lists.osmocom.org (Neels Hofmeyr) Date: Wed, 31 Aug 2016 10:30:02 +0000 Subject: libosmocore[master]: libosmocodec link fix on MacOSX In-Reply-To: References: Message-ID: Patch Set 2: > http://jenkins.osmocom.org/jenkins/job/libosmocore-gerrit/159/ : > FAILURE *again* -- To view, visit https://gerrit.osmocom.org/802 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Id7358b94e274b529a8da38a0b2ef8c892b6dd7a5 Gerrit-PatchSet: 2 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 31 11:07:28 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Wed, 31 Aug 2016 11:07:28 +0000 Subject: libosmocore[master]: libosmocodec link fix on MacOSX In-Reply-To: References: Message-ID: Patch Set 2: Code-Review+1 well, the change is quite un-intrusive, and we use that LDADD for all the test cases anyway, so I think it's fine to merge. -- To view, visit https://gerrit.osmocom.org/802 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Id7358b94e274b529a8da38a0b2ef8c892b6dd7a5 Gerrit-PatchSet: 2 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Harald Welte Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 31 11:07:35 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Wed, 31 Aug 2016 11:07:35 +0000 Subject: [MERGED] openbsc[master]: osmo-nitb: generate backtrace on SIGABRT In-Reply-To: References: Message-ID: Harald Welte has submitted this change and it was merged. Change subject: osmo-nitb: generate backtrace on SIGABRT ...................................................................... osmo-nitb: generate backtrace on SIGABRT As the NITB has an internal SIGABRT handler that prints a talloc report, let's also print a stack backtrace at the same point. Change-Id: Ia63aa5c39b26e27c3ee220d755c17d2c1ef636c5 --- M openbsc/src/osmo-nitb/bsc_hack.c 1 file changed, 1 insertion(+), 0 deletions(-) Approvals: Harald Welte: Looks good to me, but someone else must approve Jenkins Builder: Verified Holger Freyther: Looks good to me, approved diff --git a/openbsc/src/osmo-nitb/bsc_hack.c b/openbsc/src/osmo-nitb/bsc_hack.c index e3e8927..976aefa 100644 --- a/openbsc/src/osmo-nitb/bsc_hack.c +++ b/openbsc/src/osmo-nitb/bsc_hack.c @@ -209,6 +209,7 @@ exit(0); break; case SIGABRT: + osmo_generate_backtrace(); /* in case of abort, we want to obtain a talloc report * and then return to the caller, who will abort the process */ case SIGUSR1: -- To view, visit https://gerrit.osmocom.org/767 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ia63aa5c39b26e27c3ee220d755c17d2c1ef636c5 Gerrit-PatchSet: 2 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Harald Welte Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder From gerrit-no-reply at lists.osmocom.org Wed Aug 31 11:08:51 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Wed, 31 Aug 2016 11:08:51 +0000 Subject: [PATCH] openbsc[master]: IuPS: add VTY config for asn_debug In-Reply-To: References: Message-ID: Hello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/790 to look at the new patch set (#3). IuPS: add VTY config for asn_debug Add file iu_vty.c in libiu, and iu_vty_init() to initialize the new VTY command: log logging asn1-debug (1|0) Change-Id: If4e7d0ab3fc2ed0cdf4fb0a3fa077a9e34890918 --- M openbsc/include/openbsc/iu.h M openbsc/src/libiu/Makefile.am A openbsc/src/libiu/iu_vty.c 3 files changed, 53 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/90/790/3 diff --git a/openbsc/include/openbsc/iu.h b/openbsc/include/openbsc/iu.h index d0ab540..f973ac1 100644 --- a/openbsc/include/openbsc/iu.h +++ b/openbsc/include/openbsc/iu.h @@ -58,3 +58,5 @@ int iu_rab_deact(struct ue_conn_ctx *ue_ctx, uint8_t rab_id); int iu_tx_sec_mode_cmd(struct ue_conn_ctx *uectx, struct gsm_auth_tuple *tp, int send_ck, int new_key); + +void iu_vty_init(int *asn_debug_p); diff --git a/openbsc/src/libiu/Makefile.am b/openbsc/src/libiu/Makefile.am index 7b1ba4d..1968d3e 100644 --- a/openbsc/src/libiu/Makefile.am +++ b/openbsc/src/libiu/Makefile.am @@ -6,5 +6,5 @@ noinst_LIBRARIES = libiu.a -libiu_a_SOURCES = iu.c +libiu_a_SOURCES = iu.c iu_vty.c diff --git a/openbsc/src/libiu/iu_vty.c b/openbsc/src/libiu/iu_vty.c new file mode 100644 index 0000000..91eed96 --- /dev/null +++ b/openbsc/src/libiu/iu_vty.c @@ -0,0 +1,50 @@ +/* OpenBSC Iu related interface to quagga VTY */ +/* (C) 2016 by sysmocom s.m.f.c. GmbH + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include + +#include +#include + +/* Pointer to the actual asn_debug value as passed from main scopes. */ +static int *g_asn_debug_p = NULL; + +DEFUN(logging_asn_debug, + logging_asn_debug_cmd, + "logging asn1-debug (1|0)", + LOGGING_STR + "Log human readable representations of all ASN.1 messages to stderr\n" + "Log decoded ASN.1 messages to stderr\n" + "Do not log decoded ASN.1 messages to stderr\n") +{ + if (!g_asn_debug_p) { + vty_out(vty, "%%ASN.1 debugging not available%s", VTY_NEWLINE); + return CMD_WARNING; + } + + *g_asn_debug_p = atoi(argv[0]); + return CMD_SUCCESS; +} + +void iu_vty_init(int *asn_debug_p) +{ + g_asn_debug_p = asn_debug_p; + + install_element(CFG_LOG_NODE, &logging_asn_debug_cmd); +} -- To view, visit https://gerrit.osmocom.org/790 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: If4e7d0ab3fc2ed0cdf4fb0a3fa077a9e34890918 Gerrit-PatchSet: 3 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Wed Aug 31 11:08:52 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Wed, 31 Aug 2016 11:08:52 +0000 Subject: openbsc[master]: IuPS: add VTY config for asn_debug In-Reply-To: References: Message-ID: Patch Set 3: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/790 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: If4e7d0ab3fc2ed0cdf4fb0a3fa077a9e34890918 Gerrit-PatchSet: 3 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 31 11:09:37 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Wed, 31 Aug 2016 11:09:37 +0000 Subject: openbsc[master]: IuPS: osmo-sgsn: add core IuPS impl, call iu_init() In-Reply-To: References: Message-ID: Patch Set 5: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/729 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I469ae6ca9ef254d04ee0d2d79bdd65aebcd027b5 Gerrit-PatchSet: 5 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: daniel Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 31 11:09:51 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Wed, 31 Aug 2016 11:09:51 +0000 Subject: openbsc[master]: IuPS: redirect Iu in various places, link Iu in sgsn-test In-Reply-To: References: Message-ID: Patch Set 4: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/731 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ia47ffbfa6fa0f5a0cd76a379c57ef42faa0d80e3 Gerrit-PatchSet: 4 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: daniel Gerrit-Reviewer: neels_test_account Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 31 11:10:54 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Wed, 31 Aug 2016 11:10:54 +0000 Subject: openbsc[master]: IuPS: dev hack: init hardcoded Ki on ATT REQ In-Reply-To: References: Message-ID: Patch Set 4: this should probably contain a comment in the code and the commitlog about a temporary hack until the GSUP HLR is integrated. -- To view, visit https://gerrit.osmocom.org/734 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ieca45960fa941a3a706c6e479b04b9f2ef89d860 Gerrit-PatchSet: 4 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 31 11:13:48 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Wed, 31 Aug 2016 11:13:48 +0000 Subject: openbsc[master]: Adding SNDCP-XID encoder / decoder and unit test In-Reply-To: References: Message-ID: Patch Set 14: Code-Review+1 -- To view, visit https://gerrit.osmocom.org/641 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e Gerrit-PatchSet: 14 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 31 11:14:03 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Wed, 31 Aug 2016 11:14:03 +0000 Subject: openbsc[master]: Adding SLHC (RFC1144 header compression) code from linux kernel In-Reply-To: References: Message-ID: Patch Set 14: Code-Review+1 -- To view, visit https://gerrit.osmocom.org/634 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ied69c143678dc4a64cecc671f5c4dfebe19d8519 Gerrit-PatchSet: 14 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 31 11:14:08 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Wed, 31 Aug 2016 11:14:08 +0000 Subject: openbsc[master]: SLHC (RFC1144 header compression) integration and unit-test In-Reply-To: References: Message-ID: Patch Set 16: Code-Review+1 -- To view, visit https://gerrit.osmocom.org/635 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0 Gerrit-PatchSet: 16 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 31 11:50:04 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Wed, 31 Aug 2016 11:50:04 +0000 Subject: osmo-pcu[master]: Update the function immediate assignment for EGPRS In-Reply-To: References: Message-ID: Patch Set 6: (1 comment) https://gerrit.osmocom.org/#/c/431/6/src/encoding.cpp File src/encoding.cpp: Line 256: bitvec_write_field(dest, wp, ra, 8); /* RACH value */ > might be a stupid question ... if ra is now 16bit aka 11bit, if it is an 11bit rach, the additional bits are in the extended_ra attribute of the rest octets, see the code above. -- To view, visit https://gerrit.osmocom.org/431 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ie5e309156e5dbbb6add74a1b4d257c4ee2332e52 Gerrit-PatchSet: 6 Gerrit-Project: osmo-pcu Gerrit-Branch: master Gerrit-Owner: bhargava_abhyankar Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Holger Freyther Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-Reviewer: arvind.sirsikar Gerrit-Reviewer: bhargava_abhyankar Gerrit-HasComments: Yes From gerrit-no-reply at lists.osmocom.org Wed Aug 31 11:54:27 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Wed, 31 Aug 2016 11:54:27 +0000 Subject: [PATCH] openbsc[master]: Adding compression control and final fixups In-Reply-To: References: Message-ID: Hello Harald Welte, Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/642 to look at the new patch set (#26). Adding compression control and final fixups - Add module to handle compression entities - Add module to control header compression - Introduce VTY commands for heade compression configuration - Add changes in sndcp and llc to integrate header compression Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 --- M openbsc/include/openbsc/Makefile.am M openbsc/include/openbsc/gprs_llc.h M openbsc/include/openbsc/gprs_sndcp.h A openbsc/include/openbsc/gprs_sndcp_comp.h A openbsc/include/openbsc/gprs_sndcp_pcomp.h M openbsc/include/openbsc/sgsn.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/gprs_llc.c M openbsc/src/gprs/gprs_sndcp.c A openbsc/src/gprs/gprs_sndcp_comp.c A openbsc/src/gprs/gprs_sndcp_pcomp.c M openbsc/src/gprs/sgsn_libgtp.c M openbsc/src/gprs/sgsn_vty.c M openbsc/tests/sgsn/Makefile.am 14 files changed, 1,437 insertions(+), 30 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/42/642/26 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 9a093ab..850eb42 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -19,7 +19,7 @@ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ - iu.h slhc.h + iu.h slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h index c3b82b1..8b01467 100644 --- a/openbsc/include/openbsc/gprs_llc.h +++ b/openbsc/include/openbsc/gprs_llc.h @@ -174,6 +174,15 @@ * able to create the compression entity. */ struct llist_head *xid; + /* Compression entities */ + struct { + /* In these two list_heads we will store the + * data and protocol compression entities, + * together with their compression states */ + struct llist_head *proto; + struct llist_head *data; + } comp; + /* Internal management */ uint32_t age_timestamp; }; diff --git a/openbsc/include/openbsc/gprs_sndcp.h b/openbsc/include/openbsc/gprs_sndcp.h index fef871a..d970240 100644 --- a/openbsc/include/openbsc/gprs_sndcp.h +++ b/openbsc/include/openbsc/gprs_sndcp.h @@ -21,6 +21,16 @@ struct llist_head frag_list; struct osmo_timer_list timer; + + /* Holds state to know which compression mode is used + * when the packet is re-assembled */ + uint8_t pcomp; + uint8_t dcomp; + + /* Holds the pointers to the compression entity list + * that is used when the re-assembled packet is decompressed */ + struct llist_head *proto; + struct llist_head *data; }; /* See 6.7.1.2 Reassembly */ @@ -50,4 +60,20 @@ extern struct llist_head gprs_sndcp_entities; +/* Set of SNDCP-XID negotiation (See also: TS 144 065, + * Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_req(struct gprs_llc_lle *lle, uint8_t nsapi); + +/* Process SNDCP-XID indication (See also: TS 144 065, + * Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_ind(struct gprs_llc_xid_field *xid_field_indication, + struct gprs_llc_xid_field *xid_field_response, + struct gprs_llc_lle *lle); + +/* Process SNDCP-XID indication + * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_conf(struct gprs_llc_xid_field *xid_field_conf, + struct gprs_llc_xid_field *xid_field_request, + struct gprs_llc_lle *lle); + #endif /* INT_SNDCP_H */ diff --git a/openbsc/include/openbsc/gprs_sndcp_comp.h b/openbsc/include/openbsc/gprs_sndcp_comp.h new file mode 100644 index 0000000..87ab638 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_comp.h @@ -0,0 +1,82 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +/* Header / Data compression entity */ +struct gprs_sndcp_comp { + struct llist_head list; + + /* Serves as an ID in case we want to delete this entity later */ + unsigned int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + + /* Specifies to which NSAPIs the compression entity is assigned */ + uint8_t nsapi_len; /* Number of applicable NSAPIs (default 0) */ + uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */ + + /* Assigned pcomp values */ + uint8_t comp_len; /* Number of contained PCOMP / DCOMP values */ + uint8_t comp[MAX_COMP]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */ + + /* Algorithm parameters */ + int algo; /* Algorithm type (see gprs_sndcp_xid.h) */ + int compclass; /* See gprs_sndcp_xid.h/c */ + void *state; /* Algorithm status and parameters */ +}; + +#define MAX_COMP 16 /* Maximum number of possible pcomp/dcomp values */ +#define MAX_NSAPI 11 /* Maximum number usable NSAPIs */ + +/* Allocate a compression enitiy list */ +struct llist_head *gprs_sndcp_comp_alloc(const void *ctx); + +/* Free a compression entitiy list */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities); + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, unsigned int entity); + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_add(const void *ctx, + struct llist_head *comp_entities, + const struct gprs_sndcp_comp_field + *comp_field); + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head + *comp_entities, uint8_t comp); + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head + *comp_entities, uint8_t nsapi); + +/* Find a comp_index for a given pcomp/dcomp value */ +uint8_t gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp *comp_entity, + uint8_t comp); + +/* Find a pcomp/dcomp value for a given comp_index */ +uint8_t gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp *comp_entity, + uint8_t comp_index); diff --git a/openbsc/include/openbsc/gprs_sndcp_pcomp.h b/openbsc/include/openbsc/gprs_sndcp_pcomp.h new file mode 100644 index 0000000..fe3c4ec --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_pcomp.h @@ -0,0 +1,48 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +/* Note: The decompressed packet may have a maximum size of: + * Return value + MAX_DECOMPR_INCR */ +#define MAX_HDRDECOMPR_INCR 64 + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field); + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity); + +/* Expand packet header */ +int gprs_sndcp_pcomp_expand(uint8_t *data_o, uint8_t *data_i, unsigned int len, + uint8_t pcomp, + const struct llist_head *comp_entities); + +/* Compress packet header */ +int gprs_sndcp_pcomp_compress(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t *pcomp, + const struct llist_head *comp_entities, + uint8_t nsapi); diff --git a/openbsc/include/openbsc/sgsn.h b/openbsc/include/openbsc/sgsn.h index 19496cb..2d70f5a 100644 --- a/openbsc/include/openbsc/sgsn.h +++ b/openbsc/include/openbsc/sgsn.h @@ -93,6 +93,13 @@ int dynamic_lookup; struct oap_config oap; + + /* RFC1144 TCP/IP header compression */ + struct { + int active; + int passive; + int s01; + } pcomp_rfc1144; }; struct sgsn_instance { diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 245636b..2910c02 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -27,7 +27,7 @@ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ - slhc.c + slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c index 32920da..98084af 100644 --- a/openbsc/src/gprs/gprs_llc.c +++ b/openbsc/src/gprs/gprs_llc.c @@ -40,6 +40,7 @@ #include #include #include +#include #include static struct gprs_llc_llme *llme_alloc(uint32_t tlli); @@ -140,6 +141,16 @@ struct llist_head *xid_fields; struct gprs_llc_xid_field *xid_field; + struct gprs_llc_xid_field *xid_field_request; + struct gprs_llc_xid_field *xid_field_request_l3 = NULL; + + /* Pick layer3 XID from the XID request we have sent last */ + if (lle->llme->xid) { + llist_for_each_entry(xid_field_request, lle->llme->xid, list) { + if (xid_field_request->type == GPRS_LLC_XID_T_L3_PAR) + xid_field_request_l3 = xid_field_request; + } + } /* Parse and analyze XID-Response */ xid_fields = gprs_llc_parse_xid(NULL, bytes, bytes_len); @@ -150,12 +161,10 @@ llist_for_each_entry(xid_field, xid_fields, list) { /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ - if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { - LOGP(DLLC, LOGL_NOTICE, - "Ignoring SNDCP-XID-Field: XID: type=%i, data_len=%i, data=%s\n", - xid_field->type, xid_field->data_len, - osmo_hexdump_nospc(xid_field->data, - xid_field->data_len)); + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR && + xid_field_request_l3) { + sndcp_sn_xid_conf(xid_field, + xid_field_request_l3, lle); } /* Process LLC-XID fields: */ @@ -204,10 +213,6 @@ struct gprs_llc_xid_field *xid_field; struct gprs_llc_xid_field *xid_field_response; - /* Flush eventually pending XID fields */ - talloc_free(lle->llme->xid); - lle->llme->xid = NULL; - /* Parse and analyze XID-Request */ xid_fields = gprs_llc_parse_xid(lle->llme, bytes_request, bytes_request_len); @@ -236,6 +241,23 @@ (lle->llme, xid_field); llist_add(&xid_field_response->list, xid_fields_response); + } + } + + /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */ + llist_for_each_entry(xid_field, xid_fields, list) { + if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) { + + xid_field_response = + talloc_zero(lle->llme, + struct gprs_llc_xid_field); + rc = sndcp_sn_xid_ind(xid_field, + xid_field_response, lle); + if (rc == 0) + llist_add(&xid_field_response->list, + xid_fields_response); + else + talloc_free(xid_field_response); } } @@ -525,11 +547,16 @@ llist_add(&llme->list, &gprs_llc_llmes); + llme->comp.proto = gprs_sndcp_comp_alloc(llme); + llme->comp.data = gprs_sndcp_comp_alloc(llme); + return llme; } static void llme_free(struct gprs_llc_llme *llme) { + gprs_sndcp_comp_free(llme->comp.proto); + gprs_sndcp_comp_free(llme->comp.data); talloc_free(llme->xid); llist_del(&llme->list); talloc_free(llme); diff --git a/openbsc/src/gprs/gprs_sndcp.c b/openbsc/src/gprs/gprs_sndcp.c index 4f71121..1ab55af 100644 --- a/openbsc/src/gprs/gprs_sndcp.c +++ b/openbsc/src/gprs/gprs_sndcp.c @@ -35,6 +35,131 @@ #include #include #include +#include +#include +#include +#include + +#define DEBUG_IP_PACKETS 1 /* 0=Disabled, 1=Enabled */ + +#if DEBUG_IP_PACKETS == 1 +/* Calculate TCP/IP checksum */ +static uint16_t calc_ip_csum(uint8_t *data, int len) +{ + int i; + uint32_t accumulator = 0; + uint16_t *pointer = (uint16_t *) data; + + for (i = len; i > 1; i -= 2) { + accumulator += *pointer; + pointer++; + } + + if (len % 2) + accumulator += *pointer; + + accumulator = (accumulator & 0xffff) + ((accumulator >> 16) & 0xffff); + accumulator += (accumulator >> 16) & 0xffff; + return (~accumulator); +} + +/* Calculate TCP/IP checksum */ +static uint16_t calc_tcpip_csum(const void *ctx, uint8_t *packet, int len) +{ + uint8_t *buf; + uint16_t csum; + + buf = talloc_zero_size(ctx, len); + memset(buf, 0, len); + memcpy(buf, packet + 12, 8); + buf[9] = packet[9]; + buf[11] = (len - 20) & 0xFF; + buf[10] = (len - 20) >> 8 & 0xFF; + memcpy(buf + 12, packet + 20, len - 20); + csum = calc_ip_csum(buf, len - 20 + 12); + talloc_free(buf); + return csum; +} + +/* Show some ip packet details */ +static void debug_ip_packet(uint8_t *data, int len, int dir, char *info) +{ + uint8_t tcp_flags; + char flags_debugmsg[256]; + int len_short; + static unsigned int packet_count = 0; + static unsigned int tcp_csum_err_count = 0; + static unsigned int ip_csum_err_count = 0; + + packet_count++; + + if (len > 80) + len_short = 80; + else + len_short = len; + + if (dir) + DEBUGP(DSNDCP, "%s: PHONE => NETWORK: %s\n", info, + osmo_hexdump_nospc(data, len_short)); + else + DEBUGP(DSNDCP, "%s: PHONE <= NETWORK: %s\n", info, + osmo_hexdump_nospc(data, len_short)); + + DEBUGP(DSNDCP, "%s: Length.: %d\n", info, len); + DEBUGP(DSNDCP, "%s: NO.: %d\n", info, packet_count); + + if (len < 20) { + DEBUGP(DSNDCP, "%s: Error: Short IP packet!\n", info); + return; + } + + if (calc_ip_csum(data, 20) != 0) { + DEBUGP(DSNDCP, "%s: Bad IP-Header checksum!\n", info); + ip_csum_err_count++; + } else + DEBUGP(DSNDCP, "%s: IP-Header checksum ok.\n", info); + + if (data[9] == 0x06) { + if (len < 40) { + DEBUGP(DSNDCP, "%s: Error: Short TCP packet!\n", info); + return; + } + + DEBUGP(DSNDCP, "%s: Protocol type: TCP\n", info); + tcp_flags = data[33]; + + if (calc_tcpip_csum(NULL, data, len) != 0) { + DEBUGP(DSNDCP, "%s: Bad TCP checksum!\n", info); + tcp_csum_err_count++; + } else + DEBUGP(DSNDCP, "%s: TCP checksum ok.\n", info); + + memset(flags_debugmsg, 0, sizeof(flags_debugmsg)); + if (tcp_flags & 1) + strcat(flags_debugmsg, "FIN "); + if (tcp_flags & 2) + strcat(flags_debugmsg, "SYN "); + if (tcp_flags & 4) + strcat(flags_debugmsg, "RST "); + if (tcp_flags & 8) + strcat(flags_debugmsg, "PSH "); + if (tcp_flags & 16) + strcat(flags_debugmsg, "ACK "); + if (tcp_flags & 32) + strcat(flags_debugmsg, "URG "); + DEBUGP(DSNDCP, "%s: FLAGS: %s\n", info, flags_debugmsg); + } else if (data[9] == 0x11) { + DEBUGP(DSNDCP, "%s: Protocol type: UDP\n", info); + } else { + DEBUGP(DSNDCP, "%s: Protocol type: (%02x)\n", info, data[9]); + } + + DEBUGP(DSNDCP, "%s: IP-Header checksum errors: %d\n", info, + ip_csum_err_count); + DEBUGP(DSNDCP, "%s: TCP-Checksum errors: %d\n", info, + tcp_csum_err_count); +} +#endif /* Chapter 7.2: SN-PDU Formats */ struct sndcp_common_hdr { @@ -143,6 +268,9 @@ struct msgb *msg; unsigned int seg_nr; uint8_t *npdu; + int npdu_len; + int rc; + uint8_t *expnd; LOGP(DSNDCP, LOGL_DEBUG, "TLLI=0x%08x NSAPI=%u: Defragment output PDU %u " "num_seg=%u tot_len=%u\n", sne->lle->llme->tlli, sne->nsapi, @@ -173,16 +301,46 @@ talloc_free(dqe); } + npdu_len = sne->defrag.tot_len; + /* FIXME: cancel timer */ /* actually send the N-PDU to the SGSN core code, which then * hands it off to the correct GTP tunnel + GGSN via gtp_data_req() */ - return sgsn_rx_sndcp_ud_ind(&sne->ra_id, sne->lle->llme->tlli, - sne->nsapi, msg, sne->defrag.tot_len, npdu); + + /* Decompress packet */ +#if DEBUG_IP_PACKETS == 1 + DEBUGP(DSNDCP, " \n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, "===================================================\n"); +#endif + expnd = talloc_zero_size(msg, msg->len + MAX_HDRDECOMPR_INCR); + rc = gprs_sndcp_pcomp_expand(expnd, npdu, npdu_len, + sne->defrag.pcomp, sne->defrag.proto); + if (rc < 0) { + LOGP(DSNDCP, LOGL_ERROR, + "TCP/IP Header decompression failed!\n"); + talloc_free(expnd); + return -EIO; + } else + npdu_len = rc; +#if DEBUG_IP_PACKETS == 1 + debug_ip_packet(expnd, npdu_len, 1, "defrag_segments()"); + DEBUGP(DSNDCP, "===================================================\n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, " \n"); +#endif + + /* Hand off packet to gtp */ + rc = sgsn_rx_sndcp_ud_ind(&sne->ra_id, sne->lle->llme->tlli, + sne->nsapi, msg, npdu_len, expnd); + + talloc_free(expnd); + return rc; } -static int defrag_input(struct gprs_sndcp_entity *sne, struct msgb *msg, uint8_t *hdr, - unsigned int len) +static int defrag_input(struct gprs_sndcp_entity *sne, struct msgb *msg, + uint8_t *hdr, unsigned int len) { struct sndcp_common_hdr *sch; struct sndcp_udata_hdr *suh; @@ -343,7 +501,8 @@ }; /* returns '1' if there are more fragments to send, '0' if none */ -static int sndcp_send_ud_frag(struct sndcp_frag_state *fs) +static int sndcp_send_ud_frag(struct sndcp_frag_state *fs, + uint8_t pcomp, uint8_t dcomp) { struct gprs_sndcp_entity *sne = fs->sne; struct gprs_llc_lle *lle = sne->lle; @@ -380,8 +539,8 @@ if (sch->first) { scomph = (struct sndcp_comp_hdr *) msgb_put(fmsg, sizeof(*scomph)); - scomph->pcomp = 0; - scomph->dcomp = 0; + scomph->pcomp = pcomp; + scomph->dcomp = dcomp; } /* append the user-data header */ @@ -446,8 +605,37 @@ struct sndcp_comp_hdr *scomph; struct sndcp_udata_hdr *suh; struct sndcp_frag_state fs; + uint8_t pcomp = 0; + uint8_t dcomp = 0; + int rc; + uint8_t *compr; /* Identifiers from UP: (TLLI, SAPI) + (BVCI, NSEI) */ + + /* Compress packet */ +#if DEBUG_IP_PACKETS == 1 + DEBUGP(DSNDCP, " \n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, "===================================================\n"); + debug_ip_packet(msg->data, msg->len, 0, "sndcp_initdata_req()"); +#endif + compr = talloc_zero_size(msg, msg->len); + rc = gprs_sndcp_pcomp_compress(compr, msg->data, msg->len, &pcomp, + lle->llme->comp.proto, nsapi); + if (rc < 0) { + LOGP(DSNDCP, LOGL_ERROR, "TCP/IP Header compression failed!\n"); + talloc_free(compr); + return -EIO; + } else { + msg->len = rc; + memcpy(msg->data, compr, rc); + } + talloc_free(compr); +#if DEBUG_IP_PACKETS == 1 + DEBUGP(DSNDCP, "===================================================\n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, " \n"); +#endif sne = gprs_sndcp_entity_by_lle(lle, nsapi); if (!sne) { @@ -469,7 +657,7 @@ /* call function to generate and send fragments until all * of the N-PDU has been sent */ while (1) { - int rc = sndcp_send_ud_frag(&fs); + int rc = sndcp_send_ud_frag(&fs,pcomp,dcomp); if (rc == 0) return 0; if (rc < 0) @@ -489,8 +677,8 @@ sne->tx_npdu_nr = (sne->tx_npdu_nr + 1) % 0xfff; scomph = (struct sndcp_comp_hdr *) msgb_push(msg, sizeof(*scomph)); - scomph->pcomp = 0; - scomph->dcomp = 0; + scomph->pcomp = pcomp; + scomph->dcomp = dcomp; /* prepend common SNDCP header */ sch = (struct sndcp_common_hdr *) msgb_push(msg, sizeof(*sch)); @@ -512,6 +700,8 @@ uint8_t *npdu; uint16_t npdu_num __attribute__((unused)); int npdu_len; + int rc; + uint8_t *expnd; sch = (struct sndcp_common_hdr *) hdr; if (sch->first) { @@ -540,26 +730,58 @@ /* FIXME: move this RA_ID up to the LLME or even higher */ bssgp_parse_cell_id(&sne->ra_id, msgb_bcid(msg)); + if(scomph) { + sne->defrag.pcomp = scomph->pcomp; + sne->defrag.dcomp = scomph->dcomp; + sne->defrag.proto = lle->llme->comp.proto; + sne->defrag.data = lle->llme->comp.data; + } + /* any non-first segment is by definition something to defragment * as is any segment that tells us there are more segments */ if (!sch->first || sch->more) return defrag_input(sne, msg, hdr, len); - if (scomph && (scomph->pcomp || scomph->dcomp)) { - LOGP(DSNDCP, LOGL_ERROR, "We don't support compression yet\n"); - return -EIO; - } - npdu_num = (suh->npdu_high << 8) | suh->npdu_low; npdu = (uint8_t *)suh + sizeof(*suh); - npdu_len = (msg->data + msg->len) - npdu; + npdu_len = (msg->data + msg->len) - npdu - 3; /* -3 'removes' the FCS */ + if (npdu_len <= 0) { LOGP(DSNDCP, LOGL_ERROR, "Short SNDCP N-PDU: %d\n", npdu_len); return -EIO; } /* actually send the N-PDU to the SGSN core code, which then * hands it off to the correct GTP tunnel + GGSN via gtp_data_req() */ - return sgsn_rx_sndcp_ud_ind(&sne->ra_id, lle->llme->tlli, sne->nsapi, msg, npdu_len, npdu); + + /* Decompress packet */ +#if DEBUG_IP_PACKETS == 1 + DEBUGP(DSNDCP, " \n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, "===================================================\n"); +#endif + expnd = talloc_zero_size(msg, npdu_len + MAX_HDRDECOMPR_INCR); + rc = gprs_sndcp_pcomp_expand(expnd, npdu, npdu_len, + sne->defrag.pcomp, sne->defrag.proto); + if (rc < 0) { + LOGP(DSNDCP, LOGL_ERROR, + "TCP/IP Header decompression failed!\n"); + talloc_free(expnd); + return -EIO; + } else + npdu_len = rc; +#if DEBUG_IP_PACKETS == 1 + debug_ip_packet(expnd, npdu_len, 1, "sndcp_llunitdata_ind()"); + DEBUGP(DSNDCP, "===================================================\n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, " \n"); +#endif + + /* Hand off packet to gtp */ + rc = sgsn_rx_sndcp_ud_ind(&sne->ra_id, lle->llme->tlli, + sne->nsapi, msg, npdu_len, expnd); + + talloc_free(expnd); + return rc; } #if 0 @@ -619,3 +841,319 @@ case LL_STATUS_IND: } #endif + +/* Generate SNDCP-XID message */ +static int gprs_llc_gen_sndcp_xid(uint8_t *bytes, int bytes_len, uint8_t nsapi) +{ + int entity = 0; + LLIST_HEAD(comp_fields); + struct gprs_sndcp_pcomp_rfc1144_params rfc1144_params; + struct gprs_sndcp_comp_field rfc1144_comp_field; + + memset(&rfc1144_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + + /* Setup rfc1144 */ + if (sgsn->cfg.pcomp_rfc1144.active) { + rfc1144_params.nsapi[0] = nsapi; + rfc1144_params.nsapi_len = 1; + rfc1144_params.s01 = sgsn->cfg.pcomp_rfc1144.s01; + rfc1144_comp_field.p = 1; + rfc1144_comp_field.entity = entity; + rfc1144_comp_field.algo = RFC_1144; + rfc1144_comp_field.comp[RFC1144_PCOMP1] = 1; + rfc1144_comp_field.comp[RFC1144_PCOMP2] = 2; + rfc1144_comp_field.comp_len = RFC1144_PCOMP_NUM; + rfc1144_comp_field.rfc1144_params = &rfc1144_params; + entity++; + llist_add(&rfc1144_comp_field.list, &comp_fields); + } + + /* Compile bytestream */ + return gprs_sndcp_compile_xid(bytes, bytes_len, &comp_fields); +} + +/* Set of SNDCP-XID bnegotiation (See also: TS 144 065, + * Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_req(struct gprs_llc_lle *lle, uint8_t nsapi) +{ + /* Note: The specification requires the SNDCP-User to set of an + * SNDCP xid request. See also 3GPP TS 44.065, 6.8 XID parameter + * negotiation, Figure 11: SNDCP XID negotiation procedure. In + * our case the SNDCP-User is sgsn_libgtp.c, which calls + * sndcp_sn_xid_req directly. */ + + uint8_t l3params[1024]; + int xid_len; + struct gprs_llc_xid_field xid_field_request; + + /* Generate compression parameter bytestream */ + xid_len = gprs_llc_gen_sndcp_xid(l3params, sizeof(l3params), nsapi); + + /* Send XID with the SNDCP-XID bytetsream included */ + if (xid_len > 0) { + xid_field_request.type = GPRS_LLC_XID_T_L3_PAR; + xid_field_request.data = l3params; + xid_field_request.data_len = xid_len; + return gprs_ll_xid_req(lle, &xid_field_request); + } + + /* When bytestream can not be generated, proceed without SNDCP-XID */ + else { + return gprs_ll_xid_req(lle, NULL); + } +} + +/* Handle header compression entites */ +static int handle_pcomp_entities(struct gprs_sndcp_comp_field *comp_field, + struct gprs_llc_lle *lle) +{ + /* Note: This functions also transforms the comp_field into its + * echo form (strips comp values, resets propose bit etc...) + * the processed comp_fields can then be sent back as XID- + * Response without further modification. */ + + /* Delete propose bit */ + comp_field->p = 0; + + /* Process proposed parameters */ + switch (comp_field->algo) { + case RFC_1144: + if (sgsn->cfg.pcomp_rfc1144.passive && + comp_field->rfc1144_params->nsapi_len > 0) { + LOGP(DSNDCP, LOGL_DEBUG, + "Accepting RFC1144 header compression...\n"); + gprs_sndcp_comp_add(lle->llme, lle->llme->comp.proto, + comp_field); + } else { + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting RFC1144 header compression...\n"); + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + comp_field->rfc1144_params->nsapi_len = 0; + } + break; + case RFC_2507: + /* RFC 2507 is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting RFC2507 header compression...\n"); + comp_field->rfc2507_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + break; + case ROHC: + /* ROHC is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting ROHC header compression...\n"); + comp_field->rohc_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + break; + } + + return 0; +} + +/* Hanle data compression entites */ +static int handle_dcomp_entities(struct gprs_sndcp_comp_field *comp_field, + struct gprs_llc_lle *lle) +{ + /* See note in handle_pcomp_entities() */ + + /* Delete propose bit */ + comp_field->p = 0; + + /* Process proposed parameters */ + switch (comp_field->algo) { + case V42BIS: + /* V42BIS is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting V.42bis data compression...\n"); + comp_field->v42bis_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + break; + case V44: + /* V44 is not yet supported, + * so we set applicable nsapis to zero */ + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting V.44 data compression...\n"); + comp_field->v44_params->nsapi_len = 0; + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + break; + } + + return 0; + +} + +/* Process SNDCP-XID indication + * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_ind(struct gprs_llc_xid_field *xid_field_indication, + struct gprs_llc_xid_field *xid_field_response, + struct gprs_llc_lle *lle) +{ + /* Note: This function computes the SNDCP-XID response that is sent + * back to the phone when a phone originated XID is received. The + * Input XID fields are directly processed and the result is directly + * handed back. */ + + int rc; + int compclass; + + struct llist_head *comp_fields; + struct gprs_sndcp_comp_field *comp_field; + + OSMO_ASSERT(xid_field_indication); + OSMO_ASSERT(xid_field_response); + OSMO_ASSERT(lle); + + /* Parse SNDCP-CID XID-Field */ + comp_fields = gprs_sndcp_parse_xid(lle->llme, + xid_field_indication->data, + xid_field_indication->data_len, + NULL); + if (!comp_fields) + return -EINVAL; + + /* Don't bother with empty indications */ + if (llist_empty(comp_fields)) { + xid_field_response->data = NULL; + xid_field_response->data_len = 0; + DEBUGP(DSNDCP, + "SNDCP-XID indication did not contain any parameters!\n"); + return 0; + } + + /* Handle compression entites */ + DEBUGP(DSNDCP, "SNDCP-XID-IND (phone):\n"); + gprs_sndcp_dump_comp_fields(comp_fields, LOGL_DEBUG); + + llist_for_each_entry(comp_field, comp_fields, list) { + compclass = gprs_sndcp_get_compression_class(comp_field); + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + rc = handle_pcomp_entities(comp_field, lle); + else if (compclass == SNDCP_XID_DATA_COMPRESSION) + rc = handle_dcomp_entities(comp_field, lle); + else { + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + rc = 0; + } + + if (rc < 0) { + talloc_free(comp_fields); + return -EINVAL; + } + } + + DEBUGP(DSNDCP, + "SNDCP-XID-RES (sgsn):\n"); + gprs_sndcp_dump_comp_fields(comp_fields, LOGL_DEBUG); + + /* Reserve some memory to store the modified SNDCP-XID bytes */ + xid_field_response->data = + talloc_zero_size(lle->llme, xid_field_indication->data_len); + + /* Set Type flag for response */ + xid_field_response->type = GPRS_LLC_XID_T_L3_PAR; + + /* Compile modified SNDCP-XID bytes */ + rc = gprs_sndcp_compile_xid(xid_field_response->data, + xid_field_indication->data_len, + comp_fields); + + if (rc > 0) + xid_field_response->data_len = rc; + else { + talloc_free(xid_field_response->data); + xid_field_response->data = NULL; + xid_field_response->data_len = 0; + return -EINVAL; + } + + talloc_free(comp_fields); + + return 0; +} + +/* Process SNDCP-XID indication + * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_conf(struct gprs_llc_xid_field *xid_field_conf, + struct gprs_llc_xid_field *xid_field_request, + struct gprs_llc_lle *lle) +{ + /* Note: This function handles an incomming SNDCP-XID confirmiation. + * Since the confirmation fields may lack important parameters we + * will reconstruct these missing fields using the original request + * we have sent. After that we will create (or delete) the + * compression entites */ + + struct llist_head *comp_fields_req; + struct llist_head *comp_fields_conf; + struct gprs_sndcp_comp_field *comp_field; + int rc; + int compclass; + + /* We need both, the confirmation that is sent back by the phone, + * and the original request we have sent. If one of this is missing + * we can not process the confirmation, the caller must check if + * request and confirmation fields are available. */ + OSMO_ASSERT(xid_field_conf); + OSMO_ASSERT(xid_field_request); + + /* Parse SNDCP-CID XID-Field */ + comp_fields_req = gprs_sndcp_parse_xid(lle->llme, + xid_field_request->data, + xid_field_request->data_len, + NULL); + if (!comp_fields_req) + return -EINVAL; + + DEBUGP(DSNDCP, "SNDCP-XID-REQ (sgsn):\n"); + gprs_sndcp_dump_comp_fields(comp_fields_req, LOGL_DEBUG); + + /* Parse SNDCP-CID XID-Field */ + comp_fields_conf = gprs_sndcp_parse_xid(lle->llme, + xid_field_conf->data, + xid_field_conf->data_len, + comp_fields_req); + if (!comp_fields_conf) + return -EINVAL; + + DEBUGP(DSNDCP, + "SNDCP-XID-CONF (phone):\n"); + gprs_sndcp_dump_comp_fields(comp_fields_conf, LOGL_DEBUG); + + /* Handle compression entites */ + llist_for_each_entry(comp_field, comp_fields_conf, list) { + compclass = gprs_sndcp_get_compression_class(comp_field); + if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) + rc = handle_pcomp_entities(comp_field, lle); + else if (compclass == SNDCP_XID_DATA_COMPRESSION) + rc = handle_dcomp_entities(comp_field, lle); + else { + gprs_sndcp_comp_delete(lle->llme->comp.proto, + comp_field->entity); + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + rc = 0; + } + + if (rc < 0) { + talloc_free(comp_fields_req); + talloc_free(comp_fields_conf); + return -EINVAL; + } + } + + talloc_free(comp_fields_req); + talloc_free(comp_fields_conf); + + return 0; +} diff --git a/openbsc/src/gprs/gprs_sndcp_comp.c b/openbsc/src/gprs/gprs_sndcp_comp.c new file mode 100644 index 0000000..ede584e --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_comp.c @@ -0,0 +1,320 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +/* Create a new compression entity from a XID-Field */ +static struct gprs_sndcp_comp *gprs_sndcp_comp_create(const void *ctx, + const struct + gprs_sndcp_comp_field + *comp_field) +{ + struct gprs_sndcp_comp *comp_entity; + comp_entity = talloc_zero(ctx, struct gprs_sndcp_comp); + + /* Copy relevant information from the SNDCP-XID field */ + comp_entity->entity = comp_field->entity; + comp_entity->comp_len = comp_field->comp_len; + memcpy(comp_entity->comp, comp_field->comp, sizeof(comp_entity->comp)); + + if (comp_field->rfc1144_params) { + comp_entity->nsapi_len = comp_field->rfc1144_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc1144_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->rfc2507_params) { + comp_entity->nsapi_len = comp_field->rfc2507_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->rfc2507_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->rohc_params) { + comp_entity->nsapi_len = comp_field->rohc_params->nsapi_len; + memcpy(comp_entity->nsapi, comp_field->rohc_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->v42bis_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + sizeof(comp_entity->nsapi)); + } else if (comp_field->v44_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy(comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + sizeof(comp_entity->nsapi)); + } else { + /* The caller is expected to check carefully if the all + * data fields required for compression entity creation + * are present. Otherwise we blow an assertion here */ + OSMO_ASSERT(false); + } + comp_entity->algo = comp_field->algo; + + /* Check if an NSAPI is selected, if not, it does not make sense + * to create the compression entity, since the caller should + * have checked the presence of the NSAPI, we blow an assertion + * in case of missing NSAPIs */ + OSMO_ASSERT(comp_entity->nsapi_len > 0); + + /* Determine of which class our compression entity will be + * (Protocol or Data compresson ?) */ + comp_entity->compclass = gprs_sndcp_get_compression_class(comp_field); + + OSMO_ASSERT(comp_entity->compclass != -1); + + /* Create an algorithm specific compression context */ + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + if (gprs_sndcp_pcomp_init(ctx, comp_entity, comp_field) != 0) { + talloc_free(comp_entity); + comp_entity = NULL; + } + } else { + LOGP(DSNDCP, LOGL_ERROR, + "We don't support data compression yet!\n"); + talloc_free(comp_entity); + return NULL; + } + + /* Display info message */ + if (comp_entity == NULL) { + LOGP(DSNDCP, LOGL_ERROR, + "Header compression entity (%d) creation failed!\n", + comp_entity->entity); + return NULL; + } + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "New header compression entity (%d) created.\n", + comp_entity->entity); + } else { + LOGP(DSNDCP, LOGL_INFO, + "New data compression entity (%d) created.\n", + comp_entity->entity); + } + + return comp_entity; +} + +/* Allocate a compression enitiy list */ +struct llist_head *gprs_sndcp_comp_alloc(const void *ctx) +{ + struct llist_head *lh; + + lh = talloc_zero(ctx, struct llist_head); + INIT_LLIST_HEAD(lh); + + return lh; +} + +/* Free a compression entitiy list */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities) +{ + struct gprs_sndcp_comp *comp_entity; + + /* We expect the caller to take care of allocating a + * compression entity list properly. Attempting to + * free a non existing list clearly points out + * a malfunction. */ + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + /* Free compression entity */ + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %d ...\n", + comp_entity->entity); + gprs_sndcp_pcomp_term(comp_entity); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %d ...\n", + comp_entity->entity); + } + } + + talloc_free(comp_entities); +} + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, + unsigned int entity) +{ + struct gprs_sndcp_comp *comp_entity; + struct gprs_sndcp_comp *comp_entity_to_delete = NULL; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) { + comp_entity_to_delete = comp_entity; + break; + } + } + + if (!comp_entity_to_delete) + return; + + if (comp_entity_to_delete->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP(DSNDCP, LOGL_INFO, + "Deleting header compression entity %d ...\n", + comp_entity_to_delete->entity); + gprs_sndcp_pcomp_term(comp_entity_to_delete); + } else { + LOGP(DSNDCP, LOGL_INFO, + "Deleting data compression entity %d ...\n", + comp_entity_to_delete->entity); + } + + /* Delete compression entity */ + llist_del(&comp_entity_to_delete->list); + talloc_free(comp_entity_to_delete); +} + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_add(const void *ctx, + struct llist_head *comp_entities, + const struct gprs_sndcp_comp_field + *comp_field) +{ + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(comp_entities); + OSMO_ASSERT(comp_field); + + /* Just to be sure, if the entity is already in + * the list it will be deleted now */ + gprs_sndcp_comp_delete(comp_entities, comp_field->entity); + + /* Create and add a new entity to the list */ + comp_entity = gprs_sndcp_comp_create(ctx, comp_field); + + if (!comp_entity) + return NULL; + + llist_add(&comp_entity->list, comp_entities); + return comp_entity; +} + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head + *comp_entities, uint8_t comp) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return comp_entity; + } + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given pcomp/dcomp value %d.\n", + comp); + return NULL; +} + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head + *comp_entities, uint8_t nsapi) +{ + struct gprs_sndcp_comp *comp_entity; + int i; + + OSMO_ASSERT(comp_entities); + + llist_for_each_entry(comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->nsapi_len; i++) { + if (comp_entity->nsapi[i] == nsapi) + return comp_entity; + } + } + + return NULL; +} + +/* Find a comp_index for a given pcomp/dcomp value */ +uint8_t gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp *comp_entity, + uint8_t comp) +{ + /* Note: This function returns a normalized version of the comp value, + * which matches up with the position of the comp field. Since comp=0 + * is reserved for "no compression", the index value starts counting + * at one. The return value is the PCOMPn/DCOMPn value one can find + * in the Specification (see e.g. 3GPP TS 44.065, 6.5.3.2, Table 7) */ + + int i; + OSMO_ASSERT(comp_entity); + + /* A pcomp/dcomp value of zero is reserved for "no comproession", + * So we just bail and return zero in this case */ + if (comp == 0) + return 0; + + /* Look in the pcomp/dcomp list for the index */ + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return i + 1; + } + + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching comp_index for given pcomp/dcomp value %d\n", + comp); + return 0; +} + +/* Find a pcomp/dcomp value for a given comp_index */ +uint8_t gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp *comp_entity, + uint8_t comp_index) +{ + OSMO_ASSERT(comp_entity); + + /* A comp_index of zero translates to zero right away. */ + if (comp_index == 0) + return 0; + + if (comp_index > comp_entity->comp_len) { + LOGP(DSNDCP, LOGL_ERROR, + "Could not find a matching pcomp/dcomp value for given comp_index value %d.\n", + comp_index); + return 0; + } + + /* Look in the pcomp/dcomp list for the comp_index, see + * note in gprs_sndcp_comp_get_idx() */ + return comp_entity->comp[comp_index - 1]; +} diff --git a/openbsc/src/gprs/gprs_sndcp_pcomp.c b/openbsc/src/gprs/gprs_sndcp_pcomp.c new file mode 100644 index 0000000..c5118cd --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_pcomp.c @@ -0,0 +1,288 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a new header compression + * entity is created by gprs_sndcp.c */ + + OSMO_ASSERT(comp_entity); + OSMO_ASSERT(comp_field); + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + comp_entity->state = + slhc_init(ctx, comp_field->rfc1144_params->s01 + 1, + comp_field->rfc1144_params->s01 + 1); + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression initalized.\n"); + return 0; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a header compression + * entity is deleted by gprs_sndcp.c */ + + OSMO_ASSERT(comp_entity); + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo == RFC_1144) { + if (comp_entity->state) { + slhc_free((struct slcompress *)comp_entity->state); + comp_entity->state = NULL; + } + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression terminated.\n"); + return; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Compress a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_compress(uint8_t *pcomp_index, + uint8_t *data_o, uint8_t *data_i, + unsigned int len, + struct slcompress *comp) +{ + uint8_t *comp_ptr; + int compr_len; + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Run compressor */ + compr_len = slhc_compress(comp, data_i, len, data_o, &comp_ptr, 0); + + /* Generate pcomp_index */ + if (data_o[0] & SL_TYPE_COMPRESSED_TCP) { + *pcomp_index = 2; + data_o[0] &= ~SL_TYPE_COMPRESSED_TCP; + } else if ((data_o[0] & SL_TYPE_UNCOMPRESSED_TCP) == + SL_TYPE_UNCOMPRESSED_TCP) { + *pcomp_index = 1; + data_o[0] &= 0x4F; + } else + *pcomp_index = 0; + + return compr_len; +} + +/* Expand a packet using Van Jacobson RFC1144 header compression */ +static int gprs_sndcp_pcomp_rfc1144_expand(uint8_t *data_o, uint8_t *data_i, + unsigned int len, + uint8_t pcomp_index, + struct slcompress *comp) +{ + int data_decompressed_len; + int type; + + /* Note: this function should never be called with pcomp_index=0, + * since this condition is already filtered + * out by gprs_sndcp_pcomp_expand() */ + + /* Determine the data type by the PCOMP index */ + switch (pcomp_index) { + case 0: + type = SL_TYPE_IP; + case 1: + type = SL_TYPE_UNCOMPRESSED_TCP; + break; + case 2: + type = SL_TYPE_COMPRESSED_TCP; + break; + default: + LOGP(DSNDCP, LOGL_ERROR, "gprs_sndcp_pcomp_rfc1144_expand() Invalid pcomp_index value (%d) detected, assuming no compression!\n", + pcomp_index); + type = SL_TYPE_IP; + break; + } + + /* Create a working copy of the incoming data */ + memcpy(data_o, data_i, len); + + /* Restore the original version nibble on + * marked uncompressed packets */ + if (type == SL_TYPE_UNCOMPRESSED_TCP) { + /* Just in case the phone tags uncompressed tcp-data + * (normally this is handled by pcomp so there is + * no need for tagging the data) */ + data_o[0] &= 0x4F; + data_decompressed_len = slhc_remember(comp, data_o, len); + return data_decompressed_len; + } + + /* Uncompress compressed packets */ + else if (type == SL_TYPE_COMPRESSED_TCP) { + data_decompressed_len = slhc_uncompress(comp, data_o, len); + return data_decompressed_len; + } + + /* Regular or unknown packets will not be touched */ + return len; +} + +/* Expand packet header */ +int gprs_sndcp_pcomp_expand(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t pcomp, + const struct llist_head *comp_entities) +{ + int rc; + uint8_t pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data_o); + OSMO_ASSERT(data_i); + OSMO_ASSERT(comp_entities); + + LOGP(DSNDCP, LOGL_DEBUG, "Header compression entity list: comp_entities=%p\n", + comp_entities); + + LOGP(DSNDCP, LOGL_DEBUG, "Header compression mode: pcomp=%d\n", pcomp); + + /* Skip on pcomp=0 */ + if (pcomp == 0) { + memcpy(data_o, data_i, len); + return len; + } + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_comp(comp_entities, pcomp); + + /* Skip compression if no suitable compression entity can be found */ + if (!comp_entity) { + memcpy(data_o, data_i, len); + return len; + } + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION); + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144); + + /* Find pcomp_index */ + pcomp_index = gprs_sndcp_comp_get_idx(comp_entity, pcomp); + + /* Run decompression algo */ + rc = gprs_sndcp_pcomp_rfc1144_expand(data_o, data_i, len, pcomp_index, + comp_entity->state); + slhc_i_status(comp_entity->state); + slhc_o_status(comp_entity->state); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header expansion done, old length=%d, new length=%d, entity=%p\n", + len, rc, comp_entity); + + return rc; +} + +/* Compress packet header */ +int gprs_sndcp_pcomp_compress(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t *pcomp, + const struct llist_head *comp_entities, + uint8_t nsapi) +{ + int rc; + uint8_t pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data_o); + OSMO_ASSERT(data_i); + OSMO_ASSERT(pcomp); + OSMO_ASSERT(comp_entities); + + LOGP(DSNDCP, LOGL_DEBUG, "Header compression entity list: comp_entities=%p\n", + comp_entities); + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_nsapi(comp_entities, nsapi); + + /* Skip compression if no suitable compression entity can be found */ + if (!comp_entity) { + *pcomp = 0; + memcpy(data_o, data_i, len); + return len; + } + + /* Note: Only protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION); + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo == RFC_1144); + + /* Run compression algo */ + rc = gprs_sndcp_pcomp_rfc1144_compress(&pcomp_index, data_o, data_i, + len, comp_entity->state); + slhc_i_status(comp_entity->state); + slhc_o_status(comp_entity->state); + + /* Find pcomp value */ + *pcomp = gprs_sndcp_comp_get_comp(comp_entity, pcomp_index); + + LOGP(DSNDCP, LOGL_DEBUG, "Header compression mode: pcomp=%d\n", *pcomp); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header compression done, old length=%d, new length=%d, entity=%p\n", + len, rc, comp_entity); + return rc; +} diff --git a/openbsc/src/gprs/sgsn_libgtp.c b/openbsc/src/gprs/sgsn_libgtp.c index be7637a..6e6bbfd 100644 --- a/openbsc/src/gprs/sgsn_libgtp.c +++ b/openbsc/src/gprs/sgsn_libgtp.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -307,6 +308,8 @@ static int send_act_pdp_cont_acc(struct sgsn_pdp_ctx *pctx) { struct sgsn_signal_data sig_data; + int rc; + struct gprs_llc_lle *lle; /* Inform others about it */ memset(&sig_data, 0, sizeof(sig_data)); @@ -314,7 +317,17 @@ osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_ACT, &sig_data); /* Send PDP CTX ACT to MS */ - return gsm48_tx_gsm_act_pdp_acc(pctx); + rc = gsm48_tx_gsm_act_pdp_acc(pctx); + if(rc < 0) + return rc; + + /* Send SNDCP XID to MS */ + lle = &pctx->mm->gb.llme->lle[pctx->sapi]; + rc = sndcp_sn_xid_req(lle,pctx->nsapi); + if(rc < 0) + return rc; + + return 0; } /* The GGSN has confirmed the creation of a PDP Context */ diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c index e6dc68d..0eea350 100644 --- a/openbsc/src/gprs/sgsn_vty.c +++ b/openbsc/src/gprs/sgsn_vty.c @@ -269,6 +269,14 @@ vty_out(vty, " timer t3395 %d%s", g_cfg->timers.T3395, VTY_NEWLINE); vty_out(vty, " timer t3397 %d%s", g_cfg->timers.T3397, VTY_NEWLINE); + if (g_cfg->pcomp_rfc1144.active) { + vty_out(vty, " compression rfc1144 active slots %d%s", + g_cfg->pcomp_rfc1144.s01 + 1, VTY_NEWLINE); + } else if (g_cfg->pcomp_rfc1144.passive) { + vty_out(vty, " compression rfc1144 passive%s", VTY_NEWLINE); + } else + vty_out(vty, " no compression rfc1144%s", VTY_NEWLINE); + return CMD_SUCCESS; } @@ -1074,6 +1082,41 @@ return CMD_SUCCESS; } +#define COMPRESSION_STR "Configure compression\n" +DEFUN(cfg_no_comp_rfc1144, cfg_no_comp_rfc1144_cmd, + "no compression rfc1144", + NO_STR COMPRESSION_STR "disable rfc1144 TCP/IP header compression\n") +{ + g_cfg->pcomp_rfc1144.active = 0; + g_cfg->pcomp_rfc1144.passive = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_comp_rfc1144, cfg_comp_rfc1144_cmd, + "compression rfc1144 active slots <1-256>", + COMPRESSION_STR + "RFC1144 Header compresion scheme\n" + "Compression is actively proposed\n" + "Number of compression state slots\n" + "Number of compression state slots\n") +{ + g_cfg->pcomp_rfc1144.active = 1; + g_cfg->pcomp_rfc1144.passive = 1; + g_cfg->pcomp_rfc1144.s01 = atoi(argv[0]) - 1; + return CMD_SUCCESS; +} + +DEFUN(cfg_comp_rfc1144p, cfg_comp_rfc1144p_cmd, + "compression rfc1144 passive", + COMPRESSION_STR + "RFC1144 Header compresion scheme\n" + "Compression is available on request\n") +{ + g_cfg->pcomp_rfc1144.active = 0; + g_cfg->pcomp_rfc1144.passive = 1; + return CMD_SUCCESS; +} + int sgsn_vty_init(void) { install_element_ve(&show_sgsn_cmd); @@ -1128,6 +1171,10 @@ install_element(SGSN_NODE, &cfg_sgsn_T3395_cmd); install_element(SGSN_NODE, &cfg_sgsn_T3397_cmd); + install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd); + install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd); + install_element(SGSN_NODE, &cfg_comp_rfc1144p_cmd); + return 0; } diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 3e66978..1804280 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -33,6 +33,8 @@ $(top_builddir)/src/gprs/gprs_llc_xid.o \ $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ $(top_builddir)/src/gprs/slhc.o \ + $(top_builddir)/src/gprs/gprs_sndcp_comp.o \ + $(top_builddir)/src/gprs/gprs_sndcp_pcomp.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ -- To view, visit https://gerrit.osmocom.org/642 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43 Gerrit-PatchSet: 26 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr From gerrit-no-reply at lists.osmocom.org Wed Aug 31 11:54:28 2016 From: gerrit-no-reply at lists.osmocom.org (dexter) Date: Wed, 31 Aug 2016 11:54:28 +0000 Subject: [PATCH] openbsc[master]: Adding compression control for V.42bis Message-ID: Review at https://gerrit.osmocom.org/803 Adding compression control for V.42bis Add code to handle compression (gprs_sndcp_dcomp.c/h) Adjustments in SNDCP and VTY Change-Id: I6d36cbdf2f5c5f83ca9ba57c70452f02b8582e7e --- M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_sndcp_dcomp.h M openbsc/include/openbsc/sgsn.h M openbsc/src/gprs/Makefile.am M openbsc/src/gprs/gprs_sndcp.c M openbsc/src/gprs/gprs_sndcp_comp.c A openbsc/src/gprs/gprs_sndcp_dcomp.c M openbsc/src/gprs/sgsn_vty.c M openbsc/tests/sgsn/Makefile.am 9 files changed, 607 insertions(+), 41 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/03/803/1 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 9bea689..e21b485 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -20,7 +20,7 @@ oap.h oap_messages.h \ gtphub.h gprs_llc_xid.h gprs_sndcp.h gprs_sndcp_xid.h \ iu.h slhc.h gprs_sndcp_comp.h gprs_sndcp_pcomp.h v42bis.h \ - v42bis_private.h + v42bis_private.h gprs_sndcp_dcomp.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_sndcp_dcomp.h b/openbsc/include/openbsc/gprs_sndcp_dcomp.h new file mode 100644 index 0000000..35d96cf --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_dcomp.h @@ -0,0 +1,48 @@ +/* GPRS SNDCP data compression handler */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +/* Note: The decompressed packet may have a maximum size of: + * Return value * MAX_DATADECOMPR_FAC */ +#define MAX_DATADECOMPR_FAC 10 + +/* Initalize data compression */ +int gprs_sndcp_dcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field); + +/* Terminate data compression */ +void gprs_sndcp_dcomp_term(struct gprs_sndcp_comp *comp_entity); + +/* Expand packet */ +int gprs_sndcp_dcomp_expand(uint8_t *data_o, uint8_t *data_i, unsigned int len, + uint8_t pcomp, + const struct llist_head *comp_entities); + +/* Compress packet */ +int gprs_sndcp_dcomp_compress(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t *pcomp, + const struct llist_head *comp_entities, + uint8_t nsapi); diff --git a/openbsc/include/openbsc/sgsn.h b/openbsc/include/openbsc/sgsn.h index 2d70f5a..12d918e 100644 --- a/openbsc/include/openbsc/sgsn.h +++ b/openbsc/include/openbsc/sgsn.h @@ -100,6 +100,15 @@ int passive; int s01; } pcomp_rfc1144; + + /* V.42vis data compression */ + struct { + int active; + int passive; + int p0; + int p1; + int p2; + } dcomp_v42bis; }; struct sgsn_instance { diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index f479d56..98abb3d 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -27,7 +27,8 @@ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ oap.c oap_messages.c gprs_llc_xid.c gprs_sndcp_xid.c \ - slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c v42bis.c + slhc.c gprs_sndcp_comp.c gprs_sndcp_pcomp.c v42bis.c \ + gprs_sndcp_dcomp.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ diff --git a/openbsc/src/gprs/gprs_sndcp.c b/openbsc/src/gprs/gprs_sndcp.c index 1ab55af..708129d 100644 --- a/openbsc/src/gprs/gprs_sndcp.c +++ b/openbsc/src/gprs/gprs_sndcp.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #define DEBUG_IP_PACKETS 1 /* 0=Disabled, 1=Enabled */ @@ -270,7 +271,8 @@ uint8_t *npdu; int npdu_len; int rc; - uint8_t *expnd; + uint8_t *hdr_expnd = NULL; + uint8_t *data_expnd = NULL; LOGP(DSNDCP, LOGL_DEBUG, "TLLI=0x%08x NSAPI=%u: Defragment output PDU %u " "num_seg=%u tot_len=%u\n", sne->lle->llme->tlli, sne->nsapi, @@ -314,18 +316,34 @@ DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); DEBUGP(DSNDCP, "===================================================\n"); #endif - expnd = talloc_zero_size(msg, msg->len + MAX_HDRDECOMPR_INCR); - rc = gprs_sndcp_pcomp_expand(expnd, npdu, npdu_len, + /* Apply data decompression */ + data_expnd = talloc_zero_size(msg, npdu_len * MAX_DATADECOMPR_FAC); + rc = gprs_sndcp_dcomp_expand(data_expnd, npdu, npdu_len, + sne->defrag.dcomp, sne->defrag.data); + if (rc < 0) { + LOGP(DSNDCP, LOGL_ERROR, "Data decompression failed!\n"); + talloc_free(data_expnd); + return -EIO; + } + + /* Apply header decompression */ + hdr_expnd = talloc_zero_size(msg, rc + MAX_HDRDECOMPR_INCR); + rc = gprs_sndcp_pcomp_expand(hdr_expnd, data_expnd, rc, sne->defrag.pcomp, sne->defrag.proto); if (rc < 0) { LOGP(DSNDCP, LOGL_ERROR, "TCP/IP Header decompression failed!\n"); - talloc_free(expnd); + talloc_free(hdr_expnd); + talloc_free(data_expnd); return -EIO; - } else - npdu_len = rc; + } + + /* Modify npu length, hdr_expnd is handed directly handed + * over to gsn_rx_sndcp_ud_ind(), see below */ + npdu_len = rc; + #if DEBUG_IP_PACKETS == 1 - debug_ip_packet(expnd, npdu_len, 1, "defrag_segments()"); + debug_ip_packet(hdr_expnd, npdu_len, 1, "defrag_segments()"); DEBUGP(DSNDCP, "===================================================\n"); DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); DEBUGP(DSNDCP, " \n"); @@ -333,9 +351,10 @@ /* Hand off packet to gtp */ rc = sgsn_rx_sndcp_ud_ind(&sne->ra_id, sne->lle->llme->tlli, - sne->nsapi, msg, npdu_len, expnd); + sne->nsapi, msg, npdu_len, hdr_expnd); - talloc_free(expnd); + talloc_free(hdr_expnd); + talloc_free(data_expnd); return rc; } @@ -608,7 +627,8 @@ uint8_t pcomp = 0; uint8_t dcomp = 0; int rc; - uint8_t *compr; + uint8_t *hdr_compr = NULL; + uint8_t *data_compr = NULL; /* Identifiers from UP: (TLLI, SAPI) + (BVCI, NSEI) */ @@ -619,18 +639,33 @@ DEBUGP(DSNDCP, "===================================================\n"); debug_ip_packet(msg->data, msg->len, 0, "sndcp_initdata_req()"); #endif - compr = talloc_zero_size(msg, msg->len); - rc = gprs_sndcp_pcomp_compress(compr, msg->data, msg->len, &pcomp, + /* Apply header compression */ + hdr_compr = talloc_zero_size(msg, msg->len); + rc = gprs_sndcp_pcomp_compress(hdr_compr, msg->data, msg->len, &pcomp, lle->llme->comp.proto, nsapi); if (rc < 0) { LOGP(DSNDCP, LOGL_ERROR, "TCP/IP Header compression failed!\n"); - talloc_free(compr); + talloc_free(hdr_compr); return -EIO; - } else { - msg->len = rc; - memcpy(msg->data, compr, rc); } - talloc_free(compr); + + /* Apply data compression */ + data_compr = talloc_zero_size(msg, msg->len * 10); + rc = gprs_sndcp_dcomp_compress(data_compr, hdr_compr, rc, &dcomp, + lle->llme->comp.data, nsapi); + if (rc < 0) { + LOGP(DSNDCP, LOGL_ERROR, "Data compression failed!\n"); + talloc_free(hdr_compr); + talloc_free(data_compr); + return -EIO; + } + + /* Copy results back to msg buffer */ + msg->len = rc; + memcpy(msg->data, data_compr, rc); + + talloc_free(hdr_compr); + talloc_free(data_compr); #if DEBUG_IP_PACKETS == 1 DEBUGP(DSNDCP, "===================================================\n"); DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); @@ -701,7 +736,8 @@ uint16_t npdu_num __attribute__((unused)); int npdu_len; int rc; - uint8_t *expnd; + uint8_t *hdr_expnd = NULL; + uint8_t *data_expnd = NULL; sch = (struct sndcp_common_hdr *) hdr; if (sch->first) { @@ -759,18 +795,35 @@ DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); DEBUGP(DSNDCP, "===================================================\n"); #endif - expnd = talloc_zero_size(msg, npdu_len + MAX_HDRDECOMPR_INCR); - rc = gprs_sndcp_pcomp_expand(expnd, npdu, npdu_len, + + /* Apply data decompression */ + data_expnd = talloc_zero_size(msg, npdu_len * MAX_DATADECOMPR_FAC); + rc = gprs_sndcp_dcomp_expand(data_expnd, npdu, npdu_len, + sne->defrag.dcomp, sne->defrag.data); + if (rc < 0) { + LOGP(DSNDCP, LOGL_ERROR, "Data decompression failed!\n"); + talloc_free(data_expnd); + return -EIO; + } + + /* Apply header decompression */ + hdr_expnd = talloc_zero_size(msg, rc + MAX_HDRDECOMPR_INCR); + rc = gprs_sndcp_pcomp_expand(hdr_expnd, data_expnd, rc, sne->defrag.pcomp, sne->defrag.proto); if (rc < 0) { LOGP(DSNDCP, LOGL_ERROR, "TCP/IP Header decompression failed!\n"); - talloc_free(expnd); + talloc_free(hdr_expnd); + talloc_free(data_expnd); return -EIO; - } else - npdu_len = rc; + } + + /* Modify npu length, hdr_expnd is handed directly handed + * over to gsn_rx_sndcp_ud_ind(), see below */ + npdu_len = rc; + #if DEBUG_IP_PACKETS == 1 - debug_ip_packet(expnd, npdu_len, 1, "sndcp_llunitdata_ind()"); + debug_ip_packet(hdr_expnd, npdu_len, 1, "sndcp_llunitdata_ind()"); DEBUGP(DSNDCP, "===================================================\n"); DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); DEBUGP(DSNDCP, " \n"); @@ -778,9 +831,10 @@ /* Hand off packet to gtp */ rc = sgsn_rx_sndcp_ud_ind(&sne->ra_id, lle->llme->tlli, - sne->nsapi, msg, npdu_len, expnd); + sne->nsapi, msg, npdu_len, hdr_expnd); - talloc_free(expnd); + talloc_free(data_expnd); + talloc_free(hdr_expnd); return rc; } @@ -849,8 +903,11 @@ LLIST_HEAD(comp_fields); struct gprs_sndcp_pcomp_rfc1144_params rfc1144_params; struct gprs_sndcp_comp_field rfc1144_comp_field; + struct gprs_sndcp_dcomp_v42bis_params v42bis_params; + struct gprs_sndcp_comp_field v42bis_comp_field; memset(&rfc1144_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + memset(&v42bis_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); /* Setup rfc1144 */ if (sgsn->cfg.pcomp_rfc1144.active) { @@ -866,6 +923,23 @@ rfc1144_comp_field.rfc1144_params = &rfc1144_params; entity++; llist_add(&rfc1144_comp_field.list, &comp_fields); + } + + /* Setup V.42bis */ + if (sgsn->cfg.dcomp_v42bis.active) { + v42bis_params.nsapi[0] = nsapi; + v42bis_params.nsapi_len = 1; + v42bis_params.p0 = sgsn->cfg.dcomp_v42bis.p0; + v42bis_params.p1 = sgsn->cfg.dcomp_v42bis.p1; + v42bis_params.p2 = sgsn->cfg.dcomp_v42bis.p2; + v42bis_comp_field.p = 1; + v42bis_comp_field.entity = entity; + v42bis_comp_field.algo = V42BIS; + v42bis_comp_field.comp[V42BIS_DCOMP1] = 1; + v42bis_comp_field.comp_len = V42BIS_DCOMP_NUM; + v42bis_comp_field.v42bis_params = &v42bis_params; + entity++; + llist_add(&v42bis_comp_field.list, &comp_fields); } /* Compile bytestream */ @@ -967,13 +1041,19 @@ /* Process proposed parameters */ switch (comp_field->algo) { case V42BIS: - /* V42BIS is not yet supported, - * so we set applicable nsapis to zero */ - LOGP(DSNDCP, LOGL_DEBUG, - "Rejecting V.42bis data compression...\n"); - comp_field->v42bis_params->nsapi_len = 0; - gprs_sndcp_comp_delete(lle->llme->comp.data, - comp_field->entity); + if (sgsn->cfg.dcomp_v42bis.passive && + comp_field->v42bis_params->nsapi_len > 0) { + LOGP(DSNDCP, LOGL_DEBUG, + "Accepting V.42bis data compression...\n"); + gprs_sndcp_comp_add(lle->llme, lle->llme->comp.data, + comp_field); + } else { + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting V.42bis data compression...\n"); + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + comp_field->rfc1144_params->nsapi_len = 0; + } break; case V44: /* V44 is not yet supported, diff --git a/openbsc/src/gprs/gprs_sndcp_comp.c b/openbsc/src/gprs/gprs_sndcp_comp.c index ede584e..6087ccb 100644 --- a/openbsc/src/gprs/gprs_sndcp_comp.c +++ b/openbsc/src/gprs/gprs_sndcp_comp.c @@ -34,6 +34,7 @@ #include #include #include +#include /* Create a new compression entity from a XID-Field */ static struct gprs_sndcp_comp *gprs_sndcp_comp_create(const void *ctx, @@ -100,16 +101,16 @@ comp_entity = NULL; } } else { - LOGP(DSNDCP, LOGL_ERROR, - "We don't support data compression yet!\n"); - talloc_free(comp_entity); - return NULL; + if (gprs_sndcp_dcomp_init(ctx, comp_entity, comp_field) != 0) { + talloc_free(comp_entity); + comp_entity = NULL; + } } /* Display info message */ if (comp_entity == NULL) { LOGP(DSNDCP, LOGL_ERROR, - "Header compression entity (%d) creation failed!\n", + "Compression entity (%d) creation failed!\n", comp_entity->entity); return NULL; } @@ -159,6 +160,7 @@ LOGP(DSNDCP, LOGL_INFO, "Deleting data compression entity %d ...\n", comp_entity->entity); + gprs_sndcp_dcomp_term(comp_entity); } } diff --git a/openbsc/src/gprs/gprs_sndcp_dcomp.c b/openbsc/src/gprs/gprs_sndcp_dcomp.c new file mode 100644 index 0000000..df7593a --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_dcomp.c @@ -0,0 +1,349 @@ +/* GPRS SNDCP data compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* A struct to capture the output data of compressor and decompressor */ +struct v42bis_output_buffer { + uint8_t *buf; + uint8_t *buf_pointer; + int len; +}; + +/* Handler to capture the output data from the compressor */ +void tx_v42bis_frame_handler(void *user_data, const uint8_t *pkt, int len) +{ + struct v42bis_output_buffer *output_buffer = + (struct v42bis_output_buffer *)user_data; + memcpy(output_buffer->buf_pointer, pkt, len); + output_buffer->buf_pointer += len; + output_buffer->len += len; + return; +} + +/* Handler to capture the output data from the decompressor */ +void rx_v42bis_data_handler(void *user_data, const uint8_t *buf, int len) +{ + struct v42bis_output_buffer *output_buffer = + (struct v42bis_output_buffer *)user_data; + memcpy(output_buffer->buf_pointer, buf, len); + output_buffer->buf_pointer += len; + output_buffer->len += len; + return; +} + +/* Initalize data compression */ +int gprs_sndcp_dcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a new data compression + * entity is created by gprs_sndcp.c */ + + OSMO_ASSERT(comp_entity); + OSMO_ASSERT(comp_field); + + if (comp_entity->compclass == SNDCP_XID_DATA_COMPRESSION + && comp_entity->algo == V42BIS) { + comp_entity->state = + v42bis_init(ctx, NULL, comp_field->v42bis_params->p0, + comp_field->v42bis_params->p1, + comp_field->v42bis_params->p2, + &tx_v42bis_frame_handler, NULL, + V42BIS_MAX_OUTPUT_LENGTH, + &rx_v42bis_data_handler, NULL, + V42BIS_MAX_OUTPUT_LENGTH); + LOGP(DSNDCP, LOGL_INFO, + "V.42bis data compression initalized.\n"); + return 0; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * data compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Terminate data compression */ +void gprs_sndcp_dcomp_term(struct gprs_sndcp_comp *comp_entity) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a data compression + * entity is deleted by gprs_sndcp.c */ + + OSMO_ASSERT(comp_entity); + + if (comp_entity->compclass == SNDCP_XID_DATA_COMPRESSION + && comp_entity->algo == RFC_1144) { + if (comp_entity->state) { + v42bis_free((v42bis_state_t *) comp_entity->state); + comp_entity->state = NULL; + } + LOGP(DSNDCP, LOGL_INFO, + "V.42bis data compression terminated.\n"); + return; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * data compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Perform a full reset of the V.42bis compression state */ +static void gprs_sndcp_dcomp_v42bis_reset(v42bis_state_t * comp) +{ + int p0, p1, p2; + p0 = comp->decompress.v42bis_parm_p0 | comp->compress.v42bis_parm_p0; + p1 = comp->decompress.v42bis_parm_n2; + p2 = comp->decompress.v42bis_parm_n7; + + DEBUGP(DSNDCP, + "Resetting compression entity (%p), p0=%d, p1=%d, p2=%d ...\n", + comp, p0, p1, p2); + + v42bis_init(NULL, comp, p0, p1, p2, &tx_v42bis_frame_handler, NULL, + V42BIS_MAX_OUTPUT_LENGTH, &rx_v42bis_data_handler, NULL, + V42BIS_MAX_OUTPUT_LENGTH); +} + +/* Compress a packet using V.42bis data compression */ +static int gprs_sndcp_dcomp_v42bis_compress(uint8_t *pcomp_index, + uint8_t *data_o, uint8_t *data_i, + unsigned int len, + v42bis_state_t * comp) +{ + uint8_t *data_c; + int rc; + int skip = 0; + struct v42bis_output_buffer compressed_data; + data_c = talloc_zero_size(NULL, len * MAX_DATADECOMPR_FAC); + + DEBUGP(DSNDCP, "I: %s\n", osmo_hexdump_nospc(data_i, len)); + + /* Reset V.42bis compression state */ + gprs_sndcp_dcomp_v42bis_reset(comp); +// v42bis_compression_control(comp, V42BIS_COMPRESSION_MODE_NEVER); + + /* Run compressor */ + compressed_data.buf = data_c; + compressed_data.buf_pointer = data_c; + compressed_data.len = 0; + comp->compress.user_data = (&compressed_data); + rc = v42bis_compress(comp, data_i, len); + if (rc < 0) { + LOGP(DSNDCP, LOGL_ERROR, + "Data compression failed, skipping...\n"); + skip = 1; + } + rc = v42bis_compress_flush(comp); + if (rc < 0) { + LOGP(DSNDCP, LOGL_ERROR, + "Data compression failed, skipping...\n"); + skip = 1; + } + if (compressed_data.len >= len) { + LOGP(DSNDCP, LOGL_ERROR, + "Data compression ineffective, skipping...\n"); + skip = 1; + } + + /* Skip compression */ + if (skip) { + *pcomp_index = 0; + memcpy(data_o, data_i, len); + talloc_free(data_c); + return len; + } + + *pcomp_index = 1; + memcpy(data_o, data_c, compressed_data.len); + talloc_free(data_c); + + DEBUGP(DSNDCP, "O: %s\n", osmo_hexdump_nospc(data_o, compressed_data.len)); + + return compressed_data.len; +} + +/* Expand a packet using V.42bis data compression */ +static int gprs_sndcp_dcomp_v42bis_expand(uint8_t *data_o, uint8_t *data_i, + unsigned int len, + uint8_t pcomp_index, + v42bis_state_t * comp) +{ + int rc; + struct v42bis_output_buffer uncompressed_data; + +// DEBUGP(DSNDCP, "I: %s\n", osmo_hexdump_nospc(data_i, len)); + + /* Skip when the packet is marked as uncompressed */ + if (pcomp_index == 0) { + memcpy(data_o, data_i, len); + return len; + } + + /* Reset V.42bis compression state */ + gprs_sndcp_dcomp_v42bis_reset(comp); + + /* Decompress packet */ + uncompressed_data.buf = data_o; + uncompressed_data.buf_pointer = data_o; + uncompressed_data.len = 0; + comp->decompress.user_data = (&uncompressed_data); + rc = v42bis_decompress(comp, data_i, len); + if (rc < 0) + return -EINVAL; + rc = v42bis_decompress_flush(comp); + if (rc < 0) + return -EINVAL; + +// DEBUGP(DSNDCP, "O: %s\n", osmo_hexdump_nospc(data_o, compressed_data.len)); + + return uncompressed_data.len; +} + +/* Expand packet */ +int gprs_sndcp_dcomp_expand(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t pcomp, + const struct llist_head *comp_entities) +{ + int rc; + uint8_t pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data_o); + OSMO_ASSERT(data_i); + OSMO_ASSERT(comp_entities); + + LOGP(DSNDCP, LOGL_DEBUG, + "Data compression entity list: comp_entities=%p\n", comp_entities); + + LOGP(DSNDCP, LOGL_DEBUG, "Data compression mode: dcomp=%d\n", pcomp); + + /* Skip on pcomp=0 */ + if (pcomp == 0) { + memcpy(data_o, data_i, len); + return len; + } + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_comp(comp_entities, pcomp); + + /* Skip compression if no suitable compression entity can be found */ + if (!comp_entity) { + memcpy(data_o, data_i, len); + return len; + } + + /* Note: Only data compression entities may appear in + * data compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_DATA_COMPRESSION); + + /* Note: Currently V42BIS is the only compression method we + * support, so the only allowed algorithm is V42BIS */ + OSMO_ASSERT(comp_entity->algo == V42BIS); + + /* Find pcomp_index */ + pcomp_index = gprs_sndcp_comp_get_idx(comp_entity, pcomp); + + /* Run decompression algo */ + rc = gprs_sndcp_dcomp_v42bis_expand(data_o, data_i, len, pcomp_index, + comp_entity->state); + + LOGP(DSNDCP, LOGL_DEBUG, + "Data expansion done, old length=%d, new length=%d, entity=%p\n", + len, rc, comp_entity); + + return rc; +} + +/* Compress packet */ +int gprs_sndcp_dcomp_compress(uint8_t *data_o, uint8_t *data_i, + unsigned int len, uint8_t *pcomp, + const struct llist_head *comp_entities, + uint8_t nsapi) +{ + int rc; + uint8_t pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data_o); + OSMO_ASSERT(data_i); + OSMO_ASSERT(pcomp); + OSMO_ASSERT(comp_entities); + + LOGP(DSNDCP, LOGL_DEBUG, + "Data compression entity list: comp_entities=%p\n", comp_entities); + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_nsapi(comp_entities, nsapi); + + /* Skip compression if no suitable compression entity can be found */ + if (!comp_entity) { + *pcomp = 0; + memcpy(data_o, data_i, len); + return len; + } + + /* Note: Only data compression entities may appear in + * data compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_DATA_COMPRESSION); + + /* Note: Currently V42BIS is the only compression method we + * support, so the only allowed algorithm is V42BIS */ + OSMO_ASSERT(comp_entity->algo == V42BIS); + + /* Run compression algo */ + rc = gprs_sndcp_dcomp_v42bis_compress(&pcomp_index, data_o, data_i, + len, comp_entity->state); + + /* Find pcomp value */ + *pcomp = gprs_sndcp_comp_get_comp(comp_entity, pcomp_index); + + LOGP(DSNDCP, LOGL_DEBUG, "Data compression mode: dcomp=%d\n", *pcomp); + + LOGP(DSNDCP, LOGL_DEBUG, + "Data compression done, old length=%d, new length=%d, entity=%p\n", + len, rc, comp_entity); + + return rc; +} diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c index 0eea350..7b3b7bc 100644 --- a/openbsc/src/gprs/sgsn_vty.c +++ b/openbsc/src/gprs/sgsn_vty.c @@ -277,6 +277,26 @@ } else vty_out(vty, " no compression rfc1144%s", VTY_NEWLINE); + if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 1) { + vty_out(vty, + " compression v42bis active direction sgsn codewords %d strlen %d%s", + g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2, + VTY_NEWLINE); + } else if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 2) { + vty_out(vty, + " compression v42bis active direction phone codewords %d strlen %d%s", + g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2, + VTY_NEWLINE); + } else if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 3) { + vty_out(vty, + " compression v42bis active direction both codewords %d strlen %d%s", + g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2, + VTY_NEWLINE); + } else if (g_cfg->dcomp_v42bis.passive) { + vty_out(vty, " compression v42bis passive%s", VTY_NEWLINE); + } else + vty_out(vty, " no compression v42bis%s", VTY_NEWLINE); + return CMD_SUCCESS; } @@ -1117,6 +1137,59 @@ return CMD_SUCCESS; } +DEFUN(cfg_no_comp_v42bis, cfg_no_comp_v42bis_cmd, + "no compression v42bis", + NO_STR COMPRESSION_STR "disable V.42bis data compression\n") +{ + g_cfg->dcomp_v42bis.active = 0; + g_cfg->dcomp_v42bis.passive = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_comp_v42bis, cfg_comp_v42bis_cmd, + "compression v42bis active direction (sgsn|phone|both) codewords <512-65535> strlen <6-250>", + COMPRESSION_STR + "V.42bis data compresion scheme\n" + "Compression is actively proposed\n" + "Direction in which the compression shall be active (p0)\n" + "Negotiation initiator-responder direction only\n" + "Negotiation responder-initiator direction only\n" + "Both directions\n" + "Number of codewords (p1)\n" + "Number of codewords\n" + "Maximum string length (p2)\n" "Maximum string length\n") +{ + g_cfg->dcomp_v42bis.active = 1; + g_cfg->dcomp_v42bis.passive = 1; + + switch (argv[0][0]) { + case 's': + g_cfg->dcomp_v42bis.p0 = 1; + break; + case 'p': + g_cfg->dcomp_v42bis.p0 = 2; + break; + case 'b': + g_cfg->dcomp_v42bis.p0 = 3; + break; + } + + g_cfg->dcomp_v42bis.p1 = atoi(argv[1]); + g_cfg->dcomp_v42bis.p2 = atoi(argv[2]); + return CMD_SUCCESS; +} + +DEFUN(cfg_comp_v42bisp, cfg_comp_v42bisp_cmd, + "compression v42bis passive", + COMPRESSION_STR + "V.42bis data compresion scheme\n" + "Compression is available on request\n") +{ + g_cfg->dcomp_v42bis.active = 0; + g_cfg->dcomp_v42bis.passive = 1; + return CMD_SUCCESS; +} + int sgsn_vty_init(void) { install_element_ve(&show_sgsn_cmd); @@ -1174,7 +1247,9 @@ install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd); install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd); install_element(SGSN_NODE, &cfg_comp_rfc1144p_cmd); - + install_element(SGSN_NODE, &cfg_no_comp_v42bis_cmd); + install_element(SGSN_NODE, &cfg_comp_v42bis_cmd); + install_element(SGSN_NODE, &cfg_comp_v42bisp_cmd); return 0; } diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 1804280..97e8c60 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -35,6 +35,8 @@ $(top_builddir)/src/gprs/slhc.o \ $(top_builddir)/src/gprs/gprs_sndcp_comp.o \ $(top_builddir)/src/gprs/gprs_sndcp_pcomp.o \ + $(top_builddir)/src/gprs/gprs_sndcp_dcomp.o \ + $(top_builddir)/src/gprs/v42bis.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ -- To view, visit https://gerrit.osmocom.org/803 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I6d36cbdf2f5c5f83ca9ba57c70452f02b8582e7e Gerrit-PatchSet: 1 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter From gerrit-no-reply at lists.osmocom.org Wed Aug 31 13:01:27 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Wed, 31 Aug 2016 13:01:27 +0000 Subject: osmo-bts[master]: common/rsl: move decision whether to chan act ack/nack to co... In-Reply-To: References: Message-ID: Patch Set 2: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/747 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I57ba60c670730c6d7877a6a9b96ece0a7679a0bb Gerrit-PatchSet: 2 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: No From gerrit-no-reply at lists.osmocom.org Wed Aug 31 13:03:54 2016 From: gerrit-no-reply at lists.osmocom.org (Harald Welte) Date: Wed, 31 Aug 2016 13:03:54 +0000 Subject: osmo-bts[master]: dyn TS: if PCU is not connected, allow operation as TCH In-Reply-To: References: Message-ID: Patch Set 2: (1 comment) https://gerrit.osmocom.org/#/c/748/2/src/common/rsl.c File src/common/rsl.c: PS2, Line 930: o for the BSC, it is not : * helpful in any way to know that a PDCH channel fails to : * work this is not entirely true. For OML/OSS it is important to understand that something went wrong. So even if we acknowledge it on RSL, it is one of the locations where sending an OML ALERT would be very useful to propagate important errors up the network, rather than completely hiding it in the BTS and leaving the operator wonder why performance is below what's expected. -- To view, visit https://gerrit.osmocom.org/748 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I2a0b9730197786b99ff3bc1f08c75f7d279cb1f7 Gerrit-PatchSet: 2 Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr Gerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr Gerrit-HasComments: Yes