aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gbproxy/gb_proxy_main.c5
-rw-r--r--src/gbproxy/gb_proxy_patch.c14
-rw-r--r--src/gbproxy/gb_proxy_tlli.c18
-rw-r--r--src/gbproxy/gb_proxy_vty.c29
-rw-r--r--src/gprs/gprs_gb_parse.c13
-rw-r--r--src/gprs/sgsn_ares.c12
-rw-r--r--src/gtphub/gtphub.c89
-rw-r--r--src/gtphub/gtphub_main.c5
-rw-r--r--src/gtphub/gtphub_sock.c4
-rw-r--r--src/sgsn/gprs_gmm.c283
-rw-r--r--src/sgsn/gprs_gmm_attach.c2
-rw-r--r--src/sgsn/gprs_gmm_fsm.c60
-rw-r--r--src/sgsn/gprs_llc.c66
-rw-r--r--src/sgsn/gprs_mm_state_gb_fsm.c2
-rw-r--r--src/sgsn/gprs_mm_state_iu_fsm.c2
-rw-r--r--src/sgsn/gprs_sgsn.c5
-rw-r--r--src/sgsn/gprs_sm.c6
-rw-r--r--src/sgsn/gprs_sndcp.c8
-rw-r--r--src/sgsn/gprs_subscriber.c16
-rw-r--r--src/sgsn/sgsn_libgtp.c68
-rw-r--r--src/sgsn/sgsn_main.c33
-rw-r--r--src/sgsn/sgsn_vty.c14
22 files changed, 476 insertions, 278 deletions
diff --git a/src/gbproxy/gb_proxy_main.c b/src/gbproxy/gb_proxy_main.c
index 4319fda6..8c839804 100644
--- a/src/gbproxy/gb_proxy_main.c
+++ b/src/gbproxy/gb_proxy_main.c
@@ -196,6 +196,11 @@ static void handle_options(int argc, char **argv)
break;
}
}
+
+ if (argc > optind) {
+ fprintf(stderr, "Unsupported positional arguments on command line\n");
+ exit(2);
+ }
}
int gbproxy_vty_is_config_node(struct vty *vty, int node)
diff --git a/src/gbproxy/gb_proxy_patch.c b/src/gbproxy/gb_proxy_patch.c
index 6235b04f..2bc3b4b7 100644
--- a/src/gbproxy/gb_proxy_patch.c
+++ b/src/gbproxy/gb_proxy_patch.c
@@ -436,28 +436,26 @@ int gbproxy_set_patch_filter(struct gbproxy_match *match, const char *filter,
int gbproxy_check_imsi(struct gbproxy_match *match,
const uint8_t *imsi, size_t imsi_len)
{
- char mi_buf[200];
int rc;
+ struct osmo_mobile_identity mi;
if (!match->enable)
return 1;
- rc = gprs_is_mi_imsi(imsi, imsi_len);
- if (rc > 0)
- rc = gsm48_mi_to_string(mi_buf, sizeof(mi_buf), imsi, imsi_len);
- if (rc <= 0) {
+ rc = osmo_mobile_identity_decode(&mi, imsi, imsi_len, false);
+ if (rc || mi.type != GSM_MI_TYPE_IMSI) {
LOGP(DGPRS, LOGL_NOTICE, "Invalid IMSI %s\n",
osmo_hexdump(imsi, imsi_len));
return -1;
}
- LOGP(DGPRS, LOGL_DEBUG, "Checking IMSI '%s' (%d)\n", mi_buf, rc);
+ LOGP(DGPRS, LOGL_DEBUG, "Checking IMSI '%s' (%d)\n", mi.imsi, rc);
- rc = regexec(&match->re_comp, mi_buf, 0, NULL, 0);
+ rc = regexec(&match->re_comp, mi.imsi, 0, NULL, 0);
if (rc == REG_NOMATCH) {
LOGP(DGPRS, LOGL_INFO,
"IMSI '%s' doesn't match pattern '%s'\n",
- mi_buf, match->re_str);
+ mi.imsi, match->re_str);
return 0;
}
diff --git a/src/gbproxy/gb_proxy_tlli.c b/src/gbproxy/gb_proxy_tlli.c
index 4e21ede8..e9271c22 100644
--- a/src/gbproxy/gb_proxy_tlli.c
+++ b/src/gbproxy/gb_proxy_tlli.c
@@ -401,14 +401,16 @@ static void gbproxy_assign_imsi(struct gbproxy_peer *peer,
peer, parse_ctx->imsi, parse_ctx->imsi_len);
if (other_link_info && other_link_info != link_info) {
- char mi_buf[200];
- mi_buf[0] = '\0';
- gsm48_mi_to_string(mi_buf, sizeof(mi_buf),
- parse_ctx->imsi, parse_ctx->imsi_len);
- LOGP(DGPRS, LOGL_INFO,
- "Removing TLLI %08x from list (IMSI %s re-used)\n",
- other_link_info->tlli.current, mi_buf);
- gbproxy_delete_link_info(peer, other_link_info);
+ struct osmo_mobile_identity mi;
+ if (osmo_mobile_identity_decode(&mi, parse_ctx->imsi, parse_ctx->imsi_len, false)
+ || mi.type != GSM_MI_TYPE_IMSI) {
+ LOGP(DGPRS, LOGL_ERROR, "Failed to decode Mobile Identity\n");
+ } else {
+ LOGP(DGPRS, LOGL_INFO,
+ "Removing TLLI %08x from list (IMSI %s re-used)\n",
+ other_link_info->tlli.current, mi.imsi);
+ gbproxy_delete_link_info(peer, other_link_info);
+ }
}
/* Update the IMSI field */
diff --git a/src/gbproxy/gb_proxy_vty.c b/src/gbproxy/gb_proxy_vty.c
index 5c4f4542..355b23fb 100644
--- a/src/gbproxy/gb_proxy_vty.c
+++ b/src/gbproxy/gb_proxy_vty.c
@@ -554,7 +554,6 @@ DEFUN(show_gbproxy_links, show_gbproxy_links_cmd, "show gbproxy links",
SHOW_STR "Display information about the Gb proxy\n" "Show logical links\n")
{
struct gbproxy_peer *peer;
- char mi_buf[200];
time_t now;
struct timespec ts = {0,};
@@ -569,17 +568,20 @@ DEFUN(show_gbproxy_links, show_gbproxy_links_cmd, "show gbproxy links",
llist_for_each_entry(link_info, &state->logical_links, list) {
time_t age = now - link_info->timestamp;
+ struct osmo_mobile_identity mi;
+ const char *imsi_str;
if (link_info->imsi > 0) {
- snprintf(mi_buf, sizeof(mi_buf), "(invalid)");
- gsm48_mi_to_string(mi_buf, sizeof(mi_buf),
- link_info->imsi,
- link_info->imsi_len);
+ if (osmo_mobile_identity_decode(&mi, link_info->imsi, link_info->imsi_len, false)
+ || mi.type != GSM_MI_TYPE_IMSI)
+ imsi_str = "(invalid)";
+ else
+ imsi_str = mi.imsi;
} else {
- snprintf(mi_buf, sizeof(mi_buf), "(none)");
+ imsi_str = "(none)";
}
vty_out(vty, " TLLI %08x, IMSI %s, AGE %d",
- link_info->tlli.current, mi_buf, (int)age);
+ link_info->tlli.current, imsi_str, (int)age);
if (link_info->stored_msgs_len)
vty_out(vty, ", STORED %"PRIu32"/%"PRIu32,
@@ -708,7 +710,6 @@ DEFUN(delete_gb_link_by_id, delete_gb_link_by_id_cmd,
struct gbproxy_peer *peer = 0;
struct gbproxy_link_info *link_info, *nxt;
struct gbproxy_patch_state *state;
- char mi_buf[200];
int found = 0;
match = argv[1][0];
@@ -729,6 +730,8 @@ DEFUN(delete_gb_link_by_id, delete_gb_link_by_id_cmd,
state = &peer->patch_state;
llist_for_each_entry_safe(link_info, nxt, &state->logical_links, list) {
+ struct osmo_mobile_identity mi;
+
switch (match) {
case MATCH_TLLI:
if (link_info->tlli.current != ident)
@@ -741,12 +744,10 @@ DEFUN(delete_gb_link_by_id, delete_gb_link_by_id_cmd,
case MATCH_IMSI:
if (!link_info->imsi)
continue;
- mi_buf[0] = '\0';
- gsm48_mi_to_string(mi_buf, sizeof(mi_buf),
- link_info->imsi,
- link_info->imsi_len);
-
- if (strcmp(mi_buf, imsi) != 0)
+ if (osmo_mobile_identity_decode(&mi, link_info->imsi, link_info->imsi_len, false)
+ || mi.type != GSM_MI_TYPE_IMSI)
+ continue;
+ if (strcmp(mi.imsi, imsi) != 0)
continue;
break;
}
diff --git a/src/gprs/gprs_gb_parse.c b/src/gprs/gprs_gb_parse.c
index 379674a9..e5de4d4c 100644
--- a/src/gprs/gprs_gb_parse.c
+++ b/src/gprs/gprs_gb_parse.c
@@ -604,13 +604,12 @@ void gprs_gb_log_parse_context(int log_level,
}
if (parse_ctx->imsi) {
- char mi_buf[200];
- mi_buf[0] = '\0';
- gsm48_mi_to_string(mi_buf, sizeof(mi_buf),
- parse_ctx->imsi, parse_ctx->imsi_len);
- LOGPC(DGPRS, log_level, "%s IMSI %s",
- sep, mi_buf);
- sep = ",";
+ struct osmo_mobile_identity mi;
+ if (osmo_mobile_identity_decode(&mi, parse_ctx->imsi, parse_ctx->imsi_len, false) == 0
+ && mi.type == GSM_MI_TYPE_IMSI) {
+ LOGPC(DGPRS, log_level, "%s IMSI %s", sep, mi.imsi);
+ sep = ",";
+ }
}
if (parse_ctx->invalidate_tlli) {
LOGPC(DGPRS, log_level, "%s invalidate", sep);
diff --git a/src/gprs/sgsn_ares.c b/src/gprs/sgsn_ares.c
index ba168d62..38e31e13 100644
--- a/src/gprs/sgsn_ares.c
+++ b/src/gprs/sgsn_ares.c
@@ -51,8 +51,8 @@ static int ares_osmo_fd_cb(struct osmo_fd *fd, unsigned int what)
LOGP(DGPRS, LOGL_DEBUG, "C-ares fd(%d) ready(%d)\n", fd->fd, what);
ares_process_fd(sgsn->ares_channel,
- (what & BSC_FD_READ) ? fd->fd : ARES_SOCKET_BAD,
- (what & BSC_FD_WRITE) ? fd->fd : ARES_SOCKET_BAD);
+ (what & OSMO_FD_READ) ? fd->fd : ARES_SOCKET_BAD,
+ (what & OSMO_FD_WRITE) ? fd->fd : ARES_SOCKET_BAD);
osmo_ares_reschedule(sgsn);
return 0;
}
@@ -120,14 +120,14 @@ static void setup_ares_osmo_fd(void *data, int fd, int read, int write)
update_fd:
if (read)
- ufd->fd.when |= BSC_FD_READ;
+ ufd->fd.when |= OSMO_FD_READ;
else
- ufd->fd.when &= ~BSC_FD_READ;
+ ufd->fd.when &= ~OSMO_FD_READ;
if (write)
- ufd->fd.when |= BSC_FD_WRITE;
+ ufd->fd.when |= OSMO_FD_WRITE;
else
- ufd->fd.when &= ~BSC_FD_WRITE;
+ ufd->fd.when &= ~OSMO_FD_WRITE;
osmo_ares_reschedule(sgsn);
}
diff --git a/src/gtphub/gtphub.c b/src/gtphub/gtphub.c
index ca5857b3..c24652e0 100644
--- a/src/gtphub/gtphub.c
+++ b/src/gtphub/gtphub.c
@@ -167,12 +167,12 @@ void gsn_addr_copy(struct gsn_addr *gsna, const struct gsn_addr *src)
}
int gsn_addr_from_sockaddr(struct gsn_addr *gsna, uint16_t *port,
- const struct osmo_sockaddr *sa)
+ const struct sgsn_sockaddr *sa)
{
char addr_str[256];
char port_str[6];
- if (osmo_sockaddr_to_strs(addr_str, sizeof(addr_str),
+ if (sgsn_sockaddr_to_strs(addr_str, sizeof(addr_str),
port_str, sizeof(port_str),
sa, (NI_NUMERICHOST | NI_NUMERICSERV))
!= 0) {
@@ -853,10 +853,7 @@ static int gtphub_sock_init(struct osmo_fd *ofd,
return -1;
}
- ofd->when = BSC_FD_READ;
- ofd->cb = cb;
- ofd->data = data;
- ofd->priv_nr = ofd_id;
+ osmo_fd_setup(ofd, -1, OSMO_FD_READ, cb, data, ofd_id);
int rc;
rc = osmo_sock_init_ofd(ofd,
@@ -925,7 +922,7 @@ static void gtphub_bind_stop(struct gtphub_bind *b) {
/* Recv datagram from from->fd, write sender's address to *from_addr.
* Return the number of bytes read, zero on error. */
static int gtphub_read(const struct osmo_fd *from,
- struct osmo_sockaddr *from_addr,
+ struct sgsn_sockaddr *from_addr,
uint8_t *buf, size_t buf_len)
{
OSMO_ASSERT(from_addr);
@@ -946,7 +943,7 @@ static int gtphub_read(const struct osmo_fd *from,
}
LOG(LOGL_DEBUG, "Received %d bytes from %s: %s%s\n",
- (int)received, osmo_sockaddr_to_str(from_addr),
+ (int)received, sgsn_sockaddr_to_str(from_addr),
osmo_hexdump(buf, received > 1000? 1000 : received),
received > 1000 ? "..." : "");
@@ -1948,14 +1945,14 @@ static int from_sgsns_read_cb(struct osmo_fd *from_sgsns_ofd, unsigned int what)
LOG(LOGL_DEBUG, "=== reading from SGSN (%s)\n",
gtphub_plane_idx_names[plane_idx]);
- if (!(what & BSC_FD_READ))
+ if (!(what & OSMO_FD_READ))
return 0;
struct gtphub *hub = from_sgsns_ofd->data;
static uint8_t buf[4096];
- struct osmo_sockaddr from_addr;
- struct osmo_sockaddr to_addr;
+ struct sgsn_sockaddr from_addr;
+ struct sgsn_sockaddr to_addr;
struct osmo_fd *to_ofd;
int len;
uint8_t *reply_buf;
@@ -1979,14 +1976,14 @@ static int from_ggsns_read_cb(struct osmo_fd *from_ggsns_ofd, unsigned int what)
OSMO_ASSERT(plane_idx < GTPH_PLANE_N);
LOG(LOGL_DEBUG, "=== reading from GGSN (%s)\n",
gtphub_plane_idx_names[plane_idx]);
- if (!(what & BSC_FD_READ))
+ if (!(what & OSMO_FD_READ))
return 0;
struct gtphub *hub = from_ggsns_ofd->data;
static uint8_t buf[4096];
- struct osmo_sockaddr from_addr;
- struct osmo_sockaddr to_addr;
+ struct sgsn_sockaddr from_addr;
+ struct sgsn_sockaddr to_addr;
struct osmo_fd *to_ofd;
int len;
uint8_t *reply_buf;
@@ -2071,9 +2068,9 @@ static int gtphub_unmap(struct gtphub *hub,
static int gsn_addr_to_sockaddr(struct gsn_addr *src,
uint16_t port,
- struct osmo_sockaddr *dst)
+ struct sgsn_sockaddr *dst)
{
- return osmo_sockaddr_init_udp(dst, gsn_addr_to_str(src), port);
+ return sgsn_sockaddr_init_udp(dst, gsn_addr_to_str(src), port);
}
/* If p is an Echo request, replace p's data with the matching response and
@@ -2107,7 +2104,7 @@ static int gtphub_handle_echo_req(struct gtphub *hub, struct gtp_packet_desc *p,
}
struct gtphub_peer_port *gtphub_known_addr_have_port(const struct gtphub_bind *bind,
- const struct osmo_sockaddr *addr);
+ const struct sgsn_sockaddr *addr);
/* Parse buffer as GTP packet, replace elements in-place and return the ofd and
* address to forward to. Return a pointer to the osmo_fd, but copy the
@@ -2117,13 +2114,13 @@ struct gtphub_peer_port *gtphub_known_addr_have_port(const struct gtphub_bind *b
int gtphub_handle_buf(struct gtphub *hub,
unsigned int side_idx,
unsigned int plane_idx,
- const struct osmo_sockaddr *from_addr,
+ const struct sgsn_sockaddr *from_addr,
uint8_t *buf,
size_t received,
time_t now,
uint8_t **reply_buf,
struct osmo_fd **to_ofd,
- struct osmo_sockaddr *to_addr)
+ struct sgsn_sockaddr *to_addr)
{
struct gtphub_bind *from_bind = &hub->to_gsns[side_idx][plane_idx];
struct gtphub_bind *to_bind = &hub->to_gsns[other_side_idx(side_idx)][plane_idx];
@@ -2138,7 +2135,7 @@ int gtphub_handle_buf(struct gtphub *hub,
(side_idx == GTPH_SIDE_GGSN)? "<-" : "->",
gtphub_plane_idx_names[plane_idx],
gtphub_side_idx_names[side_idx],
- osmo_sockaddr_to_str(from_addr),
+ sgsn_sockaddr_to_str(from_addr),
gtp_type_str(p.type));
if (p.rc <= 0) {
@@ -2146,7 +2143,7 @@ int gtphub_handle_buf(struct gtphub *hub,
gtp_type_str(p.type),
gtphub_side_idx_names[side_idx],
gtphub_plane_idx_names[plane_idx],
- osmo_sockaddr_to_str(from_addr));
+ sgsn_sockaddr_to_str(from_addr));
return -1;
}
@@ -2156,7 +2153,7 @@ int gtphub_handle_buf(struct gtphub *hub,
reply_len = gtphub_handle_echo_req(hub, &p, reply_buf);
if (reply_len > 0) {
/* It was an echo. Nothing left to do. */
- osmo_sockaddr_copy(to_addr, from_addr);
+ sgsn_sockaddr_copy(to_addr, from_addr);
*to_ofd = &from_bind->ofd;
rate_ctr_inc(&from_bind->counters_io->ctr[GTPH_CTR_PKTS_OUT]);
@@ -2165,7 +2162,7 @@ int gtphub_handle_buf(struct gtphub *hub,
LOG(LOGL_DEBUG, "%s Echo response to %s: %d bytes to %s\n",
(side_idx == GTPH_SIDE_GGSN)? "-->" : "<--",
gtphub_side_idx_names[side_idx],
- (int)reply_len, osmo_sockaddr_to_str(to_addr));
+ (int)reply_len, sgsn_sockaddr_to_str(to_addr));
return reply_len;
}
if (reply_len < 0)
@@ -2178,7 +2175,7 @@ int gtphub_handle_buf(struct gtphub *hub,
* so no-one else is allowed to talk to us from that side. */
struct gtphub_peer_port *from_peer = hub->proxy[side_idx][plane_idx];
if (from_peer) {
- if (osmo_sockaddr_cmp(&from_peer->sa, from_addr) != 0) {
+ if (sgsn_sockaddr_cmp(&from_peer->sa, from_addr) != 0) {
LOG(LOGL_ERROR,
"Rejecting: %s proxy configured, but GTP packet"
" received on %s bind is from another sender:"
@@ -2186,7 +2183,7 @@ int gtphub_handle_buf(struct gtphub *hub,
gtphub_side_idx_names[side_idx],
gtphub_side_idx_names[side_idx],
gtphub_port_str(from_peer),
- osmo_sockaddr_to_str(from_addr));
+ sgsn_sockaddr_to_str(from_addr));
return -1;
}
}
@@ -2204,7 +2201,7 @@ int gtphub_handle_buf(struct gtphub *hub,
if (side_idx == GTPH_SIDE_GGSN) {
LOG(LOGL_ERROR, "Dropping packet%s: unknown GGSN peer: %s\n",
gtp_type_str(p.type),
- osmo_sockaddr_to_str(from_addr));
+ sgsn_sockaddr_to_str(from_addr));
return -1;
} else {
/* SGSN */
@@ -2216,7 +2213,7 @@ int gtphub_handle_buf(struct gtphub *hub,
"Dropping packet%s: User plane peer was not"
"announced by PDP Context: %s\n",
gtp_type_str(p.type),
- osmo_sockaddr_to_str(from_addr));
+ sgsn_sockaddr_to_str(from_addr));
return -1;
}
@@ -2235,7 +2232,7 @@ int gtphub_handle_buf(struct gtphub *hub,
LOG(LOGL_ERROR, "Dropping packet%s: invalid %s peer: %s\n",
gtp_type_str(p.type),
gtphub_side_idx_names[side_idx],
- osmo_sockaddr_to_str(from_addr));
+ sgsn_sockaddr_to_str(from_addr));
return -1;
}
@@ -2309,7 +2306,7 @@ int gtphub_handle_buf(struct gtphub *hub,
if (!to_peer_from_seq)
gtphub_map_seq(&p, from_peer, to_peer);
- osmo_sockaddr_copy(to_addr, &to_peer->sa);
+ sgsn_sockaddr_copy(to_addr, &to_peer->sa);
*reply_buf = (uint8_t*)p.data;
@@ -2335,7 +2332,7 @@ int gtphub_handle_buf(struct gtphub *hub,
(side_idx == GTPH_SIDE_SGSN)? "-->" : "<--",
gtphub_side_idx_names[other_side_idx(side_idx)],
p.header_tei, p.seq,
- (int)received, osmo_sockaddr_to_str(to_addr));
+ (int)received, sgsn_sockaddr_to_str(to_addr));
return received;
}
@@ -2645,7 +2642,7 @@ static struct gtphub_peer_port *gtphub_port_find(const struct gtphub_bind *bind,
}
struct gtphub_peer_port *gtphub_port_find_sa(const struct gtphub_bind *bind,
- const struct osmo_sockaddr *addr)
+ const struct sgsn_sockaddr *addr)
{
struct gsn_addr gsna;
uint16_t port;
@@ -2762,7 +2759,7 @@ struct gtphub_peer_port *gtphub_port_have(struct gtphub *hub,
/* Find a GGSN peer with a matching address. If the address is known but the
* port not, create a new port for that peer address. */
struct gtphub_peer_port *gtphub_known_addr_have_port(const struct gtphub_bind *bind,
- const struct osmo_sockaddr *addr)
+ const struct sgsn_sockaddr *addr)
{
struct gtphub_peer_addr *pa;
struct gtphub_peer_port *pp;
@@ -2817,7 +2814,7 @@ static int gtphub_resolve_ggsn(struct gtphub *hub,
/* TODO move to osmocom/core/socket.c ? */
/* use this in osmo_sock_init() to remove dup. */
-/* Internal: call getaddrinfo for osmo_sockaddr_init(). The caller is required
+/* Internal: call getaddrinfo for sgsn_sockaddr_init(). The caller is required
to call freeaddrinfo(*result), iff zero is returned. */
static int _osmo_getaddrinfo(struct addrinfo **result,
uint16_t family, uint16_t type, uint8_t proto,
@@ -2844,7 +2841,7 @@ static int _osmo_getaddrinfo(struct addrinfo **result,
}
/* TODO move to osmocom/core/socket.c ? */
-int osmo_sockaddr_init(struct osmo_sockaddr *addr,
+int sgsn_sockaddr_init(struct sgsn_sockaddr *addr,
uint16_t family, uint16_t type, uint8_t proto,
const char *host, uint16_t port)
{
@@ -2865,9 +2862,9 @@ int osmo_sockaddr_init(struct osmo_sockaddr *addr,
return 0;
}
-int osmo_sockaddr_to_strs(char *addr_str, size_t addr_str_len,
+int sgsn_sockaddr_to_strs(char *addr_str, size_t addr_str_len,
char *port_str, size_t port_str_len,
- const struct osmo_sockaddr *addr,
+ const struct sgsn_sockaddr *addr,
int flags)
{
int rc;
@@ -2896,14 +2893,14 @@ int osmo_sockaddr_to_strs(char *addr_str, size_t addr_str_len,
return rc;
}
-const char *osmo_sockaddr_to_strb(const struct osmo_sockaddr *addr,
+const char *sgsn_sockaddr_to_strb(const struct sgsn_sockaddr *addr,
char *buf, size_t buf_len)
{
+ char portbuf[6];
const int portbuf_len = 6;
OSMO_ASSERT(buf_len > portbuf_len);
- char *portbuf = buf + buf_len - portbuf_len;
buf_len -= portbuf_len;
- if (osmo_sockaddr_to_strs(buf, buf_len,
+ if (sgsn_sockaddr_to_strs(buf, buf_len,
portbuf, portbuf_len,
addr,
NI_NUMERICHOST | NI_NUMERICSERV))
@@ -2918,17 +2915,17 @@ const char *osmo_sockaddr_to_strb(const struct osmo_sockaddr *addr,
return buf;
}
-const char *osmo_sockaddr_to_str(const struct osmo_sockaddr *addr)
+const char *sgsn_sockaddr_to_str(const struct sgsn_sockaddr *addr)
{
static char buf[256];
- const char *result = osmo_sockaddr_to_strb(addr, buf, sizeof(buf));
+ const char *result = sgsn_sockaddr_to_strb(addr, buf, sizeof(buf));
if (! result)
return "(invalid)";
return result;
}
-int osmo_sockaddr_cmp(const struct osmo_sockaddr *a,
- const struct osmo_sockaddr *b)
+int sgsn_sockaddr_cmp(const struct sgsn_sockaddr *a,
+ const struct sgsn_sockaddr *b)
{
if (a == b)
return 0;
@@ -2938,7 +2935,7 @@ int osmo_sockaddr_cmp(const struct osmo_sockaddr *a,
return 1;
if (a->l != b->l) {
/* Lengths are not the same, but determine the order. Will
- * anyone ever sort a list by osmo_sockaddr though...? */
+ * anyone ever sort a list by sgsn_sockaddr though...? */
int cmp = memcmp(&a->a, &b->a, (a->l < b->l)? a->l : b->l);
if (cmp == 0) {
if (a->l < b->l)
@@ -2951,8 +2948,8 @@ int osmo_sockaddr_cmp(const struct osmo_sockaddr *a,
return memcmp(&a->a, &b->a, a->l);
}
-void osmo_sockaddr_copy(struct osmo_sockaddr *dst,
- const struct osmo_sockaddr *src)
+void sgsn_sockaddr_copy(struct sgsn_sockaddr *dst,
+ const struct sgsn_sockaddr *src)
{
OSMO_ASSERT(src->l <= sizeof(dst->a));
memcpy(&dst->a, &src->a, src->l);
diff --git a/src/gtphub/gtphub_main.c b/src/gtphub/gtphub_main.c
index f693f099..664c801e 100644
--- a/src/gtphub/gtphub_main.c
+++ b/src/gtphub/gtphub_main.c
@@ -322,6 +322,11 @@ static void handle_options(struct cmdline_cfg *ccfg, int argc, char **argv)
break;
}
}
+
+ if (argc > optind) {
+ fprintf(stderr, "Unsupported positional arguments on command line\n");
+ exit(2);
+ }
}
int main(int argc, char **argv)
diff --git a/src/gtphub/gtphub_sock.c b/src/gtphub/gtphub_sock.c
index 1acd5a62..18375334 100644
--- a/src/gtphub/gtphub_sock.c
+++ b/src/gtphub/gtphub_sock.c
@@ -33,13 +33,13 @@
LOGP(DGTPHUB, level, fmt, ##args)
int gtphub_write(const struct osmo_fd *to,
- const struct osmo_sockaddr *to_addr,
+ const struct sgsn_sockaddr *to_addr,
const uint8_t *buf, size_t buf_len)
{
errno = 0;
ssize_t sent = sendto(to->fd, buf, buf_len, 0,
(struct sockaddr*)&to_addr->a, to_addr->l);
- LOG(LOGL_DEBUG, "to %s\n", osmo_sockaddr_to_str(to_addr));
+ LOG(LOGL_DEBUG, "to %s\n", sgsn_sockaddr_to_str(to_addr));
if (sent == -1) {
LOG(LOGL_ERROR, "error: %s\n", strerror(errno));
diff --git a/src/sgsn/gprs_gmm.c b/src/sgsn/gprs_gmm.c
index b6b16854..3f7c8ab7 100644
--- a/src/sgsn/gprs_gmm.c
+++ b/src/sgsn/gprs_gmm.c
@@ -280,8 +280,10 @@ int gsm48_tx_gmm_att_ack(struct sgsn_mm_ctx *mm)
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 ATT ACK");
struct gsm48_hdr *gh;
struct gsm48_attach_ack *aa;
- uint8_t *mid;
unsigned long t;
+ struct osmo_mobile_identity mi;
+ uint8_t *l;
+ int rc;
#if 0
uint8_t *ptsig;
#endif
@@ -300,7 +302,7 @@ int gsm48_tx_gmm_att_ack(struct sgsn_mm_ctx *mm)
aa->att_result = 1; /* GPRS only */
t = osmo_tdef_get(sgsn->cfg.T_defs, 3312, OSMO_TDEF_S, -1);
aa->ra_upd_timer = gprs_secs_to_tmr_floor(t);
- aa->radio_prio = 4; /* lowest */
+ aa->radio_prio = 0x44; /* lowest */
gsm48_encode_ra(&aa->ra_id, &mm->ra);
#if 0
@@ -321,9 +323,18 @@ int gsm48_tx_gmm_att_ack(struct sgsn_mm_ctx *mm)
#ifdef PTMSI_ALLOC
/* Optional: Allocated P-TMSI */
- mid = msgb_put(msg, GSM48_MID_TMSI_LEN);
- gsm48_generate_mid_from_tmsi(mid, mm->p_tmsi);
- mid[0] = GSM48_IE_GMM_ALLOC_PTMSI;
+ mi = (struct osmo_mobile_identity){
+ .type = GSM_MI_TYPE_TMSI,
+ .tmsi = mm->p_tmsi,
+ };
+ l = msgb_tl_put(msg, GSM48_IE_GMM_ALLOC_PTMSI);
+ rc = osmo_mobile_identity_encode_msgb(msg, &mi, false);
+ if (rc < 0) {
+ LOGMMCTXP(LOGL_ERROR, mm, "Cannot encode Mobile Identity\n");
+ msgb_free(msg);
+ return -EINVAL;
+ }
+ *l = rc;
#endif
/* Optional: MS-identity (combined attach) */
@@ -1026,31 +1037,35 @@ void gsm0408_gprs_access_cancelled(struct sgsn_mm_ctx *ctx, int gmm_cause)
static int gsm48_rx_gmm_id_resp(struct sgsn_mm_ctx *ctx, struct msgb *msg)
{
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
- uint8_t mi_type = gh->data[1] & GSM_MI_TYPE_MASK;
- long mi_typel = mi_type;
- char mi_string[GSM48_MI_SIZE];
+ long mi_typel;
+ char mi_log_string[32];
+ struct osmo_mobile_identity mi;
- gsm48_mi_to_string(mi_string, sizeof(mi_string), &gh->data[1], gh->data[0]);
if (!ctx) {
DEBUGP(DMM, "from unknown TLLI 0x%08x?!? This should not happen\n", msgb_tlli(msg));
return -EINVAL;
}
- LOGMMCTXP(LOGL_DEBUG, ctx, "-> GMM IDENTITY RESPONSE: MI(%s)=%s\n",
- gsm48_mi_type_name(mi_type), mi_string);
+ if (osmo_mobile_identity_decode(&mi, &gh->data[1], gh->data[0], false)) {
+ LOGMMCTXP(LOGL_ERROR, ctx, "-> GMM IDENTITY RESPONSE: cannot decode Mobile Identity\n");
+ return -EINVAL;
+ }
+ osmo_mobile_identity_to_str_buf(mi_log_string, sizeof(mi_log_string), &mi);
+
+ LOGMMCTXP(LOGL_DEBUG, ctx, "-> GMM IDENTITY RESPONSE: MI=%s\n", mi_log_string);
if (ctx->t3370_id_type == GSM_MI_TYPE_NONE) {
LOGMMCTXP(LOGL_NOTICE, ctx,
- "Got unexpected IDENTITY RESPONSE: MI(%s)=%s, "
+ "Got unexpected IDENTITY RESPONSE: MI=%s, "
"ignoring message\n",
- gsm48_mi_type_name(mi_type), mi_string);
+ mi_log_string);
return -EINVAL;
}
- if (mi_type == ctx->t3370_id_type)
+ if (mi.type == ctx->t3370_id_type)
mmctx_timer_stop(ctx, 3370);
- switch (mi_type) {
+ switch (mi.type) {
case GSM_MI_TYPE_IMSI:
/* we already have a mm context with current TLLI, but no
* P-TMSI / IMSI yet. What we now need to do is to fill
@@ -1058,7 +1073,7 @@ static int gsm48_rx_gmm_id_resp(struct sgsn_mm_ctx *ctx, struct msgb *msg)
if (strlen(ctx->imsi) == 0) {
/* Check if we already have a MM context for this IMSI */
struct sgsn_mm_ctx *ictx;
- ictx = sgsn_mm_ctx_by_imsi(mi_string);
+ ictx = sgsn_mm_ctx_by_imsi(mi.imsi);
if (ictx) {
/* Handle it like in gsm48_rx_gmm_det_req,
* except that no messages are sent to the BSS */
@@ -1070,16 +1085,17 @@ static int gsm48_rx_gmm_id_resp(struct sgsn_mm_ctx *ctx, struct msgb *msg)
mm_ctx_cleanup_free(ictx, "GPRS IMSI re-use");
}
}
- osmo_strlcpy(ctx->imsi, mi_string, sizeof(ctx->imsi));
+ OSMO_STRLCPY_ARRAY(ctx->imsi, mi.imsi);
break;
case GSM_MI_TYPE_IMEI:
- osmo_strlcpy(ctx->imei, mi_string, sizeof(ctx->imei));
+ OSMO_STRLCPY_ARRAY(ctx->imei, mi.imei);
break;
case GSM_MI_TYPE_IMEISV:
break;
}
/* Check if we can let the mobile station enter */
+ mi_typel = mi.type;
return osmo_fsm_inst_dispatch(ctx->gmm_att_req.fsm, E_IDEN_RESP_RECV, (void *)mi_typel);
}
@@ -1099,19 +1115,46 @@ static inline void ptmsi_update(struct sgsn_mm_ctx *ctx)
osmo_fsm_inst_dispatch(ctx->gmm_fsm, E_GMM_COMMON_PROC_INIT_REQ, NULL);
}
+/* Detect if RAT has changed */
+static bool mmctx_did_rat_change(struct sgsn_mm_ctx *mmctx, struct msgb *msg)
+{
+ if (MSG_IU_UE_CTX(msg) && mmctx->ran_type != MM_CTX_T_UTRAN_Iu)
+ return true;
+ if (!MSG_IU_UE_CTX(msg) && mmctx->ran_type != MM_CTX_T_GERAN_Gb)
+ return true;
+ return false;
+}
+
+/* Notify the FSM of a RAT change */
+static void mmctx_handle_rat_change(struct sgsn_mm_ctx *mmctx, struct msgb *msg, struct gprs_llc_llme *llme)
+{
+ struct gmm_rat_change_data rat_chg = {
+ .llme = llme
+ };
+
+ rat_chg.new_ran_type = MSG_IU_UE_CTX(msg) ? MM_CTX_T_UTRAN_Iu : MM_CTX_T_GERAN_Gb;
+
+ if (rat_chg.new_ran_type != mmctx->ran_type)
+ osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_RAT_CHANGE, (void *) &rat_chg);
+ else
+ LOGMMCTXP(LOGL_ERROR, mmctx, "RAT didn't change or not implemented (ran_type=%u, "
+ "msg_iu_ue_ctx=%p\n", mmctx->ran_type, MSG_IU_UE_CTX(msg));
+
+}
+
/* 3GPP TS 24.008 § 9.4.1 Attach request */
static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
struct gprs_llc_llme *llme)
{
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
- uint8_t *cur = gh->data, *msnc, *mi, *ms_ra_acc_cap;
- uint8_t msnc_len, att_type, mi_len, mi_type, ms_ra_acc_cap_len;
+ uint8_t *cur = gh->data, *msnc, *mi_data, *ms_ra_acc_cap;
+ uint8_t msnc_len, att_type, mi_len, ms_ra_acc_cap_len;
uint16_t drx_par;
- uint32_t tmsi;
- char mi_string[GSM48_MI_SIZE];
+ char mi_log_string[32];
struct gprs_ra_id ra_id;
uint16_t cid = 0;
enum gsm48_gmm_cause reject_cause;
+ struct osmo_mobile_identity mi;
int rc;
LOGMMCTXP(LOGL_INFO, ctx, "-> GMM ATTACH REQUEST ");
@@ -1155,15 +1198,15 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
/* 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;
+ mi_data = cur;
cur += mi_len;
- gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);
+ rc = osmo_mobile_identity_decode(&mi, mi_data, mi_len, false);
+ if (rc)
+ goto err_inval;
+ osmo_mobile_identity_to_str_buf(mi_log_string, sizeof(mi_log_string), &mi);
- DEBUGPC(DMM, "MI(%s) type=\"%s\" ", mi_string,
+ DEBUGPC(DMM, "MI(%s) type=\"%s\" ", mi_log_string,
get_value_string(gprs_att_t_strs, att_type));
/* Old routing area identification 10.5.5.15. Skip it */
@@ -1180,11 +1223,11 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
/* Optional: Old P-TMSI Signature, Requested READY timer, TMSI Status */
- switch (mi_type) {
+ 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);
+ ctx = sgsn_mm_ctx_by_imsi(mi.imsi);
if (!ctx) {
if (MSG_IU_UE_CTX(msg))
ctx = sgsn_mm_ctx_alloc_iu(MSG_IU_UE_CTX(msg));
@@ -1194,15 +1237,13 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
reject_cause = GMM_CAUSE_NET_FAIL;
goto rejected;
}
- osmo_strlcpy(ctx->imsi, mi_string, sizeof(ctx->imsi));
+ OSMO_STRLCPY_ARRAY(ctx->imsi, mi.imsi);
}
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);
+ ctx = sgsn_mm_ctx_by_ptmsi(mi.tmsi);
if (!ctx) {
/* Allocate a context as most of our code expects one.
* Context will not have an IMSI ultil ID RESP is received */
@@ -1214,16 +1255,19 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
reject_cause = GMM_CAUSE_NET_FAIL;
goto rejected;
}
- ctx->p_tmsi = tmsi;
+ ctx->p_tmsi = mi.tmsi;
}
break;
default:
LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting ATTACH REQUEST with "
- "MI type %s\n", gsm48_mi_type_name(mi_type));
+ "MI %s\n", mi_log_string);
reject_cause = GMM_CAUSE_MS_ID_NOT_DERIVED;
goto rejected;
}
+ if (mmctx_did_rat_change(ctx, msg))
+ mmctx_handle_rat_change(ctx, msg, llme);
+
if (ctx->ran_type == MM_CTX_T_GERAN_Gb) {
ctx->gb.tlli = msgb_tlli(msg);
ctx->gb.llme = llme;
@@ -1245,8 +1289,8 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
ctx->ciph_algo)) {
reject_cause = GMM_CAUSE_PROTO_ERR_UNSPEC;
LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting ATTACH REQUEST with MI "
- "type %s because MS do not support required %s "
- "encryption\n", gsm48_mi_type_name(mi_type),
+ "%s because MS do not support required %s "
+ "encryption\n", mi_log_string,
get_value_string(gprs_cipher_names,ctx->ciph_algo));
goto rejected;
}
@@ -1393,8 +1437,10 @@ static int gsm48_tx_gmm_ra_upd_ack(struct sgsn_mm_ctx *mm)
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 UPD ACK");
struct gsm48_hdr *gh;
struct gsm48_ra_upd_ack *rua;
- uint8_t *mid;
unsigned long t;
+ uint8_t *l;
+ int rc;
+ struct osmo_mobile_identity mi;
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ROUTING_AREA_ACKED]);
LOGMMCTXP(LOGL_INFO, mm, "<- ROUTING AREA UPDATE ACCEPT\n");
@@ -1424,9 +1470,17 @@ static int gsm48_tx_gmm_ra_upd_ack(struct sgsn_mm_ctx *mm)
#ifdef PTMSI_ALLOC
/* Optional: Allocated P-TMSI */
- mid = msgb_put(msg, GSM48_MID_TMSI_LEN);
- gsm48_generate_mid_from_tmsi(mid, mm->p_tmsi);
- mid[0] = GSM48_IE_GMM_ALLOC_PTMSI;
+ mi = (struct osmo_mobile_identity){
+ .type = GSM_MI_TYPE_TMSI,
+ .tmsi = mm->p_tmsi,
+ };
+ l = msgb_tl_put(msg, GSM48_IE_GMM_ALLOC_PTMSI);
+ rc = osmo_mobile_identity_encode_msgb(msg, &mi, false);
+ if (rc < 0) {
+ msgb_free(msg);
+ return -EINVAL;
+ }
+ *l = rc;
#endif
/* Optional: Negotiated READY timer value */
@@ -1470,21 +1524,19 @@ static void process_ms_ctx_status(struct sgsn_mm_ctx *mmctx,
* being in state PDP-INACTIVE. */
llist_for_each_entry_safe(pdp, pdp2, &mmctx->pdp_list, list) {
- if (pdp->nsapi < 8) {
- if (!(pdp_status[0] & (1 << pdp->nsapi))) {
- LOGMMCTXP(LOGL_NOTICE, mmctx, "Dropping PDP context for NSAPI=%u "
- "due to PDP CTX STATUS IE= 0x%02x%02x\n",
- pdp->nsapi, pdp_status[1], pdp_status[0]);
- sgsn_delete_pdp_ctx(pdp);
- }
- } else {
- if (!(pdp_status[1] & (1 << (pdp->nsapi - 8)))) {
- LOGMMCTXP(LOGL_NOTICE, mmctx, "Dropping PDP context for NSAPI=%u "
- "due to PDP CTX STATUS IE= 0x%02x%02x\n",
- pdp->nsapi, pdp_status[1], pdp_status[0]);
- sgsn_delete_pdp_ctx(pdp);
- }
- }
+ bool inactive = (pdp->nsapi < 8) ?
+ !(pdp_status[0] & (1 << pdp->nsapi)) :
+ !(pdp_status[1] & (1 << (pdp->nsapi - 8)));
+ if (!inactive)
+ continue;
+
+ LOGMMCTXP(LOGL_NOTICE, mmctx, "Dropping PDP context for NSAPI=%u "
+ "due to PDP CTX STATUS IE=0x%02x%02x\n",
+ pdp->nsapi, pdp_status[1], pdp_status[0]);
+ if (pdp->ggsn)
+ sgsn_delete_pdp_ctx(pdp);
+ else /* GTP side already detached, freeing */
+ sgsn_pdp_ctx_free(pdp);
}
}
@@ -1576,19 +1628,14 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
} 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);
- const 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);
+ struct osmo_mobile_identity mi;
+ if (osmo_mobile_identity_decode(&mi, TLVP_VAL(&tp, GSM48_IE_GMM_ALLOC_PTMSI),
+ TLVP_LEN(&tp, GSM48_IE_GMM_ALLOC_PTMSI), false)
+ || mi.type != GSM_MI_TYPE_TMSI) {
+ LOGIUP(MSG_IU_UE_CTX(msg), LOGL_ERROR, "Cannot decode P-TMSI\n");
+ goto rejected;
}
+ mmctx = sgsn_mm_ctx_by_ptmsi(mi.tmsi);
#else
LOGIUP(MSG_IU_UE_CTX(msg), LOGL_ERROR,
"Rejecting GMM RA Update Request: No Iu support\n");
@@ -1604,29 +1651,44 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
mmctx->p_tmsi, mmctx->p_tmsi_old,
mmctx->gb.tlli, mmctx->gb.tlli_new,
osmo_rai_name(&mmctx->ra));
- osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_COMMON_PROC_INIT_REQ, NULL);
+ /* A RAT change will trigger the common procedure
+ * below after handling the RAT change. Protect it
+ * here from being called twice */
+ if (!mmctx_did_rat_change(mmctx, msg))
+ osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_COMMON_PROC_INIT_REQ, NULL);
+
}
} else if (!gprs_ra_id_equals(&mmctx->ra, &old_ra_id) ||
mmctx->gmm_fsm->state == ST_GMM_DEREGISTERED)
{
- /* We cannot use the mmctx */
- LOGMMCTXP(LOGL_INFO, mmctx,
- "The MM context cannot be used, RA: %s\n",
- osmo_rai_name(&mmctx->ra));
- /* mmctx is set to NULL and gprs_llgmm_unassign(llme) will be
- called below, let's make sure we don't keep dangling llme
- pointers in mmctx (OS#3957). */
- if (mmctx->ran_type == MM_CTX_T_GERAN_Gb)
- OSMO_ASSERT(mmctx->gb.llme == NULL);
- mmctx = NULL;
+ /* We've received either a RAU for a MS which isn't registered
+ * or a RAU with an unknown RA ID. As long the SGSN doesn't support
+ * PS handover we treat this as invalid RAU */
+ struct gprs_ra_id new_ra_id;
+ char new_ra[32];
+
+ bssgp_parse_cell_id(&new_ra_id, msgb_bcid(msg));
+ osmo_rai_name_buf(new_ra, sizeof(new_ra), &new_ra_id);
+
+ if (mmctx->gmm_fsm->state == ST_GMM_DEREGISTERED)
+ LOGMMCTXP(LOGL_INFO, mmctx,
+ "Rejecting RAU - GMM state is deregistered. Old RA: %s New RA: %s\n",
+ osmo_rai_name(&old_ra_id), new_ra);
+ else
+ LOGMMCTXP(LOGL_INFO, mmctx,
+ "Rejecting RAU - Old RA doesn't match MM. Old RA: %s New RA: %s\n",
+ osmo_rai_name(&old_ra_id), new_ra);
+
+ reject_cause = GMM_CAUSE_IMPL_DETACHED;
+ goto rejected;
}
if (!mmctx) {
if (llme) {
/* send a XID reset to re-set all LLC sequence numbers
* in the MS */
- LOGGBP(llme, LOGL_NOTICE, "LLC XID RESET\n");
- gprs_llgmm_reset(llme);
+ LOGGBP(llme, DMM, LOGL_NOTICE, "LLC XID RESET\n");
+ gprs_llgmm_reset_oldmsg(msg, GPRS_SAPI_GMM, llme);
}
/* The MS has to perform GPRS attach */
/* Device is still IMSI attached for CS but initiate GPRS ATTACH,
@@ -1636,13 +1698,18 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
goto rejected;
}
+ if (mmctx_did_rat_change(mmctx, msg)) {
+ mmctx_handle_rat_change(mmctx, msg, llme);
+ osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_COMMON_PROC_INIT_REQ, NULL);
+ }
+
/* Store new BVCI/NSEI in MM context (FIXME: delay until we ack?) */
msgid2mmctx(mmctx, msg);
/* Bump the statistics of received signalling msgs for this MM context */
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]);
/* Update the MM context with the new RA-ID */
- if (mmctx->ran_type == MM_CTX_T_GERAN_Gb) {
+ if (mmctx->ran_type == MM_CTX_T_GERAN_Gb && msgb_bcid(msg)) {
bssgp_parse_cell_id(&mmctx->ra, msgb_bcid(msg));
/* Update the MM context with the new (i.e. foreign) TLLI */
mmctx->gb.tlli = msgb_tlli(msg);
@@ -1762,11 +1829,11 @@ static int gsm48_rx_gmm_ptmsi_reall_compl(struct sgsn_mm_ctx *mmctx)
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 service_type, mi_len, mi_type;
- uint32_t tmsi;
+ uint8_t *cur = gh->data, *mi_data;
+ uint8_t service_type, mi_len;
struct tlv_parsed tp;
- char mi_string[GSM48_MI_SIZE];
+ struct osmo_mobile_identity mi;
+ char mi_log_string[32];
enum gsm48_gmm_cause reject_cause;
int rc;
@@ -1786,15 +1853,14 @@ static int gsm48_rx_gmm_service_req(struct sgsn_mm_ctx *ctx, struct msgb *msg)
/* 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;
+ mi_data = cur;
cur += mi_len;
+ rc = osmo_mobile_identity_decode(&mi, mi_data, mi_len, false);
+ if (rc)
+ goto err_inval;
+ osmo_mobile_identity_to_str_buf(mi_log_string, sizeof(mi_log_string), &mi);
- gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);
-
- DEBUGPC(DMM, "MI(%s) type=\"%s\" ", mi_string,
+ DEBUGPC(DMM, "MI(%s) type=\"%s\" ", mi_log_string,
get_value_string(gprs_service_t_strs, service_type));
LOGPC(DMM, LOGL_INFO, "\n");
@@ -1802,11 +1868,11 @@ static int gsm48_rx_gmm_service_req(struct sgsn_mm_ctx *ctx, struct msgb *msg)
/* 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) {
+ 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);
+ ctx = sgsn_mm_ctx_by_imsi(mi.imsi);
if (!ctx) {
/* FIXME: We need to have a context for service request? */
reject_cause = GMM_CAUSE_IMPL_DETACHED;
@@ -1815,11 +1881,9 @@ static int gsm48_rx_gmm_service_req(struct sgsn_mm_ctx *ctx, struct msgb *msg)
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);
+ ctx = sgsn_mm_ctx_by_ptmsi(mi.tmsi);
if (!ctx) {
/* FIXME: We need to have a context for service request? */
reject_cause = GMM_CAUSE_IMPL_DETACHED;
@@ -1829,7 +1893,7 @@ static int gsm48_rx_gmm_service_req(struct sgsn_mm_ctx *ctx, struct msgb *msg)
break;
default:
LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting SERVICE REQUEST with "
- "MI type %s\n", gsm48_mi_type_name(mi_type));
+ "MI %s\n", mi_log_string);
reject_cause = GMM_CAUSE_MS_ID_NOT_DERIVED;
goto rejected;
}
@@ -1905,7 +1969,7 @@ int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
if (llme && !mmctx &&
gh->msg_type != GSM48_MT_GMM_ATTACH_REQ &&
gh->msg_type != GSM48_MT_GMM_RA_UPD_REQ) {
- LOGGBP(llme, LOGL_NOTICE, "Cannot handle GMM for unknown MM CTX\n");
+ LOGGBP(llme, DMM, LOGL_NOTICE, "Cannot handle GMM for unknown MM CTX\n");
/* 4.7.10 */
if (gh->msg_type == GSM48_MT_GMM_STATUS) {
/* TLLI unassignment */
@@ -1944,6 +2008,23 @@ int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
return rc;
}
+ /* A RAT change is only expected/allowed for RAU/Attach Req */
+ if (mmctx && mmctx_did_rat_change(mmctx, msg)) {
+ switch (gh->msg_type) {
+ case GSM48_MT_GMM_RA_UPD_REQ:
+ case GSM48_MT_GMM_ATTACH_REQ:
+ break;
+ default:
+ /* This shouldn't happen with other message types and
+ * we need to error out to prevent a crash */
+ LOGMMCTXP(LOGL_NOTICE, mmctx, "Dropping GMM %s which was received on different "
+ "RAT (mmctx ran_type=%u, msg_iu_ue_ctx=%p\n",
+ get_value_string(gprs_msgt_gmm_names, gh->msg_type),
+ mmctx->ran_type, MSG_IU_UE_CTX(msg));
+ return -EINVAL;
+ }
+ }
+
/*
* For a few messages, mmctx may be NULL. For most, we want to ensure a
* non-NULL mmctx. At the same time, we want to keep the message
diff --git a/src/sgsn/gprs_gmm_attach.c b/src/sgsn/gprs_gmm_attach.c
index 130f8d1c..c903a016 100644
--- a/src/sgsn/gprs_gmm_attach.c
+++ b/src/sgsn/gprs_gmm_attach.c
@@ -449,7 +449,7 @@ struct osmo_fsm gmm_attach_req_fsm = {
static __attribute__((constructor)) void gprs_gmm_fsm_init(void)
{
- osmo_fsm_register(&gmm_attach_req_fsm);
+ OSMO_ASSERT(osmo_fsm_register(&gmm_attach_req_fsm) == 0);
}
void gmm_att_req_free(struct sgsn_mm_ctx *mm) {
diff --git a/src/sgsn/gprs_gmm_fsm.c b/src/sgsn/gprs_gmm_fsm.c
index fac06f27..886726c6 100644
--- a/src/sgsn/gprs_gmm_fsm.c
+++ b/src/sgsn/gprs_gmm_fsm.c
@@ -1,6 +1,30 @@
+/* GMM mobility management states on the network side, 3GPP TS 24.008 § 4.1.3.3 */
+/*
+ * (C) 2019 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: AGPL-3.0+
+ *
+ * Author: Pau Espin Pedrol <pespin@sysmocom.de>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
#include <osmocom/core/tdef.h>
#include <osmocom/sgsn/gprs_gmm_fsm.h>
+#include <osmocom/sgsn/gprs_mm_state_gb_fsm.h>
+#include <osmocom/sgsn/gprs_mm_state_iu_fsm.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/sgsn.h>
@@ -67,9 +91,12 @@ static void st_gmm_registered_normal(struct osmo_fsm_inst *fi, uint32_t event, v
static void st_gmm_registered_suspended(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch(event) {
- case E_GMM_RESUME:
+ case E_GMM_RESUME: /* explicit BSSGP RESUME from BSS */
gmm_fsm_state_chg(fi, ST_GMM_REGISTERED_NORMAL);
break;
+ case E_GMM_COMMON_PROC_INIT_REQ: /* implicit resume from MS */
+ gmm_fsm_state_chg(fi, ST_GMM_COMMON_PROC_INIT);
+ break;
}
}
@@ -121,10 +148,12 @@ static struct osmo_fsm_state gmm_fsm_states[] = {
.action = st_gmm_registered_normal,
},
[ST_GMM_REGISTERED_SUSPENDED] = {
- .in_event_mask = X(E_GMM_RESUME),
+ .in_event_mask = X(E_GMM_RESUME) |
+ X(E_GMM_COMMON_PROC_INIT_REQ),
.out_state_mask =
X(ST_GMM_DEREGISTERED) |
- X(ST_GMM_REGISTERED_NORMAL),
+ X(ST_GMM_REGISTERED_NORMAL) |
+ X(ST_GMM_COMMON_PROC_INIT),
.name = "Registered.SUSPENDED",
.action = st_gmm_registered_suspended,
},
@@ -149,11 +178,32 @@ const struct value_string gmm_fsm_event_names[] = {
/* OSMO_VALUE_STRING(E_GMM_DETACH_ACCEPTED), */
OSMO_VALUE_STRING(E_GMM_SUSPEND),
OSMO_VALUE_STRING(E_GMM_CLEANUP),
+ OSMO_VALUE_STRING(E_GMM_RAT_CHANGE),
{ 0, NULL }
};
void gmm_fsm_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data) {
+ struct sgsn_mm_ctx *mmctx = fi->priv;
+ struct gmm_rat_change_data *rat_chg = (struct gmm_rat_change_data *)data;
+
switch (event) {
+ case E_GMM_RAT_CHANGE:
+
+ switch (fi->state) {
+ case ST_GMM_COMMON_PROC_INIT:
+ gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED);
+ default:
+ if (mmctx->ran_type == MM_CTX_T_GERAN_Gb)
+ osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_IMPLICIT_DETACH, NULL);
+ else if (mmctx->ran_type == MM_CTX_T_UTRAN_Iu) {
+ osmo_fsm_inst_dispatch(mmctx->iu.mm_state_fsm, E_PMM_IMPLICIT_DETACH, NULL);
+ mmctx->gb.llme = rat_chg->llme;
+ }
+
+ mmctx->ran_type = rat_chg->new_ran_type;
+ break;
+ }
+
case E_GMM_CLEANUP:
switch (fi->state) {
case ST_GMM_DEREGISTERED:
@@ -175,7 +225,7 @@ struct osmo_fsm gmm_fsm = {
.states = gmm_fsm_states,
.num_states = ARRAY_SIZE(gmm_fsm_states),
.event_names = gmm_fsm_event_names,
- .allstate_event_mask = X(E_GMM_CLEANUP),
+ .allstate_event_mask = X(E_GMM_CLEANUP) | X(E_GMM_RAT_CHANGE),
.allstate_action = gmm_fsm_allstate_action,
.log_subsys = DMM,
.timer_cb = gmm_fsm_timer_cb,
@@ -183,5 +233,5 @@ struct osmo_fsm gmm_fsm = {
static __attribute__((constructor)) void gmm_fsm_init(void)
{
- osmo_fsm_register(&gmm_fsm);
+ OSMO_ASSERT(osmo_fsm_register(&gmm_fsm) == 0);
}
diff --git a/src/sgsn/gprs_llc.c b/src/sgsn/gprs_llc.c
index 2a27da84..e357d16f 100644
--- a/src/sgsn/gprs_llc.c
+++ b/src/sgsn/gprs_llc.c
@@ -22,6 +22,7 @@
#include <errno.h>
#include <stdint.h>
#include <stdbool.h>
+#include <inttypes.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/linuxlist.h>
@@ -68,17 +69,20 @@ static int gprs_llc_generate_xid(uint8_t *bytes, int bytes_len,
struct gprs_llc_xid_field xid_version;
struct gprs_llc_xid_field xid_n201u;
struct gprs_llc_xid_field xid_n201i;
+ uint16_t n201_u, n201_i;
xid_version.type = GPRS_LLC_XID_T_VERSION;
xid_version.data = (uint8_t *) "\x00";
xid_version.data_len = 1;
+ n201_u = htons(lle->params.n201_u);
xid_n201u.type = GPRS_LLC_XID_T_N201_U;
- xid_n201u.data = (uint8_t *) "\x05\xf0";
+ xid_n201u.data = (uint8_t *) &n201_u;
xid_n201u.data_len = 2;
+ n201_i = htons(lle->params.n201_i);
xid_n201i.type = GPRS_LLC_XID_T_N201_I;
- xid_n201i.data = (uint8_t *) "\x05\xf0";
+ xid_n201i.data = (uint8_t *) &n201_i;
xid_n201i.data_len = 2;
/* Add locally managed XID Fields */
@@ -372,20 +376,24 @@ static int _bssgp_tx_dl_ud(struct msgb *msg, struct sgsn_mm_ctx *mmctx)
* not yet have a MMC context (e.g. XID negotiation of primarly
* LLC connection from GMM sapi). */
if (mmctx) {
+ /* In rare cases the LLME is NULL in those cases don't
+ * use the mm radio capabilities */
dup.imsi = mmctx->imsi;
- dup.drx_parms = mmctx->drx_parms;
- dup.ms_ra_cap.len = mmctx->ms_radio_access_capa.len;
- dup.ms_ra_cap.v = mmctx->ms_radio_access_capa.buf;
-
- /* make sure we only send it to the right llme */
- if (!(msgb_tlli(msg) == mmctx->gb.llme->tlli
- || msgb_tlli(msg) == mmctx->gb.llme->old_tlli)) {
- LOGP(DLLC, LOGL_ERROR,
- "_bssgp_tx_dl_ud(): Attempt to send Downlink Unitdata to wrong LLME:"
- " msgb_tlli=0x%x mmctx->gb.llme->tlli=0x%x ->old_tlli=0x%x\n",
- msgb_tlli(msg), mmctx->gb.llme->tlli, mmctx->gb.llme->old_tlli);
- msgb_free(msg);
- return -EINVAL;
+ if (mmctx->gb.llme) {
+ dup.drx_parms = mmctx->drx_parms;
+ dup.ms_ra_cap.len = mmctx->ms_radio_access_capa.len;
+ dup.ms_ra_cap.v = mmctx->ms_radio_access_capa.buf;
+
+ /* make sure we only send it to the right llme */
+ if (!(msgb_tlli(msg) == mmctx->gb.llme->tlli
+ || msgb_tlli(msg) == mmctx->gb.llme->old_tlli)) {
+ LOGP(DLLC, LOGL_ERROR,
+ "_bssgp_tx_dl_ud(): Attempt to send Downlink Unitdata to wrong LLME:"
+ " msgb_tlli=0x%x mmctx->gb.llme->tlli=0x%x ->old_tlli=0x%x\n",
+ msgb_tlli(msg), mmctx->gb.llme->tlli, mmctx->gb.llme->old_tlli);
+ msgb_free(msg);
+ return -EINVAL;
+ }
}
}
memcpy(&dup.qos_profile, qos_profile_default,
@@ -528,7 +536,7 @@ static struct gprs_llc_lle *lle_for_rx_by_tlli_sapi(const uint32_t tlli,
struct gprs_llc_llme *llme;
/* FIXME: don't use the TLLI but the 0xFFFF unassigned? */
llme = llme_alloc(tlli);
- LOGP(DLLC, LOGL_NOTICE, "LLC RX: unknown TLLI 0x%08x, "
+ LOGGBP(llme, DLLC, LOGL_NOTICE, "LLC RX: unknown TLLI 0x%08x, "
"creating LLME on the fly\n", tlli);
lle = &llme->lle[sapi];
return lle;
@@ -1047,6 +1055,10 @@ int gprs_llgmm_assign(struct gprs_llc_llme *llme,
uint32_t old_tlli, uint32_t new_tlli)
{
unsigned int i;
+ bool free = false;
+
+ LOGGBP(llme, DLLC, LOGL_NOTICE, "LLGM Assign pre (%08x => %08x)\n",
+ old_tlli, new_tlli);
if (old_tlli == TLLI_UNASSIGNED && new_tlli != TLLI_UNASSIGNED) {
/* TLLI Assignment 8.3.1 */
@@ -1087,10 +1099,16 @@ int gprs_llgmm_assign(struct gprs_llc_llme *llme,
struct gprs_llc_lle *l = &llme->lle[i];
l->state = GPRS_LLES_UNASSIGNED;
}
- llme_free(llme);
+ free = true;
} else
return -EINVAL;
+ LOGGBP(llme, DLLC, LOGL_NOTICE, "LLGM Assign post (%08x => %08x)\n",
+ old_tlli, new_tlli);
+
+ if (free)
+ llme_free(llme);
+
return 0;
}
@@ -1104,16 +1122,18 @@ int gprs_llgmm_unassign(struct gprs_llc_llme *llme)
int gprs_llgmm_reset(struct gprs_llc_llme *llme)
{
struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID");
- struct gprs_llc_lle *lle = &llme->lle[1];
+ struct gprs_llc_lle *lle = &llme->lle[GPRS_SAPI_GMM];
uint8_t xid_bytes[1024];
int xid_bytes_len, rc;
uint8_t *xid;
- LOGP(DLLC, LOGL_NOTICE, "LLGM Reset\n");
+ LOGGBP(llme, DLLC, LOGL_NOTICE, "LLGM Reset\n");
rc = osmo_get_rand_id((uint8_t *) &llme->iov_ui, 4);
if (rc < 0) {
- LOGP(DLLC, LOGL_ERROR, "osmo_get_rand_id() failed for LLC XID reset: %s\n", strerror(-rc));
+ LOGGBP(llme, DLLC, LOGL_ERROR,
+ "osmo_get_rand_id() failed for LLC XID reset: %s\n",
+ strerror(-rc));
return rc;
}
@@ -1144,11 +1164,13 @@ int gprs_llgmm_reset_oldmsg(struct msgb* oldmsg, uint8_t sapi,
int xid_bytes_len, rc;
uint8_t *xid;
- LOGP(DLLC, LOGL_NOTICE, "LLGM Reset\n");
+ LOGGBP(llme, DLLC, LOGL_NOTICE, "LLGM Reset (SAPI=%" PRIu8 ")\n", sapi);
rc = osmo_get_rand_id((uint8_t *) &llme->iov_ui, 4);
if (rc < 0) {
- LOGP(DLLC, LOGL_ERROR, "osmo_get_rand_id() failed for LLC XID reset: %s\n", strerror(-rc));
+ LOGGBP(llme, DLLC, LOGL_ERROR,
+ "osmo_get_rand_id() failed for LLC XID reset: %s\n",
+ strerror(-rc));
return rc;
}
diff --git a/src/sgsn/gprs_mm_state_gb_fsm.c b/src/sgsn/gprs_mm_state_gb_fsm.c
index f6d680c5..811f0c2f 100644
--- a/src/sgsn/gprs_mm_state_gb_fsm.c
+++ b/src/sgsn/gprs_mm_state_gb_fsm.c
@@ -125,5 +125,5 @@ struct osmo_fsm mm_state_gb_fsm = {
static __attribute__((constructor)) void mm_state_gb_fsm_init(void)
{
- osmo_fsm_register(&mm_state_gb_fsm);
+ OSMO_ASSERT(osmo_fsm_register(&mm_state_gb_fsm) == 0);
}
diff --git a/src/sgsn/gprs_mm_state_iu_fsm.c b/src/sgsn/gprs_mm_state_iu_fsm.c
index ea319417..e571026c 100644
--- a/src/sgsn/gprs_mm_state_iu_fsm.c
+++ b/src/sgsn/gprs_mm_state_iu_fsm.c
@@ -146,5 +146,5 @@ struct osmo_fsm mm_state_iu_fsm = {
static __attribute__((constructor)) void mm_state_iu_fsm_init(void)
{
- osmo_fsm_register(&mm_state_iu_fsm);
+ OSMO_ASSERT(osmo_fsm_register(&mm_state_iu_fsm) == 0);
}
diff --git a/src/sgsn/gprs_sgsn.c b/src/sgsn/gprs_sgsn.c
index cb2c0fc2..0b7c21e9 100644
--- a/src/sgsn/gprs_sgsn.c
+++ b/src/sgsn/gprs_sgsn.c
@@ -511,6 +511,11 @@ void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp)
sig_data.pdp = pdp;
osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_FREE, &sig_data);
+ if (osmo_timer_pending(&pdp->timer)) {
+ LOGPDPCTXP(LOGL_ERROR, pdp, "Freeing PDP ctx with timer %u pending\n", pdp->T);
+ osmo_timer_del(&pdp->timer);
+ }
+
rate_ctr_group_free(pdp->ctrg);
if (pdp->mm)
llist_del(&pdp->list);
diff --git a/src/sgsn/gprs_sm.c b/src/sgsn/gprs_sm.c
index f8019ab6..3bdad3bf 100644
--- a/src/sgsn/gprs_sm.c
+++ b/src/sgsn/gprs_sm.c
@@ -639,7 +639,11 @@ static int gsm48_rx_gsm_deact_pdp_req(struct sgsn_mm_ctx *mm, struct msgb *msg)
return _gsm48_tx_gsm_deact_pdp_acc(mm, transaction_id);
}
- return sgsn_delete_pdp_ctx(pdp);
+ if (pdp->ggsn)
+ return sgsn_delete_pdp_ctx(pdp);
+ /* GTP side already detached, freeing */
+ sgsn_pdp_ctx_free(pdp);
+ return 0;
}
/* 3GPP TS 24.008 § 9.5.9: Deactivate PDP Context Accept */
diff --git a/src/sgsn/gprs_sndcp.c b/src/sgsn/gprs_sndcp.c
index 01be57ef..19d87121 100644
--- a/src/sgsn/gprs_sndcp.c
+++ b/src/sgsn/gprs_sndcp.c
@@ -366,8 +366,12 @@ static int defrag_segments(struct gprs_sndcp_entity *sne)
rc = sgsn_rx_sndcp_ud_ind(&sne->ra_id, sne->lle->llme->tlli,
sne->nsapi, msg, npdu_len, expnd);
- if (any_pcomp_or_dcomp_active(sgsn))
- talloc_free(expnd);
+ /* we must free the memory we allocated above; ownership is not transferred
+ * downwards in the call above */
+ msgb_free(msg);
+
+ /* Note: We do not have to free expnd explicitly, because it is created
+ * within the talloc context of msg, which we just freed. */
return rc;
}
diff --git a/src/sgsn/gprs_subscriber.c b/src/sgsn/gprs_subscriber.c
index 484c7ef4..c23b332f 100644
--- a/src/sgsn/gprs_subscriber.c
+++ b/src/sgsn/gprs_subscriber.c
@@ -812,7 +812,7 @@ static int gprs_subscr_query_auth_info(struct gprs_subscr *subscr,
return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
}
-int gprs_subscr_location_update(struct gprs_subscr *subscr)
+int gprs_subscr_location_update(struct gprs_subscr *subscr, enum sgsn_ran_type ran_type)
{
struct osmo_gsup_message gsup_msg = {0};
@@ -820,6 +820,18 @@ int gprs_subscr_location_update(struct gprs_subscr *subscr)
"subscriber data is not available\n");
gsup_msg.message_type = OSMO_GSUP_MSGT_UPDATE_LOCATION_REQUEST;
+
+ switch (ran_type) {
+ case MM_CTX_T_GERAN_Gb:
+ gsup_msg.current_rat_type = OSMO_RAT_GERAN_A;
+ break;
+ case MM_CTX_T_UTRAN_Iu:
+ gsup_msg.current_rat_type = OSMO_RAT_UTRAN_IU;
+ break;
+ default:
+ break;
+ }
+
return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
}
@@ -884,7 +896,7 @@ int gprs_subscr_request_update_location(struct sgsn_mm_ctx *mmctx)
subscr->flags |= GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING;
- rc = gprs_subscr_location_update(subscr);
+ rc = gprs_subscr_location_update(subscr, mmctx->ran_type);
gprs_subscr_put(subscr);
return rc;
}
diff --git a/src/sgsn/sgsn_libgtp.c b/src/sgsn/sgsn_libgtp.c
index c45431ae..367570d3 100644
--- a/src/sgsn/sgsn_libgtp.c
+++ b/src/sgsn/sgsn_libgtp.c
@@ -167,6 +167,7 @@ struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
pdp->hisaddr0 = ggsn->remote_addr;
pdp->hisaddr1 = ggsn->remote_addr;
//pdp->cch_pdp = 512; /* Charging Flat Rate */
+ pdp->radio_pri = 0x4;
/* MS provided APN, subscription was verified by the caller */
pdp->selmode = 0xFC | 0x00;
@@ -311,11 +312,16 @@ struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
return pctx;
}
-/* SGSN wants to delete a PDP context */
+/* SGSN wants to delete a PDP context, send first DeleteCtxReq on the GTP side,
+ then upon DeleteCtx ACK it will send DeactPdpAcc to the MS if still
+ connected. */
int sgsn_delete_pdp_ctx(struct sgsn_pdp_ctx *pctx)
{
LOGPDPCTXP(LOGL_INFO, pctx, "Delete PDP Context\n");
+ OSMO_ASSERT(pctx->ggsn);
+ OSMO_ASSERT(pctx->lib);
+
/* FIXME: decide if we need teardown or not ! */
return gtp_delete_context_req2(pctx->ggsn->gsn, pctx->lib, pctx, 1);
}
@@ -660,14 +666,18 @@ static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)
switch (mm->gmm_fsm->state) {
case ST_GMM_REGISTERED_SUSPENDED:
- /* initiate PS PAGING procedure */
- gprs_gb_page_ps_ra(mm);
- /* FIXME: queue the packet we received from GTP */
- break;
+ LOGMMCTXP(LOGL_INFO, mm, "Dropping DL packet for MS in GMM state %s\n",
+ osmo_fsm_inst_state_name(mm->gmm_fsm));
+ msgb_free(msg);
+ return -1;
case ST_GMM_REGISTERED_NORMAL:
OSMO_ASSERT(mm->gb.mm_state_fsm->state != ST_MM_IDLE);
- if (mm->gb.mm_state_fsm->state == ST_MM_STANDBY)
+ if (mm->gb.mm_state_fsm->state == ST_MM_STANDBY) {
+ LOGMMCTXP(LOGL_INFO, mm, "Paging MS in GMM state %s, MM state %s\n",
+ osmo_fsm_inst_state_name(mm->gmm_fsm),
+ osmo_fsm_inst_state_name(mm->gb.mm_state_fsm));
gprs_gb_page_ps_ra(mm);
+ }
/* FIXME: queue the packet we received from GTP */
break;
@@ -733,7 +743,7 @@ static int sgsn_gtp_fd_cb(struct osmo_fd *fd, unsigned int what)
struct sgsn_instance *sgi = fd->data;
int rc;
- if (!(what & BSC_FD_READ))
+ if (!(what & OSMO_FD_READ))
return 0;
switch (fd->priv_nr) {
@@ -753,28 +763,6 @@ static int sgsn_gtp_fd_cb(struct osmo_fd *fd, unsigned int what)
return rc;
}
-static void sgsn_gtp_tmr_start(struct sgsn_instance *sgi)
-{
- struct timeval next;
-
- /* Retrieve next retransmission as struct timeval */
- gtp_retranstimeout(sgi->gsn, &next);
-
- /* re-schedule the timer */
- osmo_timer_schedule(&sgi->gtp_timer, next.tv_sec, next.tv_usec/1000);
-}
-
-/* timer callback for libgtp retransmissions and ping */
-static void sgsn_gtp_tmr_cb(void *data)
-{
- struct sgsn_instance *sgi = data;
-
- /* Do all the retransmissions as needed */
- gtp_retrans(sgi->gsn);
-
- sgsn_gtp_tmr_start(sgi);
-}
-
int sgsn_gtp_init(struct sgsn_instance *sgi)
{
int rc;
@@ -793,31 +781,19 @@ int sgsn_gtp_init(struct sgsn_instance *sgi)
if (gsn->mode != GTP_MODE_SGSN)
return -EINVAL;
- sgi->gtp_fd0.fd = gsn->fd0;
- sgi->gtp_fd0.priv_nr = 0;
- sgi->gtp_fd0.data = sgi;
- sgi->gtp_fd0.when = BSC_FD_READ;
- sgi->gtp_fd0.cb = sgsn_gtp_fd_cb;
+ osmo_fd_setup(&sgi->gtp_fd0, gsn->fd0, OSMO_FD_READ, sgsn_gtp_fd_cb, sgi, 0);
rc = osmo_fd_register(&sgi->gtp_fd0);
if (rc < 0)
return rc;
- sgi->gtp_fd1c.fd = gsn->fd1c;
- sgi->gtp_fd1c.priv_nr = 1;
- sgi->gtp_fd1c.data = sgi;
- sgi->gtp_fd1c.when = BSC_FD_READ;
- sgi->gtp_fd1c.cb = sgsn_gtp_fd_cb;
+ osmo_fd_setup(&sgi->gtp_fd1c, gsn->fd1c, OSMO_FD_READ, sgsn_gtp_fd_cb, sgi, 1);
rc = osmo_fd_register(&sgi->gtp_fd1c);
if (rc < 0) {
osmo_fd_unregister(&sgi->gtp_fd0);
return rc;
}
- sgi->gtp_fd1u.fd = gsn->fd1u;
- sgi->gtp_fd1u.priv_nr = 2;
- sgi->gtp_fd1u.data = sgi;
- sgi->gtp_fd1u.when = BSC_FD_READ;
- sgi->gtp_fd1u.cb = sgsn_gtp_fd_cb;
+ osmo_fd_setup(&sgi->gtp_fd1u, gsn->fd1u, OSMO_FD_READ, sgsn_gtp_fd_cb, sgi, 2);
rc = osmo_fd_register(&sgi->gtp_fd1u);
if (rc < 0) {
osmo_fd_unregister(&sgi->gtp_fd0);
@@ -825,10 +801,6 @@ int sgsn_gtp_init(struct sgsn_instance *sgi)
return rc;
}
- /* Start GTP re-transmission timer */
- osmo_timer_setup(&sgi->gtp_timer, sgsn_gtp_tmr_cb, sgi);
- sgsn_gtp_tmr_start(sgi);
-
/* Register callbackcs with libgtp */
gtp_set_cb_delete_context(gsn, cb_delete_context);
gtp_set_cb_conf(gsn, cb_conf);
diff --git a/src/sgsn/sgsn_main.c b/src/sgsn/sgsn_main.c
index eef5f8f2..3044f95e 100644
--- a/src/sgsn/sgsn_main.c
+++ b/src/sgsn/sgsn_main.c
@@ -42,12 +42,14 @@
#include <osmocom/gprs/gprs_ns.h>
#include <osmocom/gprs/gprs_bssgp.h>
+#include <osmocom/gprs/gprs_bssgp_bss.h>
#include <osmocom/vty/telnet_interface.h>
#include <osmocom/vty/logging.h>
#include <osmocom/vty/stats.h>
#include <osmocom/vty/ports.h>
#include <osmocom/vty/misc.h>
+#include <osmocom/vty/cpu_sched_vty.h>
#include <osmocom/ctrl/control_vty.h>
@@ -199,6 +201,23 @@ int sgsn_vty_go_parent(struct vty *vty)
#endif
}
+static void bvc_reset_persistent_nsvcs(void)
+{
+ /* Send BVC-RESET on all persistent NSVCs */
+ struct gprs_nsvc *nsvc;
+
+ llist_for_each_entry(nsvc, &sgsn_nsi->gprs_nsvcs, list) {
+ struct bssgp_bvc_ctx bctx = {
+ .nsei = nsvc->nsei,
+ };
+ if (!nsvc->persistent)
+ continue;
+ /* if it is not marked ALIVE, we cannot send any data over it. */
+ nsvc->state |= NSE_S_ALIVE;
+ bssgp_tx_bvc_reset2(&bctx, BVCI_SIGNALLING, BSSGP_CAUSE_EQUIP_FAIL, false);
+ }
+}
+
static struct vty_app_info vty_info = {
.name = "OsmoSGSN",
.version = PACKAGE_VERSION,
@@ -271,6 +290,11 @@ static void handle_options(int argc, char **argv)
break;
}
}
+
+ if (argc > optind) {
+ fprintf(stderr, "Unsupported positional arguments on command line\n");
+ exit(2);
+ }
}
/* default categories */
@@ -391,9 +415,10 @@ int main(int argc, char **argv)
osmo_stats_vty_add_cmds();
sgsn_vty_init(&sgsn->cfg);
ctrl_vty_init(tall_sgsn_ctx);
+ osmo_cpu_sched_vty_init(tall_sgsn_ctx);
#if BUILD_IU
- osmo_ss7_init();
+ OSMO_ASSERT(osmo_ss7_init() == 0);
osmo_ss7_vty_init_asp(tall_sgsn_ctx);
osmo_sccp_vty_init();
#endif
@@ -507,8 +532,8 @@ int main(int argc, char **argv)
"OsmoSGSN",
(23 << 3) + 4,
OSMO_SS7_ASP_PROT_M3UA,
- 0, NULL,
- 0, "127.0.0.1");
+ 0, "localhost",
+ 0, "localhost");
if (!sccp) {
printf("Setting up SCCP client failed.\n");
return 8;
@@ -517,6 +542,8 @@ int main(int argc, char **argv)
ranap_iu_init(tall_sgsn_ctx, DRANAP, "OsmoSGSN-IuPS", sccp, gsm0408_gprs_rcvmsg_iu, sgsn_ranap_iu_event);
#endif
+ bvc_reset_persistent_nsvcs();
+
if (daemonize) {
rc = osmo_daemonize();
if (rc < 0) {
diff --git a/src/sgsn/sgsn_vty.c b/src/sgsn/sgsn_vty.c
index 14248d1d..33a652c9 100644
--- a/src/sgsn/sgsn_vty.c
+++ b/src/sgsn/sgsn_vty.c
@@ -186,6 +186,8 @@ static int config_write_sgsn(struct vty *vty)
vty_out(vty, "sgsn%s", VTY_NEWLINE);
+ vty_out(vty, " gtp state-dir %s%s",
+ g_cfg->gtp_statedir, VTY_NEWLINE);
vty_out(vty, " gtp local-ip %s%s",
inet_ntoa(g_cfg->gtp_listenaddr.sin_addr), VTY_NEWLINE);
@@ -315,6 +317,17 @@ DEFUN(cfg_sgsn, cfg_sgsn_cmd,
return CMD_SUCCESS;
}
+DEFUN(cfg_sgsn_state_dir, cfg_sgsn_state_dir_cmd,
+ "gtp state-dir PATH",
+ "GTP Parameters\n"
+ "Set the directory for the GTP State file\n"
+ "Local Directory\n")
+{
+ osmo_talloc_replace_string(sgsn, &sgsn->cfg.gtp_statedir, argv[0]);
+
+ return CMD_SUCCESS;
+}
+
DEFUN(cfg_sgsn_bind_addr, cfg_sgsn_bind_addr_cmd,
"gtp local-ip A.B.C.D",
"GTP Parameters\n"
@@ -1432,6 +1445,7 @@ int sgsn_vty_init(struct sgsn_config *cfg)
install_element(CONFIG_NODE, &cfg_sgsn_cmd);
install_node(&sgsn_node, config_write_sgsn);
+ install_element(SGSN_NODE, &cfg_sgsn_state_dir_cmd);
install_element(SGSN_NODE, &cfg_sgsn_bind_addr_cmd);
install_element(SGSN_NODE, &cfg_ggsn_remote_ip_cmd);
//install_element(SGSN_NODE, &cfg_ggsn_remote_port_cmd);